Design Patterns, Smalltalk, and the Lost Art of Reading Code

Kyle Gene Brown
The Startup
Published in
13 min readSep 22, 2020

--

Kyle Brown, IBM Fellow, CTO Cloud Architecture, IBM Cloud and Cognitive Software

The last year has not been kind to a book that I believe to be one of the classic, and most important works of computer science — the book Design Patterns: Elements of Reusable Object Oriented Design. This is unfortunate, because the preceding year had been the 25th anniversary of the book’s publication and it’s odd that a book that old can generate such vitriol. The twitterverse in particular has been pretty savage to the book — using words like “impenetrable” and in one memorable put-down “the Atlas Shrugged of Computer Science”.

In a sense, I’m not surprised by this. Even when the book came out, it seemed it had as many detractors as it had supporters. What’s more, even when it was being written, there was a small but impassioned contingent of reviewers at the time that argued that the book needed to be completely rewritten before it was ever published. But every book has issues — and Design Patterns is not immune to the fact that any work is at best an imperfect reflection of the ideas of the authors.

However, what to my mind is the most difficult part to understand is that regardless of comments on the format, style, or even font choice of the work, I’ve never quite understood is how anyone could reject the ideas contained within it as being either trivial, useless, or banal. But then again, that’s where my experience as a programmer, and an author, differs from what I have found over the last twenty-five years to be the most common case.

So let’s start with the beginning. I first learned how to program in the same way many people of my generation did — we learned BASIC programming on a home computer. For me, it was a succession of them that I encountered at school, at friends houses, and eventually that I owned. During my high school years I learned to program on the Apple II in Integer and Applesoft BASIC, on the VIC-20, on the TI-99/4A, and on the Sinclair TX1000. Programming on the Sinclair, with only 4K and it’s bizarre shift-key combinations to create BASIC keywords was very different experience from programming on the relatively spacious 48K that the Apple II possessed and it’s wonderfully tactile keyboard that required you to fully type out all of your commands. As a result, I did a lot more low-level development with PEEK and POKE on the Sinclair than I did on the Apple, where the wonderful floating-point capabilities of Applesoft BASIC gave me free reign for my imagination. So nearly from the beginning, I learned that your available environment and language formed the way you thought about a problem.

Besides that, the way I learned to program was pretty typical for the time — I learned by writing programs. Now, there would be some programs that you could read — particularly those published in magazines where you had to type them in to run them (no internet!) and in the few that were available freely and circulated on BBS, disk and tape (long before “open source” became a thing), but in general, you learned how to solve problems by solving problems.

When I went to University for my degree, I found that this was still the predominant paradigm for learning the trickier bits of programming and of computer science. For example, when I took a class on operating systems, we would read about a concept, like a semaphore, or a file system, and then be expected to be able to implement the concept. There might be a few simple examples in the text to help get you over the hump as to how the implementation would work, but more often than not these were in a type of pseudocode that you would have to mentally translate into C or C++.

When I graduated from University and went to work as a C++ and C programmer, nothing much changed from the way I had learned things in college. Every programming problem began with searching out the documentation of the relevant libraries, then sitting down and plotting out how to write the solution from scratch. That was just the way I thought development should be, and always would be.

But then, in the winter of 1989, I had an unusual opportunity come my way that changed the way I thought about programming by changing the way I thought about how to solve problems. That opportunity was when I was introduced to Smalltalk (particularly the Smalltalk/V PM version from Digitalk). Writing programs in Smalltalk is such a departure from traditional ways of developing that it took me a long time to fully wrap my head around it. I’ve found that people that try to learn it end up in one of two extremes — either it becomes their all-time favorite development language and environment, or they hate it with a passion bordering on mania.

In order to understand why this is true, you need to understand some things that were, at the time completely radical about Smalltalk, and that even to this day, have not fully been replicated in any other development language or environment.

1. Smalltalk does not have files where you put your source code. Now, in a sense that’s a lie, because there IS a single file that contains your source code, but it’s not organized the way you think it might be. Instead of a single file for each module or class, all of the early Smalltalk implementations feature a single large, rolling log file, called the change log, that contains the new source code that you’ve added to the system. As you add a new method, or modify a method, it gets added on the end of the change file.
2. Smalltalk doesn’t have a file-based compilation system — instead, every change you make to any method or class definition in that changes file is instantly compiled by an incremental compiler and added into a single, large, in-memory image of the entire Smalltalk system.
3. Smalltalk was (and is) completely and totally Object-oriented. It was object-oriented in a way that Java, Python or C++ (or newer languages) cannot even match — in that even Integers are objects — and what’s more, you can extend the behavior of an Integer by adding new methods to it!
4. Smalltalk had this great concept called Workspaces that allowed you to highlight and run little snippets of code of any length — it would just compile and run them instantly. People would also mix and match documentation and code snippets within a Workspace — this is the basic idea behind Jupyter notebooks today. This was awesome for just trying something out to see what it did — part of a process of learning by exploration.

