Merrick Christensen's Avatar
Fundamentally, computer science is a science of abstraction — creating the right model for thinking about a problem and devising the appropriate mechanizable techniques to solve it.Jeffry Ullman

Art of Abstraction

2019-11-29

Monorepos & packages seem to be all the rage. However, simply relocating code to a package doesn’t make it more valuable. In fact, it can make it more expensive & introduce unexpected risks! The real value comes from good abstractions. Packages are a set of tools to author, encapsulate & distribute such abstractions. Here are some thoughts for you to consider when designing an abstraction.

Fundamentally, computer science is a science of abstraction — creating the right model for thinking about a problem and devising the appropriate mechanizable techniques to solve it. - Jeffry Ullman, Computer Science: The Mechanization of Abstraction

When creating a package it is important to consider the complexity we want the package to encapsulate. One of my favorite mental tools for reasoning about abstraction is the abstraction graph introduced by Cheng Lou in his talk "The Spectrum of Abstraction”, here is the TLDR;

A React Motion Abstraction Graph

A few definitions:

  1. Usefulness - Concrete use case for an abstraction.
  2. Power - How many downstream use cases an abstraction powers.
  3. Indirection Cost - Cognitive load is increased if an abstraction fails to encapsulate its complexity. For example, if react-motion required us to “go up” the chain and implement something with React directly in order to be “useful”. Then we paid the cognitive (and code size) cost of react-motion & the cost of react in order to fulfill our use case.

The value of an abstraction should exceed the cost of indirection. This value comes in the form of abstracting complexity and/or isolating risk.

The interface for an abstraction should strive for the minimum API surface intrinsically required to make it useful.

An abstraction should not “leak” the complexity of whatever it is responsible for encapsulating. Else we are doomed to incur the overhead of the abstraction and inherit the cost of the thing we were trying to abstract in the first place.

Abstraction is a tool for collective thought. It results in more cohesive APIs & tooling across projects because people are thinking & collaborating about things with a similar language.

Abstraction is a double edged sword. The right abstraction can be immensely valuable. The wrong abstraction can be extremely expensive. One is unlikely to create a useful abstraction over something they don’t understand and given the high impact potential of abstraction we should be prudent in our wielding of this power. A great deal of the risk in an abstraction comes from its conceptual overhead. Jeffry Ullman

“Don’t repeat yourself is the introductory step to the real principle; don’t repeat concepts.” - Jimmy Koppel

I’d recommend Hammock Driven Development as part of your exercise in identifying abstractions.

As a concrete example of a wonderful abstraction that abides by the above principles I offer React. React abstracts the complexity of keeping the DOM up to date efficiently & securely. React’s value also shines in its drastic reduction of API surface area compared to working with the DOM directly, you no longer have to think about the intricacies of the browser! Because you’ve taken on the constraints of working with the abstraction new opportunities are afforded, such as rendering to a different platform. React additionally gives us new concrete language like “Component” & “Element” to collaborate, as well as the ability to define our own language in terms of this collective language. React is truly a delightful abstraction for this and many other reasons.