This article concerns real-time and knowledgeable Kotlin Scenario-Based Questions 2025. It is drafted with the interview theme in mind to provide maximum support for your interview. Go through these Kotlin Scenario-Based Questions 2025 to the end, as all scenarios have their importance and learning potential.
To check out other Scenarios Based Questions:- Click Here.
Disclaimer:
These solutions are based on my experience and best effort. Actual results may vary depending on your setup. Codes may need some tweaking.
1) Your team is moving from LiveData to Flow in a Compose app. What will you choose for UI state and why?
- I’d use StateFlow for screen state because it always holds the latest value and works cleanly with Compose state collectors.
- It reduces missed emissions during recomposition and rotation since it replays the current state.
- Events like one-time toasts are better as SharedFlow to avoid accidental replays as state.
- Business benefit: cleaner mental model than LiveData when everything is Kotlin-first.
- Common pitfall: exposing cold Flow directly to UI and losing values on lifecycle changes.
- Trade-off: StateFlow needs an initial value; model your “Empty/Loading” explicitly.
- Decision tip: if it’s “what the screen looks like now,” it’s StateFlow; if “notify and forget,” it’s SharedFlow.
- Process improvement: document a simple rule-of-thumb so all modules stay consistent.
2) Review finds runBlocking inside production code. How do you handle it?
runBlockingblocks threads; on Android that risks ANRs and broken responsiveness.- I replace it with suspending APIs and proper scopes so calls don’t block the main thread.
- Business benefit: smoother UI, fewer frame drops, better user satisfaction.
- Risk management: add a lint or static check to flag
runBlockingoutside tests. - Pitfall: swapping it to
GlobalScope.launchis worse; that hides lifecycle bugs. - Decision: if it’s test setup or migration glue, keep it in tests only.
- Curiosity point: measure start-to-first-draw before and after to prove the win.
- Lesson learned: blocking hacks today become firefights during release week.
3) A child coroutine crash takes down the whole screen. What would you change?
- Switch failure semantics with SupervisorJob/supervisorScope so one child failing doesn’t cancel siblings.
- Keep structured concurrency: parent still owns lifetime, but isolates failures.
- Business benefit: one flaky network call won’t blank the entire feature.
- Trade-off: you must still surface errors; don’t silently swallow them.
- Pitfall: using
try/catcheverywhere without understanding cancellation leads to leaks. - Decision: critical fan-out work → supervisor; all-or-nothing work → regular scope.
- Process improvement: add a tiny “failure semantics” note to design docs.
- Curiosity: add crash telemetry tagging which child failed to guide retries.
4) Your flow pipeline lags under load. How do you address backpressure?
- First, identify where work happens; wrong dispatcher or heavy operators on main cause lag.
- Consider buffer/conflate to reduce slow collectors blocking upstream.
- Business benefit: more stable UX during bursts, fewer janky scrolls.
- Trade-off: conflate drops intermediate values; only use when you can skip them.
- Pitfall: sprinkling
flowOnrandomly; it only affects upstream of its position. - Decision: keep CPU-heavy map/filter off main, prove with simple frame metrics.
- Process improvement: add a shared “flow operator cookbook” for the team.
- Lesson: measure before/after with a reproducible burst test.
5) Stakeholders ask why you chose SharedFlow for events. Explain it.
- Events are not state; SharedFlow emits to multiple observers without storing a forever “current.”
- It avoids replaying stale one-time actions after rotation like toasts or navigation.
- Business benefit: fewer weird “duplicate event” bugs in prod.
- Pitfall: using StateFlow for events leads to accidental re-triggers.
- Trade-off: you must configure replay/buffer thoughtfully for edge races.
- Decision: reserve StateFlow for durable UI state; SharedFlow for transient signals.
- Process improvement: enforce a small lint rule or code review checklist.
- Curiosity: log event emissions during rotation tests to verify zero duplicates.
6) Cold vs hot confusion caused missed emissions. How do you stabilize?
- Teach that cold flows start on collect, hot flows are ongoing sources.
- For UI state, publish via StateFlow so collectors never “miss the latest.”
- Business benefit: deterministic screens regardless of timing.
- Pitfall: exposing a cold Flow from repository and expecting it to “hold” state.
- Decision: define “state holders” vs “signal pipes” in your architecture doc.
- Risk: hot sources need lifecycle care; tie them to ViewModel not Activity.
- Process improvement: add simple diagrams in your ADR showing data lifetimes.
- Lesson: a shared vocabulary prevents half the bugs.
7) Your repository API design: suspend vs Flow—what’s your rule?
- Use suspend for one-shot work like a single network fetch.
- Use Flow for streams or anything that can change over time.
- Business benefit: simpler testing and easier composition.
- Pitfall: wrapping single shots in Flow adds unneeded complexity.
- Decision: version the API; don’t break callers if you later promote to Flow.
- Trade-off: Flow brings cancellation and backpressure concerns.
- Process improvement: include a small decision table in the repo README.
- Curiosity: track call patterns to retire misfit APIs.
8) Production shows “occasionally stuck loading.” Where would you look first?
- Check for lost cancellations that keep a spinner alive after scope ended.
- Audit dispatcher usage; heavy work on main will starve UI updates.
- Business benefit: faster diagnosis means fewer hotfixes.
- Pitfall: swallowing CancellationException with
runCatchingor broad catches. - Decision: add structured timeouts for network and database layers.
- Risk: silent retries can mask true outages; log with correlation IDs.
- Process improvement: create a red-flag checklist for “stuck UI” triage.
- Lesson: cancellation hygiene is not optional.
9) Team used GlobalScope for “quick fixes.” How do you unwind that?
- Replace with lifecycle-tied scopes: viewModelScope, lifecycleScope, or DI-provided scopes.
- Business benefit: predictable lifetimes and fewer memory leaks.
- Pitfall: swapping to application scope and leaking work forever.
- Decision: define one source of truth for background app-wide scope if needed.
- Risk: cancelation cascade differences; document parent ownership.
- Process improvement: static analysis to flag
GlobalScope. - Curiosity: add a “scope map” diagram per feature for onboarding.
- Lesson: quick fixes become long-term page-outs.
10) You need retries without hammering servers. What pattern do you prefer?
- Use bounded exponential backoff with jitter to spread load.
- Business benefit: protects APIs and battery while still being resilient.
- Pitfall: infinite retries hide outages and spike costs.
- Decision: choose retry only for transient errors; fail fast on 4xx.
- Trade-off: user feedback vs silent background retry—be explicit.
- Process improvement: centralize a retry policy util so all teams align.
- Curiosity: log per-endpoint retry stats to catch regressions.
- Lesson: resilience is policy, not ad hoc.
11) A long-running coroutine survives after Activity is gone. Your fix?
- Move work into ViewModel or a DI-managed scope that outlives UI safely.
- Business benefit: no leaks, no wasted background work.
- Pitfall: tying repositories to Activity scope by accident.
- Decision: for truly app-wide tasks, use a single well-named application scope.
- Risk: losing results on rotation—store to StateFlow, not a callback.
- Process improvement: add lifecycle tests that rotate and verify cancellations.
- Curiosity: memory tools can confirm no Activity references remain.
- Lesson: lifetimes first, code later.
12) Your flow tests are flaky with delays. How do you stabilize them?
- Switch to virtual time and Flow test helpers like Turbine for deterministic checks.
- Business benefit: faster, repeatable CI with fewer false reds.
- Pitfall: asserting intermediate states of StateFlow instead of final
value. - Decision: prefer asserting final state for UI models; stream tests for pipelines.
- Process improvement: a tiny internal testing cookbook helps new devs.
- Curiosity: remove
delaycalls and watch flakiness disappear. - Lesson: stable tests come from controlling time.
13) Greenfield project asks: Hilt or Koin? What’s your pick and why?
- For large Android apps, I choose Hilt due to compile-time safety and first-party integration.
- Business benefit: faster startup and clearer scoping in complex graphs.
- Pitfall: mis-scoping objects leads to memory bloat regardless of framework.
- Decision: small protos or tools may prefer Koin for quick setup.
- Trade-off: Hilt has annotation overhead; Koin has runtime resolution cost.
- Process improvement: document module boundaries before wiring DI.
- Curiosity: benchmark injection time and cold start to validate the choice.
- Lesson: pick once, stick to conventions.
14) In a brownfield RxJava app, how do you phase in coroutines safely?
- Start at edges: wrap network/data calls in
suspendand expose Flow alongside Observable. - Business benefit: gradual migration with no Big Bang risk.
- Pitfall: double subscriptions and duplicate work if both layers run.
- Decision: create adapters at boundaries, not deep inside features.
- Trade-off: some duplication while both systems coexist.
- Process improvement: an ADR per module clarifies the cut-over plan.
- Curiosity: track crash rate during the hybrid period.
- Lesson: migration is a project, not a PR.
15) Release build crashes but debug is fine. Where do you look?
- Suspect R8/ProGuard removing reflective or generated classes.
- Business benefit: fixing rules reduces crash loops post-deploy.
- Pitfall: blanket “keep everything” hides the real issue and increases size.
- Decision: add targeted keep rules for serializers, mappers, or retrofit interfaces.
- Risk: libraries differ in codegen vs reflection; know what you use.
- Process improvement: pre-release smoke tests with minify enabled.
- Curiosity: compare mapping files before/after to pinpoint the culprit.
- Lesson: always test like release.
16) You’re modeling UI state. Enums or sealed classes?
- Sealed classes let you attach data per state and enforce exhaustiveness.
- Business benefit: safer refactors; compiler tells you what you missed.
- Pitfall: using enums then adding ad hoc fields elsewhere.
- Decision: enums for simple flags; sealed hierarchy for real UI states.
- Trade-off: sealed classes need more boilerplate but pay off in clarity.
- Process improvement: share a base
UiStatepattern across modules. - Curiosity: run static checks to ensure exhaustive
whenis used. - Lesson: model states, not flags.
17) A data class equality bug broke your caching. What likely happened?
- You used mutable properties inside a data class, so
copyand equality drifted. - Business benefit: making models immutable stabilizes cache keys and diffing.
- Pitfall: lists inside data classes mutated after hashing.
- Decision: wrap collections or expose read-only views only.
- Trade-off: a bit more memory for immutability, but far fewer heisenbugs.
- Process improvement: code review checklist for “no mutable in equals.”
- Curiosity: add tests asserting hash stability after operations.
- Lesson: immutability is your friend.
18) Java interop keeps throwing NPEs. How do you harden it?
- Respect Java nullability; add annotations or wrappers to express intent.
- Business benefit: fewer crash loops from platform APIs that can return null.
- Pitfall: using
!!to silence; it just delays the problem to runtime. - Decision: map Java types to safe Kotlin forms at the boundary.
- Trade-off: some extra adapters, but clearer contracts.
- Process improvement: enable nullability warnings in build tools.
- Curiosity: track NPE hot spots and fix at the edges.
- Lesson: be explicit with nulls.
19) Team overuses typealias for “strong types.” Any concerns?
typealiasdoesn’t create a new type; it’s only a rename, so bugs slip through.- Business benefit: prefer value classes for true type-safety at near-zero cost.
- Pitfall: passing Email where UserId was expected because aliases match.
- Decision: use value classes for domain IDs and money amounts.
- Trade-off: tiny proguard/config tweaks, but worth the safety.
- Process improvement: a lint to restrict risky aliases.
- Curiosity: measure how many bugs were mis-typed parameters.
- Lesson: names aren’t types.
20) Concurrency on shared counters is flaky. What do you choose?
- Use Mutex with coroutines rather than Java’s
synchronizedon hot paths. - Business benefit: consistent results without blocking extra threads.
- Pitfall: holding locks across suspension points if not careful.
- Decision: keep critical sections small and clearly documented.
- Trade-off: a bit of overhead vs data corruption risk.
- Process improvement: wrap synchronization in a small, tested helper.
- Curiosity: add contention metrics to spot hotspots.
- Lesson: correctness first.
21) Your flowOn is placed randomly. What could go wrong?
flowOnonly moves upstream work; downstream remains on the collector context.- Business benefit: placing it right prevents main-thread hiccups.
- Pitfall: thinking it moves everything; then UI jank appears.
- Decision: place it immediately after the heavy upstream chain.
- Trade-off: too many context hops add overhead; keep it minimal.
- Process improvement: a shared snippet showing the recommended placement.
- Curiosity: capture dispatch traces with simple logs.
- Lesson: understand operator boundaries.
22) Search suggestions need to avoid flooding. How do you shape the stream?
- Add debounce and latest-wins behavior so only final intent triggers work.
- Business benefit: lower API cost and snappier UX.
- Pitfall: debouncing too long makes the UI feel sluggish.
- Decision: tune the interval based on telemetry, not guesswork.
- Trade-off: edge cases for backspaces; test with fast typers.
- Process improvement: centralize a “search flow” utility used across screens.
- Curiosity: compare API calls per minute before and after.
- Lesson: tame the firehose.
23) Offline-first feature request arrives. How do flows help?
- Model local cache as a Flow and merge with network refresh.
- Business benefit: immediate data with background updates for freshness.
- Pitfall: bouncing UI states when local and remote conflict.
- Decision: define conflict rules (e.g., newest timestamp wins).
- Trade-off: more logic in the repository, simpler UI.
- Process improvement: add metrics for cache hit ratio.
- Curiosity: simulate airplane mode in tests to validate behavior.
- Lesson: users love fast and stable.
24) Compose preview can’t run your Flows. What’s your workaround?
- In previews, provide fake immutable state instead of collecting real flows.
- Business benefit: reliable previews without wiring runtime concerns.
- Pitfall: trying to spin up real scopes in preview slows everything down.
- Decision: DI injects a stub VM or state holder just for tooling.
- Trade-off: a bit of duplication for design speed.
- Process improvement: keep preview states in a shared
previewdatamodule. - Curiosity: designers iterate faster when previews are instant.
- Lesson: separate runtime from design time.
25) A teammate swallowed CancellationException. What’s the risk?
- Cancellation is not a regular error; swallowing it makes jobs hang.
- Business benefit: honoring cancellation frees resources quickly.
- Pitfall: using broad catch blocks or
runCatchingwithout rethrowing. - Decision: always rethrow cancellation or let it bubble.
- Trade-off: slightly more explicit code, far fewer leaks.
- Process improvement: add a code review tick for “cancellation safe.”
- Curiosity: add log hooks to observe cancel paths.
- Lesson: cancellation is a feature.
26) CPU-heavy JSON mapping stalls the UI. What’s your approach?
- Move it to Default/IO with clear boundaries; don’t block main.
- Business benefit: smoother scrolling and faster taps.
- Pitfall: bouncing between contexts too often; batch work instead.
- Decision: profile to see where the real cost is—parsing or allocation.
- Trade-off: a small latency for huge frame stability.
- Process improvement: write a tiny benchmark for critical mappers.
- Curiosity: consider binary formats if JSON dominates.
- Lesson: map smart, not hard.
27) You’re choosing a serialization library for KMM. What matters most?
- Pick kotlinx.serialization for first-class multiplatform support.
- Business benefit: shared models across Android/iOS with less glue.
- Pitfall: reflection-heavy libs can fight R8 and increase size.
- Decision: verify ecosystem (Retrofit/Ktor) integration up front.
- Trade-off: migration cost vs long-term simplicity.
- Process improvement: sample both on a real payload and compare size/time.
- Curiosity: measure crash-free sessions before/after migration.
- Lesson: platform-native wins in KMM.
28) KMM team complains about platform API differences. How do you design?
- Keep shared business logic pure; push platform specifics behind expect/actual.
- Business benefit: minimal
#iftangles and clearer ownership. - Pitfall: leaking Android or iOS concepts into shared code.
- Decision: define strict boundaries and contracts early.
- Trade-off: some duplication per platform, but cleaner core.
- Process improvement: ADRs showing the shared vs platform split.
- Curiosity: track churn in shared vs platform modules to spot leaks.
- Lesson: draw the line once.
29) Channel used as a global event bus caused chaos. What now?
- Replace with scoped SharedFlow or explicit callbacks per feature.
- Business benefit: predictable ownership and lifecycle.
- Pitfall: channels are synchronization primitives, not app-wide buses.
- Decision: localize communication; avoid global mutable pipes.
- Trade-off: a bit more wiring, much less spooky action.
- Process improvement: forbid global channels in code guidelines.
- Curiosity: map event sources to consumers in docs.
- Lesson: design for clarity, not cleverness.
30) Room queries on main thread caused frame drops. How to fix?
- Expose Room as Flow/suspend and ensure work happens off main.
- Business benefit: smooth lists and fewer jank reports.
- Pitfall: heavy mappers in collectors pulling work back to main.
- Decision: move mapping upstream with proper context.
- Trade-off: slight latency vs consistent 60fps.
- Process improvement: add a perf budget for DB operations.
- Curiosity: measure query time distribution in CI.
- Lesson: main thread is sacred.
31) Users report “random timeouts.” What’s your coroutine strategy?
- Set clear timeouts at network boundaries; don’t rely on endless waits.
- Business benefit: better user feedback and retry control.
- Pitfall: forgetting to handle partial results on timeout.
- Decision: combine timeouts with cancellation-aware cleanup.
- Trade-off: shorter timeouts increase perceived errors; tune with data.
- Process improvement: centralize timeout defaults per endpoint class.
- Curiosity: track timeout rate by version to catch regressions.
- Lesson: fail fast, fail clear.
32) Your dispatching strategy is inconsistent across modules. What now?
- Standardize: IO for blocking I/O, Default for CPU, Main for UI only.
- Business benefit: predictable performance and simpler reviews.
- Pitfall: using Main for everything “just to be safe.”
- Decision: add a small dispatcher provider abstraction for tests.
- Trade-off: minor indirection for big clarity.
- Process improvement: document where
flowOnbelongs by pattern. - Curiosity: look at traces to confirm fewer main-thread stalls.
- Lesson: consistency beats heroics.
33) A teammate nested coroutines like callbacks. How do you refactor?
- Flatten with structured concurrency and clear scopes.
- Business benefit: fewer leaks and easier reasoning.
- Pitfall: launching in launches creates orphaned work.
- Decision: prefer
coroutineScopeto await children properly. - Trade-off: small refactor now to prevent nasty bugs later.
- Process improvement: sample before/after to teach the pattern.
- Curiosity: show how error propagation improves after flattening.
- Lesson: coroutines aren’t callbacks with new syntax.
34) Design wants strict ordering guarantees in a stream. Your approach?
- Use operators that preserve order and avoid unordered concurrency.
- Business benefit: predictable UI transitions and analytics.
- Pitfall: using
flatMapMergewhereflatMapConcatwas needed. - Decision: document ordering requirements in the story.
- Trade-off: less parallelism but correct UX.
- Process improvement: add contract tests asserting order.
- Curiosity: measure latency impact to justify the choice.
- Lesson: correctness over raw throughput.
35) You need “restartable” streams on connectivity changes. How?
- Build a cold producer that re-establishes work on each new collect.
- Business benefit: automatic recovery when network returns.
- Pitfall: keeping a hot stream alive across dead lifecycles.
- Decision: tie collection to lifecycle and use retry with backoff.
- Trade-off: brief gaps during handover are acceptable.
- Process improvement: chaos tests toggling airplane mode in CI.
- Curiosity: log reconnection counts per session.
- Lesson: design for flakiness.
36) PM asks whether Kotlin 2.x matters to the business. Your answer?
- New compiler brings performance and tooling wins that speed builds.
- Business benefit: shorter dev cycles and fewer IDE hiccups.
- Pitfall: plugin version mismatches during upgrade windows.
- Decision: upgrade on a branch with full CI matrix first.
- Trade-off: temporary churn vs long-term productivity.
- Process improvement: maintain an “upgrade playbook” for language bumps.
- Curiosity: measure build time before/after to show ROI.
- Lesson: platform health pays dividends.
37) After a Kotlin upgrade, DI kapt tasks explode. How do you respond?
- Align AGP, Kotlin, Hilt/Dagger versions per their compatibility notes.
- Business benefit: reliable builds and happier developers.
- Pitfall: partial upgrades causing kapt regressions.
- Decision: use Gradle version catalogs to lock sets.
- Trade-off: slower adoption vs stability.
- Process improvement: stage upgrades per environment before rolling out.
- Curiosity: cache build scans to pinpoint which tasks regressed.
- Lesson: move in lockstep.
38) Logging in coroutines is noisy and hard to trace. Your fix?
- Include coroutine context info or use MDC-like tags for request IDs.
- Business benefit: simpler incident triage and better root cause.
- Pitfall: excessive logging on main thread hurts perf.
- Decision: sample logs in hot paths and aggregate server-side.
- Trade-off: less detail vs better performance—tune thresholds.
- Process improvement: a tiny logging wrapper standardizes fields.
- Curiosity: correlate logs with user actions to spot patterns.
- Lesson: observability is a feature.
39) Teams debate exceptions vs Result wrappers. How do you decide?
- For domain flows, I prefer explicit Result types to model outcomes.
- Business benefit: call sites handle success/failure predictably.
- Pitfall: mixing both styles in the same layer confuses everyone.
- Decision: choose one per layer and document it.
- Trade-off: Result is verbose; exceptions are terse but hidden.
- Process improvement: add helpers to map exceptions to domain errors.
- Curiosity: error analytics improve when types are explicit.
- Lesson: make failure visible.
40) CI shows flaky tests with coroutines and lifecycle. Next steps?
- Use TestDispatcher and run-test utilities to control execution.
- Business benefit: stable, fast CI runs.
- Pitfall: relying on real time and
delay. - Decision: isolate lifecycle and ViewModel in tests with fakes.
- Trade-off: more setup, far fewer flakes.
- Process improvement: a template test base class for all features.
- Curiosity: track flake rate trend after adoption.
- Lesson: determinism wins.
41) A junior dev exposed internal MutableStateFlow publicly. Risk?
- External code can mutate your state, breaking invariants.
- Business benefit: encapsulation prevents accidental corruption.
- Pitfall: crashes that appear “random” due to external writes.
- Decision: expose StateFlow, keep MutableStateFlow private.
- Trade-off: small extra code, big safety.
- Process improvement: code review checklist item for encapsulation.
- Curiosity: add tests ensuring invariants hold under load.
- Lesson: protect your state.
42) Analytics want to observe UI state transitions. How do you do it cleanly?
- Have a single state reducer path that emits to StateFlow.
- Business benefit: one hook point to log transitions.
- Pitfall: emitting from multiple places causing race conditions.
- Decision: centralize updates; derive everything from the reducer.
- Trade-off: slightly more structure, much better observability.
- Process improvement: add a tiny middleware for analytics.
- Curiosity: build a small timeline visual to spot odd sequences.
- Lesson: one path in, many observers out.
43) Your Flow chain masks errors in catch. What’s the fix?
- Ensure
catchis placed after the operator that can throw and rethrow unknowns. - Business benefit: fewer silent failures in production.
- Pitfall: placing
catchtoo early or swallowing cancellation. - Decision: map known exceptions to domain errors, let others bubble.
- Trade-off: more explicit handling, cleaner telemetry.
- Process improvement: code examples showing correct
catchplacement. - Curiosity: add alerting on “unexpected error type.”
- Lesson: handle what you mean.
44) Debate: expose Flow or suspend to UI for one-off button actions?
- For one-off actions, expose suspend to avoid accidental re-trigger flows.
- Business benefit: simpler to call and reason about.
- Pitfall: wrapping it in a hot flow leads to subtle bugs.
- Decision: use Flow only when multiple values or observation is needed.
- Trade-off: slightly less composability, more clarity.
- Process improvement: include this rule in architecture docs.
- Curiosity: count bugs avoided after adopting the rule.
- Lesson: choose the simplest API.
45) App uses Gson with heavy reflection and is slow. Your move?
- Prefer code-gen-friendly serializers to reduce reflection overhead.
- Business benefit: faster cold start and smaller APK.
- Pitfall: adding broad keep rules that bloat the app.
- Decision: migrate gradually, starting with biggest models.
- Trade-off: migration cost vs ongoing performance wins.
- Process improvement: track method count and size per release.
- Curiosity: benchmark parse time before/after.
- Lesson: reflection has a cost.
46) Compose screen flickers when state changes quickly. Why?
- You’re emitting too many intermediate states or recomposing heavy trees.
- Business benefit: smoothing emissions means calmer UI.
- Pitfall: recomputing expensive lists on each tiny change.
- Decision: batch updates or use
distinctUntilChanged-style logic. - Trade-off: slight latency vs visual stability.
- Process improvement: memoize derived state where appropriate.
- Curiosity: use simple tracing to find hotspots.
- Lesson: less churn, better feel.
47) You must protect API keys in a Kotlin app. What’s realistic?
- Don’t hardcode keys; use backend tokens or remote config with rotation.
- Business benefit: reduced abuse and compromised accounts.
- Pitfall: thinking obfuscation alone is “secure.”
- Decision: scope tokens per user/session with server checks.
- Trade-off: extra infra vs real security.
- Process improvement: add leak scanning to CI.
- Curiosity: monitor key usage anomalies.
- Lesson: defense in depth.
48) Multiple collectors compete for the same expensive stream. Strategy?
- Share the upstream work with shareIn/stateIn in the ViewModel scope.
- Business benefit: one fetch, many consumers.
- Pitfall: wrong sharing started/stopped policy causes leaks.
- Decision: pick WhileSubscribed with an idle timeout for UI.
- Trade-off: small complexity, big resource savings.
- Process improvement: document default share policy per app.
- Curiosity: compare network call counts before/after.
- Lesson: share wisely.
49) Product wants fast feature flags rollout. Kotlin approach?
- Model flags as a state holder with snapshots from remote config.
- Business benefit: safe, incremental rollouts and quick rollbacks.
- Pitfall: reading flags ad hoc without caching leads to jank.
- Decision: expose a Flow for reactive updates where needed.
- Trade-off: slightly more plumbing, much safer releases.
- Process improvement: include a kill-switch for risky features.
- Curiosity: track flag change impact on errors.
- Lesson: ship guarded.
50) Team keeps mixing UI, domain, and data concerns in Flows. Cleanup plan?
- Standardize layers: data → domain → UI, each with clear models.
- Business benefit: simpler tests and safer refactors.
- Pitfall: leaking DTOs to UI, then changing server breaks screens.
- Decision: mapping happens at boundaries; never inside UI.
- Trade-off: more models, but predictable ownership.
- Process improvement: add module boundaries in Gradle to enforce it.
- Curiosity: measure PR review time dropping after structure.
- Lesson: layers pay you back.
51) You spot nested withContext(Dispatchers.IO) calls inside suspend functions. What’s your advice?
- One
withContextat the boundary is enough; nesting just adds noise. - Business benefit: cleaner code and fewer context hops.
- Pitfall: overusing
withContextmakes tracing harder and adds overhead. - Decision: push blocking work once to IO, then keep downstream clean.
- Trade-off: less “safety blanket,” but better readability.
- Process improvement: review guidelines to avoid redundant dispatching.
- Curiosity: profile with systrace to prove cost.
- Lesson: context shifts are not free.
52) QA reports duplicate API calls when rotating screen. What likely went wrong?
- Collector restarted with each Activity/Fragment recreation without sharing state.
- Business benefit: fixing it avoids wasted network and battery drain.
- Pitfall: not using
stateIn/shareInin ViewModel scope to cache. - Decision: hoist flow to ViewModel so it survives rotation.
- Trade-off: slight memory cost vs huge UX improvement.
- Process improvement: add rotation tests in QA automation.
- Curiosity: log call counts across rotations.
- Lesson: lifetimes define efficiency.
53) Your team debates sealed interface vs sealed class. When pick which?
- Sealed interfaces allow multiple inheritance; sealed classes give a single hierarchy.
- Business benefit: interfaces keep it flexible for modeling behaviors.
- Pitfall: sealed classes are stricter but safer for states.
- Decision: choose based on whether multiple types should implement.
- Trade-off: complexity vs clarity—decide per use case.
- Process improvement: ADR showing modeling examples.
- Curiosity: measure compile-time exhaustiveness with each.
- Lesson: pick the right abstraction.
54) Some flows never complete and hold resources. How do you solve?
- Add takeUntil/timeout/cancel logic to ensure completion where appropriate.
- Business benefit: predictable lifecycle and no leaks.
- Pitfall: forgetting cancellation and leaving DB cursors or sockets alive.
- Decision: tie flows to lifecycle scope and close properly.
- Trade-off: early completion vs missing late data—decide by requirement.
- Process improvement: instrument flows to log completion events.
- Curiosity: track open resources in debug tools.
- Lesson: every stream should end or recycle.
55) Devs debate between async/await vs launch for background work. Your rule?
- Use
async/awaitfor parallel computations returning results. - Use
launchfor fire-and-forget tasks tied to lifecycle. - Business benefit: fewer logic errors when intent is clear.
- Pitfall: misusing
launchwhen results are needed leads to races. - Decision: document rule-of-thumb in coding guidelines.
- Trade-off: async adds overhead; launch is lighter.
- Process improvement: code review item to verify correct choice.
- Curiosity: inspect bug backlog to see misuses.
- Lesson: intent dictates tool.
56) CI build times increased after adding more kapt. What’s your approach?
- Investigate codegen-heavy libs and see if KSP alternatives exist.
- Business benefit: faster builds, happier devs.
- Pitfall: ignoring kapt cost until CI is unworkable.
- Decision: migrate incrementally; e.g., Room/Glide support KSP now.
- Trade-off: migration effort vs long-term savings.
- Process improvement: baseline build scan metrics per sprint.
- Curiosity: compare module build times pre/post migration.
- Lesson: watch your annotation budget.
57) You must enforce immutability in collections. How in Kotlin?
- Use read-only
List/Map/Setinterfaces and avoid exposing mutable ones. - Business benefit: predictable state and safer concurrency.
- Pitfall: assuming
listOf()is immutable—it’s just unmodifiable. - Decision: wrap with defensive copies at boundaries.
- Trade-off: extra memory vs safety.
- Process improvement: lint rule to forbid mutable exposures.
- Curiosity: audit crash reports for mutable misuse.
- Lesson: protect contracts.
58) Team wants coroutines in libraries but fears API leaks. How do you design?
- Keep internals coroutine-based but expose clean suspend/Flow APIs.
- Business benefit: flexible internals, stable external contract.
- Pitfall: leaking scope details forces callers into unwanted patterns.
- Decision: encapsulate scope management inside library.
- Trade-off: less caller control, but safer design.
- Process improvement: design ADRs for library APIs.
- Curiosity: test from plain Java callers too.
- Lesson: encapsulate concurrency.
59) You’re tasked with monitoring coroutine leaks in prod. What’s practical?
- Add structured logging for launches and completions.
- Business benefit: detect runaway jobs before they eat memory.
- Pitfall: logging too much adds overhead.
- Decision: sample logs or aggregate in analytics backend.
- Trade-off: detail vs performance.
- Process improvement: build a small internal leak detector utility.
- Curiosity: chart active jobs per screen in prod.
- Lesson: what you don’t measure, you can’t fix.
60) A customer asks why Kotlin is chosen over Java for new features. What’s your business case?
- Kotlin reduces boilerplate, cutting dev time and bugs.
- Business benefit: faster delivery and happier team morale.
- Pitfall: partial adoption without training can slow things.
- Decision: invest in Kotlin-first training and guidelines.
- Trade-off: short learning curve vs long-term velocity.
- Process improvement: track bug density per feature vs old Java code.
- Curiosity: share success metrics with stakeholders.
- Lesson: Kotlin is not just syntax—it’s ROI.