Interview Practice

Theory then practice

Object-oriented design

Contracts, composition, state, concurrency and complete design rounds.

Theory chapters

Prerequisites: Java classes/interfaces and the basic collections chapters.

  1. Chapter 1Objects, contracts and invariants

    Model responsibilities and legal states before drawing classes.

  2. Chapter 2Composition, SOLID and patterns with purpose

    Use patterns to manage real variation, not to decorate a class diagram.

  3. Chapter 3Designing caches, schedulers and rate limiters

    Connect class structure to operation costs and concurrency requirements.

  4. Chapter 4A complete design round: booking and payment

    Walk a design through success, conflict, failure and recovery.

  5. Chapter 5Designing for change: a notification service

    Separate what varies (channels, templates, policies) from what must stay reliable (delivery state).

Interview questions

Try answering aloud before opening an answer. Reading an answer is exposure, not proof of independent mastery. Save reflections in your mistake notebook.

20 of 20 questions

Beginner

What are encapsulation, abstraction and polymorphism?

Reveal answer and example

Encapsulation protects state and invariants. Abstraction exposes the capabilities callers need, while polymorphism lets implementations satisfy the same contract with different behavior.

Example: A PaymentGateway contract hides provider-specific network details from checkout.

Big O is not intrinsic to this conceptual question. Define the implementation, input size and operation before assigning a complexity.

Common mistake: Getters and setters for every field do not automatically produce meaningful encapsulation.

Follow-up: Where should payment validation live?

Beginner

Composition or inheritance?

Reveal answer and example

Prefer composition when behavior should vary independently or the relationship is uses-a. Use inheritance only when subtypes genuinely honor the parent's behavioral contract and substitution remains safe.

Example: A report service uses a formatter strategy rather than subclassing for every format/delivery combination.

Big O is not intrinsic to this conceptual question. Define the implementation, input size and operation before assigning a complexity.

Common mistake: Reusing code through inheritance can expose methods that violate a subtype's invariants.

Follow-up: What changes when subclasses need incompatible preconditions?

Beginner

What does encapsulation protect beyond hiding fields?

Reveal answer and example

Encapsulation protects invariants. An object should expose operations that keep its state valid instead of setters that let callers put it in any state. Private fields with public getters and setters for everything is still poor encapsulation, because the rules live in callers and drift apart.

Example: BankAccount.withdraw(amount) checks the balance and records a transaction; there is no setBalance.

Big O is not intrinsic to this conceptual question. Define the implementation, input size and operation before assigning a complexity.

Common mistake: Returning internal mutable collections from getters, which lets callers bypass every check.

Follow-up: How would you expose an account's transaction history without allowing modification?

Beginner

Interface or abstract class?

Reveal answer and example

Use an interface to define a capability that unrelated classes can implement, since a class can implement many interfaces; default methods can add behavior without breaking implementers. Use an abstract class when subclasses share state or a construction protocol and a single inheritance line is acceptable. Prefer interfaces at boundaries so callers depend on contracts.

Example: PaymentGateway as an interface implemented by Stripe and Adyen adapters; AbstractRetryingClient holding shared HTTP state and backoff.

Big O is not intrinsic to this conceptual question. Define the implementation, input size and operation before assigning a complexity.

Common mistake: Creating deep abstract hierarchies for code reuse when composition with a helper would be simpler.

Follow-up: When could a default method on an interface cause a conflict for an implementing class?

Intermediate

How do you apply SOLID without overengineering?

Reveal answer and example

Keep responsibilities cohesive, depend on useful abstractions at change boundaries and preserve substitutable contracts. Apply interface segregation and extension points to actual variation rather than inventing a hierarchy for every class.

Example: Separate price calculation from receipt delivery so either can change independently.

Big O is not intrinsic to this conceptual question. Define the implementation, input size and operation before assigning a complexity.

Common mistake: One interface per class is not a goal; unnecessary indirection makes simple flows harder to follow.

Follow-up: Which likely change justifies an interface in your current design?

Intermediate

When should you use Strategy instead of conditionals?

Reveal answer and example

