Skip to main content

Kotlin engineer behavioral interview questions

19 questions on behavioral for kotlin engineer candidates. Expect prompts such as “ViewModel doing heavy computation on Main thread” and “Debugging a coroutine deadlock in production”, each with a worked answer outline and the follow-ups interviewers push on.

Questions

Showing 1 to 19 of 19 behavioral questions.

As asked

A junior engineer has a ViewModel that parses a large JSON response and builds a complex UI model directly inside a StateFlow update, all on the main thread. Users report UI jank. You are doing the code review. What do you say and how do you suggest fixing it?

Sample answer outline

The fix is moving the heavy computation to withContext(Dispatchers.Default) inside the ViewModel's coroutine. The review comment should explain why: the main thread has a 16ms frame budget and blocking it causes dropped frames. The candidate should also mention testing the fix with a profiler and suggest adding a custom lint rule or a performance test that measures the computation time.

Expect these follow-ups

  • How do you determine the right dispatcher for a task: Default vs IO?
  • What would you check to confirm the jank is gone after the fix?
situationaldispatchersandroidkotlinperformance

As asked

Tell me about a time you debugged a concurrency issue, such as a deadlock or a race condition, in a Kotlin or JVM codebase. Walk me through how you reproduced it, identified the root cause, and fixed it.

Sample answer outline

A strong answer follows STAR: names a specific production incident, describes the symptoms (e.g., requests hanging, thread dumps showing WAITING states), explains the investigation (Thread.getAllStackTraces, coroutine dump via DebugProbes), identifies the cause (e.g., a suspend function holding a non-reentrant lock or a blocking call inside a coroutine on Dispatchers.Default), and explains the fix and prevention measures added.

Expect these follow-ups

  • How did you prevent similar issues from reoccurring?
  • Have you used DebugProbes or kotlinx-coroutines-debug in a live environment?
behavioraldebuggingconcurrencykotlinproduction

As asked

Describe a time you migrated a Java codebase to Kotlin or introduced Kotlin incrementally into an existing Java project. What was your strategy, what friction did you encounter with the team, and what would you do differently?

Sample answer outline

The answer should detail a concrete strategy: converting files bottom-up from utilities to business logic, adding IDE Kotlin support, agreeing on null-safety conventions at interop boundaries. Team friction usually involves convincing Java engineers of new idioms. The candidate should mention tooling like the J2K converter and its limitations and how they set code style guidelines (ktlint, detekt).

Expect these follow-ups

  • How did you handle disagreements about Kotlin idioms vs Java familiarity?
  • What was the biggest source of bugs during the migration?
behavioralmigrationkotlinjava-interopteam-dynamics

As asked

Tell me about a time you identified and fixed a performance regression in an Android or backend Kotlin application. How did you find the root cause and measure the improvement?

Sample answer outline

The answer should name specific profiling tools: Android Profiler for CPU/memory, Systrace for frame drops, or JVM VisualVM and async-profiler for backend work. The root cause should be concrete, such as excessive object allocation in a hot path, a blocking call on the main thread, or an N+1 database query. Measurement should include before/after metrics (frame time, p99 latency) not just anecdotal improvement.

Expect these follow-ups

  • What did you add to prevent regressions in the future, like performance tests or CI alerts?
  • How did you balance the fix with shipping schedule pressure?
behavioralperformanceandroidkotlinprofiling

As asked

Give me an example of a time you pushed back on a teammate's design decision during code review, specifically around a Kotlin design pattern or architectural choice. How did you handle the disagreement and what was the outcome?

Sample answer outline

The answer should show technical conviction balanced with empathy. A good example is pushing back on using a String for error modeling when a sealed class would make exhaustive handling possible, or objecting to using GlobalScope. The candidate should explain how they explained the tradeoffs with evidence (e.g., showing where the compiler fails to catch a case) rather than asserting authority.

Expect these follow-ups

  • How do you handle it when the PR author disagrees and has seniority?
  • What would make you drop a code review comment rather than pursue it?
behavioralcode-reviewcollaborationkotlindesign

As asked

Describe a situation where a coroutine or scope outlived its intended lifetime and caused a memory leak or incorrect behavior in a production app. How did you detect it and what did you change?

Sample answer outline

A strong answer names a specific scenario: a GlobalScope coroutine holding a Fragment reference, a ViewModel that did not cancel a scope on clearance, or a Flow that was never cancelled. Detection involved LeakCanary alerts or OOM crash reports. The fix used viewModelScope, lifecycle-aware collection with repeatOnLifecycle, or explicit scope cancellation. Prevention included adding a lint rule or code review checklist item.

Expect these follow-ups

  • How did you prioritize fixing this relative to feature work?
  • What monitoring did you add to detect similar issues earlier?
behavioralmemory-leaksproductionkotlinandroid

As asked

Tell me about a time you helped a new team member who was unfamiliar with Kotlin coroutines or Kotlin idioms get up to speed. What resources did you use and how did you measure their progress?

