This post is inspired by a tweet this morning suggesting that abstraction is simply a way of making code that does nothing but call code that does. Of course I disagree. Abstraction in computer programming creates code that does something very important… it abstracts. Following my philosophy of “right tool for the job”, then abstraction is the tool you use when you want to be able to hide details from higher level functionality. There is more to writing code than thinking about the steps the processor takes to execute it.
The world of programming can be split into roughly two; those programmers who understand the tool of abstraction and those who do not. In my experience, programmers who properly understand the tool of abstraction and its uses are a minority, even though all programmers use abstraction in some shape or form.
To demonstrate what abstraction is I like to use a real world example: good old fashioned post. When you write a letter to someone, you execute a delivery transaction by placing the letter in an envelope. Upon the envelope you write instructions for its delivery. The postal service is then able to deliver the letter without concern about the contents of it. The machines and personnel that execute delivery really do not care about what the mail contains, only the instructions for where the package of information should go.
The above scenario is very similar to software abstraction. The letter has an implementation (the contents) which is encapsulated (in an envelope). The encapsulation has an interface (the writing upon it) that implements a protocol (the address).
Can you imagine a world where letters were delivered according to contents? Where to decide what to do with a letter is was necessary to read it? Think about all the reasons why this would not be a good plan, and you will have your explanation of why we place letters in addressed envelopes. Although one could say “Envelopes are a way of adding more paper and information to a letter that is not needed by either the person who writes it or the person who reads it”, it would hardly be a fair statement, would it?
Of course, abstraction is not without its pitfalls. Let’s take a look at some of the issues.
First of all there is the problem that we have duplication of information (which translates to more memory usage in computer programs, something that usually want to avoid in low level coding). The identity of the recipient is probably both on the letter itself and also on the envelope. This duplication is a common cost of abstraction, although sometimes you can create clever solutions (a plastic window on the envelope that shows you the address on the letter – the equivalent of providing a constant reference to a part of the implementation).
Additionally, the abstraction increases the weight of the letter (which may be considered a loss in performance).
Further there is an interesting cost that you may not have considered: The envelope actually adds some complexity, and thus creates opportunities for things to go wrong that could not otherwise. The address may be incorrect for the contents, as an example, resulting in the letter being delivered to the wrong recipient. The letter may shift in the envelope hiding part of the address in the plastic window (if one is used). The delivery address may be mistaken for the return address and so on.
Do these disadvantages mean that we should not use the addressed envelope tool? Of course not. They are far outweighed by the worse things that would happen if we did not use addressed envelopes. Such things as:
- Privacy (it is not desirable for everyone to be able to read the contents)
- Integrity (if the letter is not protected in an envelope it may become damaged by elemental factors and handling)
- Speed of processing (although the protocol adds complexity and use of resources, it speeds up the process of delivery through use of a standard protocol that is independent of the contents of the letter)
- Simplicity (the life of the postal worker is made much easier by removing information they do not require in order to execute their jobs)
Of course, you may say that programming is different. Well it turns out on analysis (at least it turned out after my own analysis, why not do your own analysis to see if I am right) that even though every programming problem is different, there are issues that arise commonly in all circumstances. By studying the example of letter delivery (if one can get over any prejudice such as “Why on earth is a computer programmer going on about the postal service”) you will learn about abstraction and then be able to apply this to software abstractions. Which brings me to a final advantage of abstraction: fitting multiple complex scenarios into a single unified abstraction is a great way to become versatile. Why? Because you develop a general purpose pattern that can be applied to situations you have never encountered before.
Abstraction is an orgnisational tool that can help you maintain flexibility as complexity increases. If you follow my posts, you may recognize this from a previous post called “Beware the Bemusing Triangle”. In it I described the robust FLEXIBILITY – COMPLEXITY – ORGANISATION triangle. To maintain flexibility in an increasingly complex world, one must get organised and abstraction is the most powerful tool for doing so.
Of course you can go too far. Memos in an office of 4 people do not require addressed envelopes, for example. But this is simply a case of using the right tools for the task. Generally, the more complexity, the greater the need for abstraction.
In video game programming, the most popular programming activity appears to be graphics programming. The irony is that this is probably the least complex part of a video game, compared to asset management, behavior management (also known, inaccurately as AI) and user interfaces. All stuff that many programmers find boring or at the very least “not sexy”, but all stuff that is absolutely essential to shipping a game.
Well, if you are a graphics programmer, layers of abstraction are likely to get in your way, but it is misguided to think that means abstraction is bad. It is not a question of whether or not to abstract, but where to abstract.
One programmer I worked with a many years ago kept moaning at me because I was using virtual methods in a console game. “You can’t do that, it will run like a dog! It will break the cache! blah blah blah blah”. Of course, I know this. I know it because I am a rather experienced programmer (30 years) who has worked on all kinds of platforms, configurations and processors. But I also know that virtual functions are a great way to keep his hacky, messy code away from my code. And I also know that it is far easier to take working, but slow, code and speed it up by adding hacks, than it is to hack from the start and get it to work. So created an abstraction layer using pure virtual classes. I developed the gameplay on a PC. Most of the PC code shipped in the console without modification. The threatened disaster of virtual function cache breaking did not appear. I did not even need to optimise everything.
How did I do that? How did commit the cardinal sin of using virtual functions on a processor that hates virtual functions and get away with it? Simple. I chose where to abstract carefully.
Sure in the depths of the rendering pipeline, virtual functions would be a bad idea. But at the object level, where there may be only 10 or 20 objects being manipulated (or even hundreds), the performance cost of a thin abstraction layer that provides code organisational advantages can hardly be measured. The abstraction I am talking about is at the level of “Place this game object at this location”.
“Hey, Fred”, (real name concealed to protect them), “You know those horrible virtual functions I am using? They are only called a total of about 1000 times per second. That’s a few cycles cost once every millisecond. So this performance impact you keep talking about can hardly be measured. Meanwhile the code works. So please get off my back”.
So next time you have a lead programmer, a colleague or even a teacher speak about the wonders of abstraction, do yourself a favor and try to put any prejudices you have about software engineering away. Remember the letter. Remember that the great programmers find a balance, and that you will never find that balance if you dismiss half of the equation out of hand. You can never choose the right tool if you are unaware of the tool that solves your problem. And you can never learn to be a better programmer if you are prejudiced against the paths that will help you.