Posted On: 2022-05-16
Abstraction is an incredible design tool. It allows for comparison between unlike systems, and the ability to focus on the meaningful elements of a design during analysis or planning. Despite its immense utility, it's seldom defined or explained - programmers (myself included) often talk about it without giving a second thought to whether the audience understands what abstraction actually is. To rectify that, I've created this post - which will (hopefully) explain what abstraction is, both generally and in the domain of programming.
The simplest way to talk about the abstract is to start with its opposite: the concrete*. Something is concrete when it is specific, tangible, or fully realized. The table in front of me is a concrete object - I can touch it, see the signs of wear from prolonged use, and remember the years spent sitting at it working. In writing about the table in concrete terms, I am writing about this specific one, which is different from every other table in existence.
Abstraction, by contrast, is the exact opposite. Abstraction omits details, instead talking about things that are in common between multiple concrete objects. A table, in the abstract, is a supportive piece of furniture that provides a flat surface for use. To talk about my table, in the abstract, would likewise allow me to say things that are true of the many different concrete objects. I have owned and used many different tables, and I can use abstraction to talk about all of them at once, saying things like "I have always kept my computer monitor on my table*."
The ability to talk about many different things at once is incredibly powerful - it enables whole fields of work or study that simply cannot be properly explored by relying on the concrete. In mathematics, for example, the number 1 is not a concrete thing. Sure, you can have a single concrete thing (ie. one particular table) or a concrete representation of the number (ie. the pixels that together form the "1" that you see on your screen right now), but neither of those allow you to do math. You can't add concrete things - the process of adding (or even counting, for that matter), requires at least a bit of abstraction - grouping together multiple different concrete things is a (simple) act of abstraction.
With how common abstraction is, we often don't talk about it as such. We use abstraction in everyday things, from paying bills (every coin you own is a distinct, concrete thing - but thinking about that gets in the way of budgeting/spending them) to ordering a sandwich (you're not dictating which exact slice of cheese to include, after all.) Yet, for many people, abstraction is viewed as difficult or unapproachable - I've even heard some people use "abstract" as a synonym for "esoteric" or "inscrutable". This does a disservice to understanding abstraction: it distances people from a key part of their everyday lives, making it seem more obscure or difficult than it actually is.
While I'd rather not speculate on the historical/cultural factors that obfuscate peoples' routine use of abstraction, it is important to understand that abstraction is routinely presented as more difficult than it actually is. This is especially important for understanding abstraction in programming and system design: I've met plenty of programmers that shy away from abstraction - even though they are routinely using abstraction without thinking about it (the whole field of computer programming is built on abstraction: you're not coding for a specific computer, after all.)
When people talk about abstraction in programming, they are usually talking about one of two things: abstraction as an implementation tool or abstraction in design. The former refers to a process by which the details that multiple things (code, design, etc.) share in common are turned into something concrete (ie. an abstract class.) To be frank, the tools for doing this - inheritance, prototypes, or delegates - are not particularly intuitive, and are usually not a part of developers' routine efforts to make their code "just work." In my experience, these barriers often discourage using abstraction in implementation: learning/using unfamiliar tools is a barrier in itself, and any code change that makes things work less well - however briefly - can be viewed with hostility when on tight deadlines or stressful projects.
Abstraction in design is an incredibly deep topic - but at its most basic it is (I think) a rather intuitive one. In general, the goal of design abstraction is to make a design work for a wider range of situations than it currently does. Consider, for example, my old grocery list analogy: a single grocery list tells the shopper what to buy on a single visit. Perhaps it's just a list of reminders (ie. "eggs, milk, cheese") - this would work fine if the shopper is the one who wrote it, but a different shopper (ie. a friend helping out) probably wouldn't get the right quantity or kinds of items. To make a grocery list work for every shopper, one could be more specific: include details like how many and what brands to buy. This more detailed list could be described as being a design that is more abstracted: instead of working for only one concrete shopper, it can work for any one of a bunch of different shoppers.
One of the key things about abstraction in design is that it's usually possible to keep getting more abstract. In the example of the detailed shopping list, the shopper may be abstracted, but the contents of the list are still pretty concrete: they correspond to a single visit, and will change with every visit. To make a list that works with every visit, one might turn the grocery list into a form: print out a list of all possible items, and then write in the quantity for each individual trip. In this way, the form grocery list is more abstract than a manually written one, but it's still just as flexible. All designs are like this: there's (almost) always a way to make something more abstract, while still making sure that each concrete use of the design behaves exactly as desired*.
I hope this explanation of what abstraction is - both in general and in programming specifically - has been helpful. It's a very common tool, and a part of our everyday lives, so I think it's important to be comfortable both talking about it and intentionally using it. As always, if you have any thoughts or feedback, please let me know.