Sample answer outline

The answer should show a structured approach: pairing on real tasks, recommending specific learning resources (Kotlin coroutines guide, Roman Elizarov's talks), reviewing their first PRs with detailed comments focused on idioms and pitfalls, and setting milestones. Measuring progress through PR quality, reducing review cycles, and the engineer tackling more complex coroutine patterns independently.

Expect these follow-ups

  • What is the most common misunderstanding Kotlin newcomers have about coroutines?
  • How do you balance mentoring with your own delivery commitments?
behavioralmentoringkotlincoroutinesonboarding

As asked

Tell me about a time a NullPointerException (or Kotlin equivalent) hit production. How did you find the cause and what did you change to prevent it?

Sample answer outline

A strong answer identifies a Java interop scenario: a platform type assigned to a non-nullable variable, or a @Nullable annotation missing from a Java API. The candidate should walk through the stack trace, the fix (adding null checks at the boundary, using !! only where provably non-null, or annotating the Java API), and the systemic fix (adding detekt null-safety rules or requiring explicit type declarations at interop boundaries).

Expect these follow-ups

  • How do you prevent this from happening in future Java interop code?
  • Have you ever used !! in production code and regretted it?
behavioralnull-safetyjava-interopkotlinproduction

As asked

Describe a bug you fixed where shared state managed in a StateFlow or SharedFlow was causing incorrect or stale UI in an Android app. What was the mistake and how did you fix it?

Sample answer outline

Classic scenarios include: using StateFlow for one-time events causing duplicate navigation on screen rotation (the last value is replayed to new collectors), or not using distinctUntilChanged causing redundant UI redraws. A strong answer describes the specific bug, the investigation (adding logs or using Flipper for ViewModel state), and the fix (Channel for events, distinctUntilChanged for state, or a custom ConsumableEvent wrapper).

Expect these follow-ups

  • How do you test for this kind of stale-state bug?
  • What is your preferred pattern for one-time UI events in an MVI architecture?
behavioralstateflowandroidkotlindebugging

As asked

During a code review you see a coroutine on Dispatchers.Default that makes a blocking JDBC call inside a launch block, without any withContext wrapping. The service is under low load now but will handle 10x traffic next month. What do you do and why?

Sample answer outline

The candidate should flag it immediately: Dispatchers.Default uses a CPU-bound thread pool and blocking it starves other coroutines. The fix is wrapping the JDBC call in withContext(Dispatchers.IO). They should also raise the question of whether a non-blocking database driver (R2DBC, coroutine-aware driver) is appropriate for the service's scale. The candidate should leave a code review comment and perhaps add a lint rule or test to detect this pattern.

Expect these follow-ups

  • Would you block the PR or merge with a comment?
  • How do you detect blocking calls inside coroutines in a large codebase?
situationalcoroutinesdispatcherskotlinperformance

As asked

A senior teammate proposes representing API error states as String error codes rather than a sealed class hierarchy for a Kotlin service you are both building. They argue it is simpler and easier to extend. How do you respond?

Sample answer outline

The candidate should present the tradeoffs honestly: String codes are extensible at runtime (good for client-driven error codes) but lose compile-time exhaustiveness and are prone to typos. Sealed classes give the compiler the ability to enforce handling of all cases. A compromise is a sealed class for known errors with a data class Unknown(val code: String) case. The candidate should propose a small prototype to compare before deciding.

Expect these follow-ups

  • When is a String error code actually the right choice?
  • How would you evolve the sealed class when a new error type is added in a later release?
situationalsealed-classesdesignkotlintradeoffs

As asked

You are onboarding to a new team and discover that a critical production Ktor service uses GlobalScope.launch extensively for background tasks. The service is stable today. What do you do, when, and how do you justify the priority?

Sample answer outline

The candidate should not propose an immediate large refactor without understanding the risk. First, assess the actual impact: are coroutines leaking (OutOfMemoryError, growing thread pools)? Are tasks orphaned on service restart? If the service is stable, propose a gradual migration: add an application-scoped CoroutineScope tied to the Ktor ApplicationLifetime, migrate one service at a time, with tests. Justify priority by estimating the blast radius of a leak under traffic spike.

Expect these follow-ups

  • What metrics would you watch to detect that GlobalScope is causing issues?
  • If the team pushes back due to delivery pressure, what is your minimum safe change?
situationalglobalscopekotlinproductionrisk-management

As asked

You need to integrate a third-party Android SDK that only exposes a callback interface for location updates. Your app's architecture uses Kotlin Flow throughout. How do you bridge the gap safely, and what edge cases do you watch for?

Sample answer outline

The solution uses callbackFlow to wrap the SDK callback. Inside the block, register the callback with the SDK and send values via trySend or send. Use awaitClose to unregister the callback when the flow is cancelled, preventing leaks. Edge cases include the SDK calling back on a background thread (safe, Flow handles it), buffer overflow if the consumer is slow (use a buffer with a drop policy), and the SDK not allowing re-registration without explicit unregister.

Expect these follow-ups

  • What happens if trySend returns false?
  • How would you unit test a callbackFlow that depends on the SDK?
situationalcallbackflowsdk-integrationkotlinandroid

As asked

You discover that a Ktor endpoint fetching a list of orders, each with associated items, is running N+1 database queries (one for orders, then one per order for items). The database is Postgres accessed via JDBC with Exposed. How do you fix this and how do you verify the fix?

Sample answer outline

Fix with a single join query (Exposed allows joining tables and mapping the result) or two queries with a batch fetch (fetch all items where orderId IN (...)). Verify with query logging in Exposed (addLogger(StdOutSqlLogger) or a QueryInterceptor), then switch to an integration test with a real Postgres instance (Testcontainers) that asserts on query count. The candidate should mention indexing the foreign key column.

Expect these follow-ups

  • How would you detect N+1 queries automatically in a CI pipeline?
  • What are the tradeoffs between a join and two separate batch queries for this case?
situationaln-plus-oneexposed-ormkotlindatabases

As asked

Tell me about a time you proposed replacing RxJava (or another reactive library) with Kotlin Flow in a project. How did you make the case and manage the transition risks?

Sample answer outline

The answer should show evidence-based advocacy: benchmarking coroutines vs RxJava overhead, showing reduced boilerplate with Flow, lower learning curve for new engineers. Transition risks include mixed codebases (Flow and Observable interop via asFlow), team retraining time, and behavioral differences (cold vs hot, back-pressure). A strong answer mentions a pilot module approach before full migration.

Expect these follow-ups

  • How did you handle the parts of the codebase where RxJava's richer operator set had no direct Flow equivalent?
  • What was the biggest technical risk in the migration?
behavioralflowrxjavakotlinteam-influence

As asked

Tell me about a time you had to make a breaking change to a shared Kotlin library that other teams depended on. How did you communicate and coordinate the change?

Sample answer outline

The answer should show a migration plan: adding the new API alongside the old, marking the old as @Deprecated with ReplaceWith, coordinating with consumer teams on a timeline, and providing a codemods script or IDE refactoring for the migration. The candidate should mention semantic versioning (a major version bump for breaking changes) and documentation updates.

Expect these follow-ups

  • How did you decide what timeline to give consumer teams for migration?
  • What would you do if a team was unable to migrate by the deadline?
behavioralapi-designlibrarykotlinteam-coordination

As asked

Describe a time you inherited a Kotlin codebase with problematic coroutine patterns (for example, runBlocking in a library, GlobalScope usage, or non-cancelled scopes) and had to clean it up while keeping the service running.

Sample answer outline

A strong answer shows a systematic approach: auditing usage with grep or a lint rule, triaging by risk (GlobalScope in UI vs in a background service), making changes incrementally with tests, and monitoring for regressions. The candidate should describe a specific risky change (e.g., removing runBlocking from a hot path without introducing starvation) and how they validated it.

Expect these follow-ups

  • How did you prioritize which debt to fix first?
  • What automated checks did you add to prevent regression?
behavioraltechnical-debtcoroutineskotlinrefactoring

As asked

Your Kotlin Multiplatform shared module works perfectly on Android but crashes on iOS with an uncaught exception from a coroutine. The iOS team has no Kotlin experience. Walk me through how you would diagnose and fix this.

Sample answer outline

Coroutine exceptions on iOS crash the process by default because the Kotlin/Native runtime calls the uncaught exception handler. The fix is to install a CoroutineExceptionHandler at the top-level scope in the shared module and expose suspend functions via a thin wrapper that converts exceptions to a Result type for Swift consumption. The candidate should also mention using MainScope() for UI-bound coroutines on iOS and the new memory model in Kotlin/Native 1.7.20+.

Expect these follow-ups

  • How do you write tests for the shared module that cover the iOS exception behavior?
  • What tooling do you use to debug Kotlin/Native crashes?
situationalkotlin-multiplatformioscoroutinesdebugging

As asked

A core Kotlin library used by dozens of services has a method that uses runBlocking to call a suspend function. Under high load, thread exhaustion occurs. You are asked to fix it without breaking the public API. What are your options?

Sample answer outline

Options include: (1) expose a suspend version of the method alongside the blocking one, deprecating the blocking variant; (2) convert the internals to async and cache the result to avoid repeated blocking; (3) use a dedicated bounded thread pool for the blocking calls to isolate the impact. The candidate should explain that removing runBlocking entirely requires consumers to adopt suspend, which is a breaking change, so option 1 is the safest migration path.

Expect these follow-ups

  • How do you ensure the new suspend variant is adopted and the old one is eventually removed?
  • What metrics would tell you the thread exhaustion is resolved?
situationalrunblockinglibrarykotlinperformance