Skip to main content

Interview questions

Scala engineer interview questions

Scala engineers usually work on distributed data systems, backend services or functional programming-heavy platforms. Interviews test JVM fundamentals, type systems, collections, Spark or Akka experience and the ability to keep complex abstractions maintainable.

Seniorities
juniormidseniorstaffprincipal

Most reported

Top scala engineer interview questions

6 questions

Sorted by reported frequency. Click any question for the sample outline, follow-ups, and reference implementation.

As asked

In Scala, when would you use Future directly, and when would you reach for an effect system such as cats-effect or ZIO?

Sample answer outline

Future starts running eagerly and is tied to an ExecutionContext, which is fine for simple service calls but makes cancellation, resource safety and deterministic tests harder. Effect systems represent work as values, so execution, retries, cancellation, timeouts and resource scopes can be composed before the program is run. The tradeoff is complexity and team learning cost. A strong answer names the operational benefits: bounded concurrency, structured resource handling and better testing with controlled runtimes. Candidates often describe effect systems as only functional style rather than as production control over side effects.

Expect these follow-ups

  • Why does eager execution make Future awkward in tests?
  • How does Resource prevent leaks?
  • When would an effect system be overkill?
futurecats-effectzio

As asked

Walk me through covariance and contravariance in Scala. When would you mark a type parameter as +A versus -A, and what does the compiler actually enforce when you do that?

Sample answer outline

A strong answer explains that +A means the type constructor is covariant, so List[Cat] is a subtype of List[Animal], while -A means contravariant, so Function1[-A, +B] accepts a wider input type. The candidate should explain that the compiler enforces positions: covariant type params can only appear in output positions, contravariant only in input positions. Bonus for mentioning invariance in mutable containers like Array[A] and why mutation breaks the substitution principle.

Expect these follow-ups

  • Why is Array[T] invariant in Scala even though List[+T] is covariant?
  • How does variance interact with bounds, like +A <: Animal?
type-systemvariancegenericsscalacompiler

As asked

How did Scala 3 change the implicit system? Walk me through the differences between Scala 2 implicits and Scala 3 givens and using clauses, and tell me about a real migration problem you would face going from 2 to 3.

Sample answer outline

Strong answer covers the renaming from implicit val/def to given/using, the new import syntax (import given), and how Scala 3 restricts implicit conversions to reduce footguns. Should mention the canonical given derivation pattern and how given instances replace implicit objects. A good candidate also mentions that implicit search rules changed and that some Scala 2 library implicits require a compatibility layer.

Expect these follow-ups

  • How do you handle a library that still uses Scala 2 implicits when your codebase is on Scala 3?
  • What scalacOption would you enable to get warnings about implicit conversions being applied silently in Scala 2, and what replaced that concern in Scala 3?
implicitsgivensscala3migrationtype-classes

As asked

Show me how you would define a Show type class in Scala and provide instances for Int, String, and a case class Person. Then explain how the compiler resolves which instance to use at the call site.

Sample answer outline

Candidate should write a trait Show[A] with a method show(a: A): String, then provide implicit (or given in Scala 3) instances. The call site uses an implicit parameter or context bound syntax [A: Show]. They should describe the Scala 2 implicit search order: (1) local definitions and block scope including method parameters, (2) inherited members of the enclosing class, (3) implicit scope of types involved, which means the companion objects of A and Show. Explicitly imported implicits also fall in tier 1 and beat companion objects. Bonus for explaining ambiguity: two instances at the same priority tier produce a compile error, not a silent pick.

Expect these follow-ups

  • What is a context bound and how does it desugar at the bytecode level?
  • How would you derive a Show instance for a generic case class automatically in Scala 3 using Mirror?
type-classesimplicitsscalafunctional-programmingderivation

As asked

Walk me through Akka's supervision tree model. What are the built-in supervision strategies, when would you use OneForOneStrategy versus AllForOneStrategy, and how do you avoid silently swallowing failures?

Sample answer outline

Strong answer covers the hierarchy: every actor has a parent that supervises it. OneForOneStrategy applies the directive (Resume, Restart, Stop, Escalate) only to the failed child; AllForOneStrategy applies it to all siblings too. Should mention the Decider partial function and how Escalate bubbles up. A common pitfall is not logging inside the decider, so failures vanish silently. Good candidates also mention Akka Typed's behavior-based supervision.

Expect these follow-ups

  • How does supervision change in Akka Typed compared to classic actors?
  • What happens to messages in the mailbox when an actor restarts?
akkaactorssupervisionfault-tolerancescala

As asked

Explain what happens during a shuffle in Spark. What triggers a shuffle, what are the performance costs, and what are three concrete techniques you use in production to reduce shuffle overhead?

Sample answer outline

Shuffle is triggered by wide transformations like groupByKey, join, or repartition. Data is written to local disk by map tasks and read by reduce tasks across the network. Costs include disk I/O, serialization, and network transfer. Concrete optimizations: (1) use reduceByKey instead of groupByKey to combine locally before shuffle, (2) broadcast join when one side is small enough to fit in memory, (3) partition on a relevant key beforehand to avoid re-shuffling. Bonus: mention AQE (Adaptive Query Execution) in Spark 3.

Expect these follow-ups

  • How does a sort-merge join differ from a broadcast hash join in Spark, and when does AQE switch between them?
  • How do you diagnose excessive shuffle spill in the Spark UI?
sparkshuffleperformanceoptimizationbig-data

Also known as

Scala developer - JVM engineer - Spark engineer