Think of your favorite food. Maybe it’s pizza, chicken tikka masala, or maybe tiramisu. Whatever it is, imagine the texture, the flavors, and the satisfaction you feel after eating it. You probably have all sorts of words to describe your experience. Sweet, salty, crunchy, smooth, spicy. Hungry yet?
Now consider the molecular makeup of your favorite food, including the chemical compounds that deliver each flavor component to your taste buds. Think about the chemical reactions that took place during the preparation of this food, as well as during your consumption and digestion. Still with me?
My point is that our enjoyment of food doesn’t require any in-depth knowledge of the food itself. We care only that the food we eat gives us the experience we can describe in terms of flavor and texture; the molecular makeup isn’t important to us as consumers.
Now let’s say we’d like to open a restaurant specializing in molecular gastronomy. Suddenly, we need to know chemistry. In particular, we want to become familiar with the building blocks of food so that we can come up with our own novel creations. For example, if we understand the melting point of sugar and can tightly regulate the temperature of our cooking apparatus, we can create clear, crystal-like sugar sculptures without triggering a Maillard reaction that would otherwise result in bronze-like sculptures.
Now that I have your mind on food, let’s talk software. Using software is like eating food – we don’t need to know how it’s built in order to enjoy it. As developers, though, suddenly the building blocks of software are of interest to us. This comes into play particularly in the use of third-party libraries or abstractions.
What exactly do I mean by abstractions? Here’s how dictionary.com defines abstraction:
“The act of considering something as a general quality or characteristic, apart from concrete realities, specific objects, or actual instances.”
Now that’s interesting: “apart from…specific objects, or actual instances”. It’s like the definition of the word directly references object-oriented programming! But programming itself has always been exclusively about one thing: abstractions.
High-level languages allow us to write code in a powerful, human-readable form, which gives us a comfortable separation from assembly, binary, and, ultimately, the electronic circuitry of the machine itself. Each layer is an abstraction meant to bridge what originally seemed to be an infinite abyss between what we can touch and what we can automate.
Taken further, you can think of an API as an abstraction of the source code powering the API, or even a user interface as an abstraction of the API that powers it. Native mobile app users interact with the app, which interacts with an API, and this may trigger any number of other layered abstractions. These layers are conveniently coded for reuse without inconveniently requiring every layer to know about the others. For example, I can comfortably use the Facebook app on iOS without knowing that React, PHP, and Cassandra (among other technologies) are responsible for showing me my friends’ rants during the 2016 US Presidential Election.
Each level of abstraction allows us to focus on the problem we are solving, and not on the inner-workings of the problems that have already been solved in other layers. That is, we don’t need to know anything about assembly, binary, or electronic circuitry in order to be successful developers. We simply can think of the layers below us as a black box of stuff that works.
Getting comfortable with abstractions means that you aren’t constantly reinventing the wheel by, say, writing your own data structure when a suitable one already exists, or by coding your own web framework when an entire community of developers has spent tireless hours doing just that.
That said, you might be at a point in your educational journey where the complexity introduced by a third-party library clouds your ability to sufficiently understand the details of your application as a whole. And without sufficient understanding, this complexity feels more like magic. You might first need to verify that there is no underlying mystery in the libraries, classes, and frameworks that you’re using. If you are successful at convincing yourself of the absence of magic, you’ll see that these abstractions provide nothing more than extensible convenience, which allows you to focus on the new problems you’re solving rather than on the old problems others have already solved.
“Abstractions provide nothing more than extensible convenience, which allows you to focus on the new problems you’re solving rather than on the old problems others have already solved.”
Regardless of the language you’re using, understanding abstractions amounts to learning the building blocks of your craft. If you’re looking to revolutionize the culinary world with innovative cooking techniques and stunning food, your building blocks are molecules. If, on the other hand, you are looking to stay on the bleeding edge of software development, your building blocks are programmatic abstractions. Either way, you’d be well served to take a closer look.
How, then, do you go about taking a closer look? One approach is to look at some of the common abstractions you’re using, be they classes or entire frameworks, and examine the source code itself. Here are a few places to get started:
- Java: the OpenJDK implementation of an ArrayList
- Python: the CPython interpreter’s implementation of a list
- Ruby: Array implementation
Because this process isn’t necessarily straightforward, check back in next week for a follow up post where I’ll show you an example using the Java programming language.