Use Strategy when alternative policies have a stable contract and evolve independently. A short, stable switch can be clearer when the choices are fixed; explain the change pressure before adding objects.

Example: A ShippingCostPolicy computes a quote for a destination and package.

Big O is not intrinsic to this conceptual question. Define the implementation, input size and operation before assigning a complexity.

Common mistake: A strategy that mutates unrelated shared state makes interchangeable behavior difficult to reason about.

Follow-up: How would you validate and select an allowed strategy?

Intermediate

Factory, builder or dependency injection?

Reveal answer and example

A factory encapsulates creation choices; a builder assembles a complex value with readable optional parameters. Dependency injection supplies collaborators and lifecycle ownership rather than being another name for any constructor.

Example: A builder validates an immutable search request; a container wires the search service.

Big O is not intrinsic to this conceptual question. Define the implementation, input size and operation before assigning a complexity.

Common mistake: Builders should not allow invalid objects to escape before validation.

Follow-up: How would you prevent callers from forgetting a required field?

Intermediate

What should an event publisher promise to subscribers?

Reveal answer and example

Specify delivery timing, ordering, failure isolation and subscription lifetime. In-process observer callbacks are not durable messaging and need explicit handling for slow or failing subscribers.

Example: A UI model publishes changes and unregisters listeners when the view closes.

Common mistake: One throwing callback should not accidentally prevent required cleanup or unrelated delivery.

Follow-up: When must an event move to a durable outbox/message broker?

Intermediate

Design a parking lot from requirements.

Reveal answer and example

Clarify vehicle/space types, allocation, pricing and concurrency first. Model a ticket lifecycle, a spot repository and pricing policy; make spot reservation and ticket creation atomic within the chosen persistence boundary.

Example: A ticket transitions from active to paid to exited with a defined policy for lost tickets.

Common mistake: A class diagram alone does not prevent two attendants allocating the same spot.

Follow-up: How would EV charging or reservations change the model?

Advanced

How would you design an elevator controller?

Reveal answer and example

Separate car state, door safety, request queues and a scheduling policy. Define permitted transitions and hardware interlocks before optimizing routing; a local simulation cannot replace real safety systems.

Example: A car must not move while its door-open interlock is active.

Common mistake: Treating an elevator as a simple sorted list ignores direction, capacity and safety constraints.

Follow-up: How would emergency mode interrupt normal scheduling?

Intermediate

How do you model a vending machine with State?

Reveal answer and example

Represent legal transitions such as idle, funded, dispensing and refunding. Keep inventory and money invariants explicit and handle a dispense failure without pretending the sale succeeded.

Example: Insufficient funds must not decrement inventory; a failed dispenser needs a refund/recovery policy.

Common mistake: A collection of booleans permits impossible combinations like idle and dispensing together.

Follow-up: What happens if the process restarts after charging but before dispensing?

Advanced

Design a token-bucket rate limiter.

Reveal answer and example

Define capacity and refill rate, update tokens using elapsed monotonic time, then atomically consume if enough remain. Clarify whether limits apply per process, tenant or across a distributed fleet.

Example: A capacity of ten allows a burst of ten while refilling at the configured rate.

Common mistake: Unsynchronized read-check-write can grant the same tokens to multiple threads.

Follow-up: How do you bound memory for inactive users?

Advanced

Design a task scheduler with cancellation.

Reveal answer and example

Separate task identity, due time, execution ownership and lifecycle. Use a priority queue for next due time and define whether cancellation can prevent execution after a worker has claimed a task.

Example: Cancellation before claim prevents execution; after claim it may only request cooperative interruption.

Common mistake: Removing an arbitrary item from a basic heap is not automatically logarithmic.

Follow-up: What must change to survive a process crash?

Advanced

Design a booking workflow that prevents double booking.

Reveal answer and example

Define the availability interval, hold expiration and confirmation states. Use a storage-enforced uniqueness/exclusion rule or atomic conditional write, and make payment retries idempotent.

Example: Two concurrent requests for the same seat cannot both confirm, even if both earlier reads saw it free.

