The World Is Built on Abstractions

The World Is Built on Abstractions Featured Image

After writing this piece, I mostly fried my brain, but hopefully it helps folks come to terms with the concept of abstraction—even if it’s not in a software context.

Table of Contents

How to Throw a Ball

For a bit of background, I should mention that I like to teach early software education. There are a variety of reasons for that, which I won’t get into now, but I’ve slowly waded deeper into software education over time. Now, rather than teaching concepts like programming language syntax and software design patterns, I’ve found myself teaching concepts like software architecture and compiler design. And ultimately, I’ve had a lot of fun with it.

In this new class, we get into software architecture pretty early on. As a result, we have to introduce the concept of abstraction. However, rather than discussing this concept through a traditional lecture, I like to have students think through these ideas alone and in groups. To do that, I have students think about an almost universal task: how to throw a ball.

In an introductory programming course, I might give a similar task. Of course, the goals are much different. In an introductory programming class, I would be interested in getting students comfortable with “algorithmic thinking.” In other words, how would they go about writing the instructions for throwing a ball?

In my new course, I already know the students know how to write a set of detailed instructions to accomplish a task. This time, however, I’m interested in getting them to think about the task in terms of levels of abstraction. For example, at the top is the broad task: “throw a ball.” They then need to think about how they might explain the idea to someone who doesn’t already know. To demonstrate this, I’m going to try to walk through that activity right here with all of you!

The Tower of Abstraction: Body Mechanics

If I were to explain to someone how to throw a ball, there are several actions that come into play such as:

  • Grabbing the ball
  • Looking at the target
  • Raising the arm
  • Extending the arm
  • Letting go

There is, of course, probably other ways to break down the task of throwing a ball, but for the purposes of this activity, I think this is a great list. Hopefully, the person who you’re training already knows how to do these things, so they shouldn’t have any problem throwing a ball.

Now, what I would want to do is think about how we could label these actions as a layer of abstraction. In other words, what does our student need to know to be able to throw a ball? I would probably describe this knowledge as “body mechanics.” In other words, the person only needs to know how to move their body to be able to throw a ball.

The Tower of Abstraction: Anatomy

However, “body mechanics” itself is a level of abstraction. Surely, there is some underlying reality that allows us to speak to each other in terms of body mechanics. Therefore, the temptation at this point might be to try to break down the actions above into even more detailed actions, which you could do. For example, you might describe “grabbing a ball” as follows:

  • Opening palm
  • Placing hand over ball
  • Closing palm

And again, we could continue to break these terms down. For example, we might describe “opening palm” as follows:

  • Extending thumb
  • Extending fingers

Having done this activity with my classes, I’ve been pretty satisfied with the discussion ending here. However, while reflecting, I’ve come to the conclusion that we never actually reach a new level of abstraction. In other words, actions like “extending fingers” and “grabbing the ball” are all the same level of abstraction (but different grain sizes). And in fact, we almost certainly run into a wall in our descriptions. How do we describe extending a finger in more depth? I suppose we could talk about the physics of the movement where we introduce angles, positions, and velocities, but that doesn’t really take us anywhere new; we’re just getting more pedantic.

What I’m interested in is how we can model body mechanics. To do that, we would have to enter a domain that is out of our control: anatomy (or maybe it’s physiology; I’m out of my depth). In other words, our ability to extend our fingers is at complete mercy of our anatomy. Therefore, if we want to define any of the body mechanics, we have to talk about the various anatomical systems in our bodies (e.g., musculoskeletal system, nervous system, respiratory system, etc.). These are not things we ever really think about when we’re throwing a ball because we’ve already abstracted them away behind “body mechanics” concepts like grabbing a ball and extending the arm.

Ultimately, when we move down a level of abstraction, we have to change who (or what) we’re teaching. At this point, we’re no longer talking to a person; we’re now talking to the anatomy of that person. For example, we might have to speak in terms of engagement of certain muscle groups, such as the biceps and triceps or the abs. With enough knowledge of anatomy, we could define all of the body mechanics needed to throw a ball.

The Tower of Abstraction: Cell Biology

I think what you’ll find is that even anatomy has its limits. After all, when we discuss anatomy, we talk about systems of organs which each perform certain functions. Let’s take the circulatory system for example. This system is made of a variety of organs, such as the heart and blood vessels. At this level, we can still talk about the system in terms of anatomy (e.g., beat the heart). But interestingly, there are almost no other actions that we can describe: the heart beats or it doesn’t. Therefore, it’s what the heart is made of that launches us into a new level of abstraction: cell biology.

