Abstraction is Not Decoupling

Abstraction is certainly one of the most valuable tools engineers across disciplines have at their disposal. It is a particularly prominent aspect of software engineering as we not only work on top of many levels of abstraction (I for one do not know Maxwell’s equations let alone apply them) but we are also likely to construct new abstractions…of varying virtue. A unfortunate tendency I’ve seen, however, is to believe decoupling is an inherent benefit delivered by abstraction.

Abstraction is a crucial weapon against coupling, and decoupling is often one of the goals of abstraction. Proper decoupling almost certainly implies that appropriate abstractions have been introduced, but the converse (as outlined here) is not true.

First, even in cases where the abstractions are sound they may serve to provide a simplified model rather than decoupling. Revisiting the fundamental thread from above, constructs like Ohm’s Law and the lumped-circuit abstraction are both fantastically useful tools but do little to decouple produced artifacts from the laws of physics. In fact many such very useful abstractions could be viewed to do the opposite. By effectively packaging up more ready-to-use axioms derived from the system that is being abstracted the assumptions from those lower layers become foundational to what is built atop them.

Designing the right abstractions is closely related to modeling and is a skill which is not widely developed. Some tactical approaches such as using dependency inversion to prevent type coupling can address very focused concerns and can therefore provide the corresponding focused value. Similarly tracking and controlling edges between modules can help curb a system from devolving into spaghetti. Many of these more mechanical pursuits of decoupling are useful as a baseline since they can at least provide local values and facilitate future evolution. Standard design principles such as SOLID can go a long way towards actually delivering loose coupling, but most of the key bits are those that cannot be automatically enforced such as single responsibility.

The key point of this argument is that abstraction can also introduce costs; they may carry complexity or obfuscation that makes any system as a whole harder to reason about. If the abstractions are poor they can also result in a system being more brittle and prone to bugs. If there’s a perception that abstraction inherently delivers decoupling then it may lead to areas of concern being swept under the rug; any underlying issues still very much exist and are lurking in the dark corners waiting to issue painful reminders. A questionable design may now be masquerading as one that has superficially more design clout underneath a veneer of intent.