But that last observation is merely the tip of the iceberg on what I think was one of the most revolutionary things about Smalltalk that changed the way I develop — and influenced the way that everyone who was exposed to Smalltalk in those days thinks about development. The remainder of that iceberg is this — the entire system, from the code implementing the editors you developed in, to the basic system libraries like the Integer and Collection classes, up through the Smalltalk compiler classes themselves were available in that Image (from a single base, unchanging “sources” file) for you to read!

Squeak Smalltalk showing 4-pane browser and workspace

It was this feature that changed the way I thought about developing — and that change only came about by how I was taught to use Smalltalk. I had the wonderful experience of being taught by two of the true masters of the language — Sam Adams and Ken Auer, who at the time were both with Knowledge Systems Corporation, one of the first Smalltalk consulting companies. The simple lesson they taught me was this:

Don’t start any new programming task from scratch — always look in the Smalltalk image first to see what’s available and what has been already done before you start building anything new.

To me, this was a revelation. It upended everything I had ever learned to this point about programming. But as I’ve thought back over my career and my life, I realized that this really isn’t that unusual. Think back to how you first learned to read (in whatever language that was). Your elementary school teachers didn’t expect you to write a novel as soon as you mastered the alphabet. No, what they probably did (I know mine did) was to first give you the opportunity to read at length before you were expected to be able to write something comparable. As I look back to my elementary school days, I remember writing a lot of book reports — which are really just shorter summaries of larger works — but the point is, we ended up reading probably 10 times more than we actually wrote.

As I moved into high school and college, the lengths of the essays, reports and other things I was expected to write grew, but that same rough 10–1 ratio of reading to writing remained approximately the same, or even increased as I moved on to university and especially graduate school (where the ratio may have been 50–1).

At this point, some of my Gen Z and Millenial friends will be losing interest as they start muttering about Boomers because of the following thought

That’s just Boomertalk. We have this thing called the “Internet” now, and especially this thing called “Stack Overflow”

(I’m Gen X, thank you — and as such my natural Gen X cynicism informs me that you forgot we exist, didn’t you!) But the argument I want to make is that using Stack Overflow is not the same as what I’m referring to — and that the experience was quite different. When you use Stack Overflow, or a search engine like Google, what you’re doing is narrowing in on a particular way of solving a problem in the specific way you describe it. That’s because you’re searching by keyword — what you’re missing is context — and the ability to see a solution in the context in which it was written. What you’re also missing is the serendipity of coming across a better way of thinking about a problem than you may have had in mind when you began the search. You’re also missing the sheer joy of just chasing rabbits through the source code as you sought to understand how a particular section of the code worked, which led you to another rabbit, and another.

And that is where we work our way back to the original topic of this blog, which was the book Design Patterns. I had been a Smalltalk programmer for about five years when the book first came out — in fact, I first encountered the patterns in a xeroxed pre-print of part of the book before the book was officially released. Outside of the context of the book as a whole, they didn’t make much of an impression on me. But then, once the book was released, I took a copy with me on a long car ride from Raleigh to Atlanta (about six hours) and read it on the way. This time, it clicked.

So let’s think about how the way I had been developing for the last several years had molded my thinking — I would always browse through the Smalltalk source code for ideas and inspiration whenever I was solving a programming problem. That means I had read through most, if not all of the Smalltalk/V and Smalltalk-80 (VisualWorks) source code several times, and had been using things I picked up from that source code in the projects I was working on.

What Design Patterns did was to suddenly give me a vocabulary for many (not all, but a lot) of the things that I had already encountered in reading all of that source code. I remember coming across Observer and thinking — “OK, I’ve not only seen this, but I’ve used this a couple of hundred times because you can’t write a GUI in VisualWorks Smalltalk without it.” Then I came across Mediator — and realized I had seen that inside the GUI source code of both Smalltalk versions, and as I read more I kept experiencing the same sense of deja vu over, and over, and over again.

The best analogy I can think of was as if I had been reading and writing fiction, but I didn’t have the vocabulary to describe what I was doing — I didn’t know what to call a Character, or a Scene, or a Plot Device, but I had used all of them on my own work and had encountered them in fiction I had read.