The heart itself is made of cells, and as I’ve learned, we can begin defining the “beating of the heart” action through the behavior of these cells. Specifically, the National Heart, Lung, and Blood Institute (NHLBI) states the the heart beats as a result of what is called the cardiac conduction system. The system works by sending an electrical signal up and down the heart, causing it to contract. The process itself can be described in terms of cell biology as follows:

  • The signal begins in a group of cells, called pacemaker cells, located in the sinoatrial (SA) node in the right atrium.
  • The electrical signal travels through the atria, causing them to pump blood into the ventricles.
  • The electrical signal then moves down to a group of pacemaker cells called the atrioventricular (AV) node, located between the atria and the ventricles. Here the signal slows down slightly, allowing the ventricles time to finish filling with blood.
  • The AV node fires another signal that travels along the walls of your ventricles, causing them to contract and pump blood out of your heart.
  • The ventricles relax, and the heartbeat process starts all over again in the SA node.
NHLBIOpens in a new tab.

Who would have thought we’d get here from throwing a ball? That’s how complex the world really is!

The Tower of Abstraction: To Infinity and Beyond

Now interestingly, cells are not the lowest level of abstraction. After all, we can talk about what cells are made of, which I think starts to get into chemistry. Unfortunately, it’s tough to say what might be the most basic level of abstraction, but I think the “physical world” is about as close as we’re going to get. At that level, the smallest building blocks in the physical world are atoms and their associated subatomic particles.

At first, I was somewhat tempted to break down the physical world even further into concepts like math and philosophy, but those actually introduce abstractions. For instance, you can’t observe the number “5.” It’s a concept that we abstracted to describe our world. Hell, even words are abstractions of concepts, so the whole conversation starts to become a mess!

My Head Is Spinning

At times, I think it can be somewhat challenging to actually draw a line and say “this is a different level of abstraction,” and I even think the argument I made in this article about where I drew the lines (e.g., body mechanics vs. anatomy vs. cell biology) is up for debate. With that said, I think the following statement might better help you understand the concept of abstraction:

A triangle can be drawn in the sand, on paper, or on a monitor, but the triangle is not sand, not ink, and not pixels.

Keinosuke Johan MiyanagaOpens in a new tab.

I love this example because it show a couple of key ideas. First, what the triangle is made of has no significance in the interpretation: a triangle is a triangle regardless of how it’s constructed. Second, as a consequence of the first idea, a triangle can be configured in many ways and still be a triangle. That may sound like I’m saying the same thing twice, but there’s a key distinction. For the person viewing the triangle, the medium is irrelevant. For the person constructing the triangle, there’s freedom in the medium.

If we bring these ideas all the way back to throwing a ball, we find that there’s perhaps a lot of different ways that “throwing a ball” can be represented. We happened to go down the human biology rabbit hole, but no one said that a human had to be throwing the ball. Maybe a robot is throwing the ball or maybe the ball is being thrown in a video game. Even in the realm of humans, there are different abilities. For example, someone with a prosthetic arm would have different concerns at lower levels of the hierarchy. Ultimately, the high level of abstraction of “throwing a ball” allows it to live in many contexts, whereas the lower level abstractions are less flexible (e.g., the circulatory system isn’t exactly transferable to a robot).

How Does This Connect to Software?

All the philosophy aside, we can actually have this exact discussion about abstraction from the perspective of software. Fortunately, drawing the lines is a little bit easier.

To start, think about a program you’ve written. For instance, you’re probably familiar with the infamous FizzBuzz. At your level of abstraction, you are probably most concerned with some programming language. In other words, how do you assemble the syntax of that language to get the computer to do what you want?

In reality, there is a lot of stuff happening under the hood! For example, the text you’re putting into your keyboard has to show up on a display. Therefore, graphics have some sort of tower of abstraction that we rarely think about. Similarly, the program you’re writing has to make its way down the tower of abstraction, so the computer can make sense of it. That process is known as compilation (and/or interpretation) and involves walking from the high level that you live at down to machine code. Along the way, the code might hit several levels of abstraction, such as the byte code level.

Even once your code makes it to machine code, there are still a few levels of abstraction below. For instance, you can think about how the computer takes your machine code and computes FizzBuzz with it. At that level, the machine is concerned about decoding instructions and moving numbers around in memory—in fact, it doesn’t even know what FizzBuzz is.

