Data and Technical Strategy Alignment Questions
Evaluates a candidate's ability to reason about the technical and architectural trade-offs that shape a data platform: batch versus streaming (and hybrid) pipelines, data warehouse versus data lake versus lakehouse architecture, ETL versus ELT, schema design and partitioning for analytics and ingestion, data contracts between producers and consumers, feature stores, and metrics (semantic) layers. Good answers pick a concrete architecture or approach for a stated scale, latency, and cost profile, name the trade-offs of the alternatives, and justify the choice rather than reciting definitions.
Sample Answer
Sample Answer
// pseudocode - Scala Flink
import org.apache.flink.streaming.api.scala._
import org.apache.flink.api.common.state._
import org.apache.flink.streaming.api.functions.KeyedProcessFunction
import org.apache.flink.util.Collector
case class Event(userId: String, eventId: String, payload: Map[String, Any])
case class EnrichedEvent(...)
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.enableCheckpointing(30_000) // 30s
env.getCheckpointConfig.setMinPauseBetweenCheckpoints(10_000)
env.setStateBackend(myStateBackend) // see explanation
env.setParallelism(8)
val kafkaStream: DataStream[Event] = // read from Kafka with exactly-once source
kafkaStream
.keyBy(_.userId)
.process(new KeyedProcessFunction[String, Event, EnrichedEvent] {
// per-user enrichment cache
lazy val enrichmentState: ValueState[UserProfile] = getRuntimeContext.getState(
new ValueStateDescriptor("profile", classOf[UserProfile])
)
// dedup store with TTL (MapState eventId -> timestamp)
lazy val seenIds: MapState[String, Long] = getRuntimeContext.getMapState(
new MapStateDescriptor("seen", classOf[String], classOf[Long])
)
override def processElement(ev: Event, ctx: Context, out: Collector[EnrichedEvent]): Unit = {
if (!seenIds.contains(ev.eventId)) {
// mark seen with current processing time; TTL configured on state backend or managed manually
seenIds.put(ev.eventId, ctx.timerService().currentProcessingTime())
val profile = enrichmentState.value()
val enriched = enrich(ev, profile)
out.collect(enriched)
} else {
// duplicate -> drop
}
// optionally register timer to cleanup old seenIds
ctx.timerService().registerProcessingTimeTimer(ctx.timerService().currentProcessingTime() + cleanupMs)
}
override def onTimer(ts: Long, ctx: OnTimerContext, out: Collector[EnrichedEvent]): Unit = {
// remove entries older than retention
// iterate seenIds and remove by timestamp
}
})
.addSink(new TwoPhaseCommitSink(...)) // transactional sink (exactly-once)Sample Answer
Sample Answer
Sample Answer
Unlock Full Question Bank
Get access to hundreds of Data and Technical Strategy Alignment interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.