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.