CodeAdvanced

When is there too much abstraction?

“How do you recognise that a codebase has more abstraction than it needs, and how do you decide what to remove?”

What this tests

  • Concrete signals of over-abstraction, not vague discomfort
  • Whether the candidate can weigh abstraction against reading and change cost
  • A method for removing abstraction safely
  • Understanding that abstraction is a bet on future variation

Answers by level

Read the beginner answer first and notice what is missing.

Abstraction is a bet that something will vary. It pays when the variation arrives and costs indirection until then. Signals that the bet lost: interfaces with one implementation that has never changed; pass-through layers where a service method calls a repository method with the same name and arguments; generic base classes with one subclass; configuration for choices nobody has ever made; and tests that mock the abstraction to return exactly what the concrete thing would.

The cost is measurable. Reading a request path that crosses eight files to do a query is slower to understand and debug — a stack trace through six layers of delegation hides the one line that matters. Change cost rises too: adding a field means touching a DTO, a mapper, an interface, an implementation and a test double.

To remove it, I inline the pass-through layer, collapse the single-implementation interface into the concrete type, and keep the abstraction only at the seams where variation is real: external systems, and the places tests genuinely need to substitute behaviour.

Green flags · Red flags

Strong green flag · Applies the rule that a layer must transform, validate, decide or isolate — otherwise it is deleted.
Green flags
  • Names concrete signals: single-implementation interfaces, pass-through layers, mocks that mirror the real thing
  • Frames abstraction as a bet on variation with a carrying cost
  • Keeps abstraction at external boundaries and test seams
  • Has a safe removal method (inline, collapse, keep seams)
  • Mentions that extracting later is cheap with tooling
Red flags
  • "You might need it later, so keep it."
  • Cannot name a concrete signal beyond "it feels complex"
  • Treats interfaces as inherently good
  • Would remove the seams around external systems too (the opposite error)

Follow-up questions

F1
Which abstractions would you keep in a small service that talks to Stripe and Postgres?
F2
How do you tell an anemic service layer from a thin but useful one?
F3
What happens to tests when you inline a pass-through layer?

Scenario

A request to fetch a user profile passes through a controller, a facade, an application service, a domain service, a repository interface, a repository implementation, a mapper and a DTO — eight files, no branching, one SQL statement. A new engineer took two days to add one field. Decide what stays and what goes, and justify each.

Learn this topic