But the thing that it really did was to open my mind to the possibility that those 23 patterns weren’t all of the recurring themes that I had seen. Today, in fiction (particularly the anime and sci-fi genres) we call these Tropes, and there are entire websites devoted to them, like TVTropes, where you can learn about common themes like The Mad Scientist’s Beautiful Daughter and The Sorting Algorithm of Evil (read them both — you’ll recognize them). But the idea is much older — Joseph Campbell famously declared that there is a single “monomyth” called The Hero’s Journey that can capture the essence of every epic story from The Odyssey through Star Wars.

And that wraps me back around to the original thesis of this blog. People pick up Design Patterns and expect to read it as literature, but you can’t do that — it’s not a story. You shouldn’t read it that way. It’s more like a textbook about comparative literature. At its best it teaches you something about the art of writing code, much like a comparative literature textbook would teach you something about the art of writing fiction. It will not teach you programming — that is the problem with the way many people started applying the patterns, which resulted in unbelievable overuse of the 23 patterns where they applied the “Everything looks like a nail when you have a hammer” antipattern.

Instead, you should just think of the patterns as 23 terms that can be useful for describing particular tropes that are most common in object-oriented programming. It can help you recognize those tropes, and even give you some indication as to when they might be helpful — but most importantly it gives you a vocabulary to talk to others about those tropes.

Now, there is one more thing I want to bring in about this — probably the most common thing I hear people dismiss the patterns as are “well, these are just things that are language features in X, Y or Z, so you don’t need them in that language”. Nothing could be farther from the truth.

You see, the first language that this particular trope was applied to was Smalltalk! When the book came out, the Smalltalk message boards (remember — this was 1996!) were flooded with messages from Smalltalk developers saying that these patterns were only needed because C++ (which was the only other OO language widely used at the time) was so deficient. This was despite the fact that about half of the examples in Design Patterns were originally written in Smalltalk.

But this is where I was able to help out. To make a long story short, Sherman Alpert, Bobby Woolf and I became co-authors of The Design Patterns Smalltalk Companion — the very first official follow-on book to Design Patterns. We showed that the ideas, the tropes, are universal. You can implement them more simply in some languages than others, but the fact that the ideas remain the same across the boundaries of language and environment is the important thing.

Which brings me to the last point I want to make — if you don’t understand the patterns, and can’t make heads or tails of them, maybe one thing to do is — read more code. If you’ve primarily read your own code, and you’ve not read widely in the code of others, odds are good that you’ve not encountered any of the patterns, much like you’d never encounter The Sorting Algorithm of Evil if you never watched or read any science fiction or played online MMORPGs. But the more you watch and read, the more likely you are to encounter that trope.

Another thing to do is to read particular types of code — let’s be honest — not all code is created equally. In my job I do a lot of code review of client code, mostly in Java, and some of it is particularly terrible. In fact, there’s one problem I see that is endemic. That’s where the code is “supposedly” object-oriented, but in fact, it doesn’t take advantage of any of the features of object orientation (no inheritance, no method overrides, and few if any uses of type substitution). In particular I see tons of code where there are these static “data” objects (a misunderstanding of another pattern from Martin Fowler, called the Data Access Object) and these “processing” objects that are, for the most part, just bags of procedures that operate on the data objects. This is object-orientation in name only, and not in practice. If the only code you ever encounter looks like that, then I again understand why you may never have encountered any of the patterns from Design Patterns. I also feel terrible for you, because reading code like that is painful and wearing. Unfortunately, I think that this style of development is encouraged by the very tools we use to develop them — editors that focus on the level of a file will, unfortunately, never encourage you think about what lies beyond the context of the file — yet another thing that’s been lost as file-oriented languages and development environments took over.

Despite that potential pain, in any case, reading more code can never be a bad thing. If you don’t have any good code to read in your work, then I encourage you to turn to open source projects — many of us simply consume open-source code and use the public API’s without ever diving down into understanding how the internals are written — doing that will give you an opportunity to see how many different people code, and to compare many different styles of development. Even if you don’t see the 23 patterns from Design Patterns, you will learn to identify and pick up other tropes that will, I guarantee, improve your programming in whatever language you develop in. And, if you want to help others out with a vocabulary to describe those tropes, then you can do what the authors of Design Patterns did — write the trope down so that others can identify it. That’s how everyone will benefit — you from learning from the experiences of others, and everyone else from being able to adopt your vocabulary when they re-encounter that particular concept.

BTW, if you want to try Smalltalk yourself, Squeak Smalltalk provides a very faithful open-source implementation of Smalltalk and is available on most platforms.

--

--

Kyle Gene Brown
The Startup

IBM Fellow, CTO for Cloud Architecture for the IBM Garage, author and blogger