Of course, the numbers moving around in memory are also an abstraction. Computers don’t think in base 10. They think in base 2 (i.e., binary). And naturally, that’s just an abstraction of voltages on transistors, which of course is an abstraction on electrons.

Fortunately, as programmers, abstractions are our friends! Our lives are much easier than they used to be, though these advantages have brought along greater demands. Regardless, before the modern programming languages we use today, folks were using more rudimentary programming languages that didn’t have support for key features like objects or even functions. In some cases, folks didn’t even use keyboards or terminals, which we might already argue are too low level for modern use. Instead, people coded using punch cards. Hell, old arcade games were “coded” with hardware. There was no programmable hardware at one point.

All of this is to say that all of software is built on abstractions and that good software works hard to clarify those abstractions. Failure to do so results in what’s known as a leaky abstractionOpens in a new tab., though this is often unavoidable to a certain degree. Regardless, in the course I teach, we spend a lot of time just implementing data structures with special attention to drawing the line between abstractions. Specifically, we talk a lot of about how to hide underlying details of our data structure, so users never have to be concerned about them. It’s like the triangle example. We don’t want our users to know the triangle is made of sand, ink, or pixels. As an added benefit, we can change the underlying details at will with no consequences to our users. Today, the triangle is made of sand, but when I get my paycheck, it’ll be made of gold.

Moral of the Story

As you can probably guess, as much as I love talking about programming related concepts, I love critiquing our community so much more. Therefore, if there’s anything that you take away from this article, it’s this:

Everybody in our field uses whatever tools they want, and I think that’s great! However, I don’t love it when conversations in our community revolve around what it takes to be a “real” programmer. Therefore, if you ever catch anyone claiming you’re not a “real” programmer because you use a particular programming language or a particular tool, I encourage you to lean into the conversation by considering the tower of abstraction of tech. In other words, you can always undercut their claim with something further down the tower. If they say they don’t use a mouse because they’re a terminal wizard, tell them your keyboard only has two keys: 0 and 1.

All jokes aside, I’ve talked about these ideas a lot on this site but never really in a single place. As a result, I’m going to dump a lot of related pieces, so you can see many of these ideas in different contexts:

One last thing I’ll mention is that I’m thinking about reworking the activity I do with students in the future. Working with verbs (i.e., throwing a ball) makes the analogy I’m trying to draw to component-level design somewhat messy. After all, we tend to think of verbs in the context of functions, which are a form of abstraction but don’t map well to the OOP concepts we’re trying to cover. It would perhaps be easier to start with a noun and talk about what that noun is made of. Or even better, stick with the triangle idea and let folks make the abstraction more concrete over time (e.g., a triangle can be made of sand and sand can be made of certain materials). Whatever I settle on, I’m sure it will work out!

With that out of the way, let’s call this rambling piece finished! I have to get back to writing my dissertation…

As always, if you liked this and want to see more like it, I’d appreciate it if you made your way to my list of ways to grow the site. Otherwise, take care!

Coding Tangents (43 Articles)—Series Navigation

As a lifelong learner and aspiring teacher, I find that not all subjects carry the same weight. As a result, some topics can fall through the cracks due to time constraints or other commitments. Personally, I find these lost artifacts to be quite fun to discuss. That’s why I’ve decided to launch a whole series to do just that. Welcome to Coding Tangents, a collection of articles that tackle the edge case topics of software development.

In this series, I’ll be tackling topics that I feel many of my own students have been curious about but never really got the chance to explore. In many cases, these are subjects that I think deserve more exposure in the classroom. For instance, did you ever receive a formal explanation of access modifiers? How about package management? Version control?

In some cases, students are forced to learn these subjects on their own. Naturally, this forms a breeding ground for misconceptions which are made popular in online forums like Stack Overflow and Reddit. With this series, I’m hoping to get back to the basics where these subjects can be tackled in their entirety.

Jeremy Grifski

Jeremy grew up in a small town where he enjoyed playing soccer and video games, practicing taekwondo, and trading Pokémon cards. Once out of the nest, he pursued a Bachelors in Computer Engineering with a minor in Game Design. After college, he spent about two years writing software for a major engineering company. Then, he earned a master's in Computer Science and Engineering. Today, he pursues a PhD in Engineering Education in order to ultimately land a teaching gig. In his spare time, Jeremy enjoys spending time with his wife and kid, playing Overwatch 2, Lethal Company, and Baldur's Gate 3, reading manga, watching Penguins hockey, and traveling the world.

Recent Posts