That's not an abstraction, that's a layer of indirection

Definition debates: abstraction vs. indirection vs. encapsulation

  • Several commenters argue much of what devs call “abstraction” is really:
    • Indirection: extra layers that just forward calls and permute arguments.
    • Encapsulation / information hiding: restricting access to implementation details.
    • Modularity: splitting code into components with minimal coupling.
  • A stricter view: an abstraction introduces a new semantic level or concept that lets you reason precisely (e.g., TCP streams over packets, “file” over devices), not just hide mechanics.
  • Others stress “generalization”: a good abstraction represents shared properties across multiple concrete cases; it usually only makes sense once you have at least two real implementations or repetitions.

What makes an abstraction “good”

  • Common criteria mentioned:
    • Creates a simpler “what” over a complex “how” (deep, small interfaces).
    • Aligns with the problem or business domain; easier to explain to non‑technical people.
    • Lets parts of the system change independently (e.g., hardware, database, protocol).
    • Rarely forces you to “peek under the hood”; the less you do, the better it is.
  • Cited positive examples: TCP, HTTP, filesystems, CRDTs, standard data structures, SQL, and classic algorithms when exposed via small, clear APIs.
  • Some argue not all abstractions must hide complexity; some primarily add flexibility or composability.

Bad abstractions, indirection hell, and leaky layers

  • Complaints about:
    • ORMs as leaky abstractions or mere mapping/indirection, often failing to really hide SQL and dialect differences.
    • Long chains of tiny wrapper functions, pointless interfaces with a single implementation, and overuse of patterns (factories, facades, adapters).
    • 3‑tier CRUD architectures and deep frameworks added “just in case” that never pay off.
    • UI layers over‑abstracted or over‑generalized, making display bugs hard to debug.
  • Examples of leaks and hidden costs: TCP vs close/reset semantics, unbuffered I/O hidden by a “read” call, ORM N+1 queries, performance surprises inside “identity” functions.

When and how to abstract

  • Strong support for:
    • Delaying abstractions until patterns or multiple implementations actually exist (“rule of three”).
    • Preferring simple, concrete code first, then refactoring into abstractions once real needs are understood.
    • Designing around orthogonal concerns and “key decisions” (e.g., storage, routing, encryption) rather than rigid vertical layering.
  • Several note an asymmetry of costs: authors enjoy immediate cleanliness; future maintainers pay for unnecessary layers.
  • Some say ultimately good abstraction choice comes from experience and judgment (“taste”), though others push for more explicit, teachable criteria.