Common mistake: An in-memory lock on one application instance does not protect a multi-instance service.

Follow-up: How would you recover payment success followed by confirmation failure?

Intermediate

How do you model money and time correctly?

Reveal answer and example

Use a money value object with amount, currency and explicit rounding rules. Represent instants and business time zones separately; use a clock abstraction for deterministic time-sensitive tests.

Example: Two USD amounts can be added; adding USD to EUR requires an explicit conversion policy.

Big O is not intrinsic to this conceptual question. Define the implementation, input size and operation before assigning a complexity.

Common mistake: Binary floating-point and a server-default time zone are unsafe defaults for many financial rules.

Follow-up: Where should tax rounding occur: line item or invoice total?

Intermediate

When should you use the State pattern?

Reveal answer and example

Use State when an object's allowed operations depend on its current state and conditional logic over a status field is spreading. Each state object implements the operations it permits and returns the next state, so illegal transitions are impossible or explicit. In Java, a sealed interface of state records or an enum with transition methods often expresses this compactly.

Example: An Order moves Created → Paid → Shipped → Delivered; cancel is allowed only before Shipped.

Big O is not intrinsic to this conceptual question. Define the implementation, input size and operation before assigning a complexity.

Common mistake: Creating a class per state for a two-state toggle; a boolean or enum is clearer.

Follow-up: How would you persist the state and guard against two concurrent transitions?

Intermediate

How does the Decorator pattern differ from inheritance?

Reveal answer and example

A decorator implements the same interface as the object it wraps and adds behavior before or after delegating. Decorators compose at runtime in any order, while subclassing fixes combinations at compile time and multiplies classes. Java I/O streams and Spring's proxies are familiar examples.

Example: new RetryingClient(new CachingClient(new HttpPriceClient())) adds caching and retries without changing HttpPriceClient.

Big O is not intrinsic to this conceptual question. Define the implementation, input size and operation before assigning a complexity.

Common mistake: Ordering mistakes, such as caching outside retries versus inside them, change behavior and must be deliberate.

Follow-up: How would you test each decorator independently?

Advanced

How do you make a stateful object thread-safe?

Reveal answer and example

State an invariant and identify the atomic boundary needed to preserve it. Choose confinement, immutability, locks or appropriate concurrent primitives; document ownership and avoid holding locks during slow external calls.

Example: Protect both balance updates under a consistent lock order for an in-memory transfer.

Big O is not intrinsic to this conceptual question. Define the implementation, input size and operation before assigning a complexity.

Common mistake: Concurrent collections do not make a sequence across several objects atomic.

Follow-up: How would you detect and prevent a lock-order deadlock?

Advanced

How do you evaluate an object-oriented design in an interview?

Reveal answer and example

Walk a concrete use case through interfaces, state transitions, failures and tests. Evaluate cohesion, dependency direction and how likely changes affect the model; explain tradeoffs rather than naming patterns as the answer.

Example: Add a second payment provider and trace which code must change and which contract tests stay valid.

Big O is not intrinsic to this conceptual question. Define the implementation, input size and operation before assigning a complexity.

Common mistake: Presenting only the happy path misses concurrency, recovery and lifecycle responsibilities.

Follow-up: Which requirement would force the largest redesign, and why?

Advanced

Design a notification service supporting email, SMS and push.

Reveal answer and example

Model an immutable Notification with an idempotency key, a Channel interface per transport that returns sent, retryable or permanent results, a TemplateRenderer and a chain of Policy objects for preferences and quiet hours. A Dispatcher claims the notification, applies policies, renders and sends, and a DeliveryAttempt state machine drives bounded retries with backoff.

Example: Adding WhatsApp is one new Channel implementation; adding quiet hours is one new Policy; neither changes the Dispatcher.

Big O is not intrinsic to this conceptual question. Define the implementation, input size and operation before assigning a complexity.

Common mistake: Putting retry and fallback logic inside each channel, which duplicates policy and causes double sends on fallback.

Follow-up: How would you guarantee a user is not notified twice when two workers pick up the same job?

Reference documentation