In teaching software engineering at Curtin Uni, we have long had a 2nd-year unit that dealt principally with the grandiosely-named Unified Modelling Language (UML), that diagrammatic language that promised to be software’s answer to the technical drawings of other engineering disciplines. I recall it as a student, when the various UML notations (each one allowing you to articulate a particular aspect of the software you’re designing) were described at a rate of approximately one per lecture (with one lecture per week). At the time, not knowing any different, this seemed a logical approach to useful design material.
As a mathematical system, UML draws you in. Pure abstract curiosity drives you to understand what its constructs are for and how they relate to one another. It has a kind of internal elegance, if you know where to look, where a few core concepts can be used to articulate systems of great complexity with great subtlety and flexibility. Its creators made mammoth efforts to anticipate all the situations they wanted to be able model with a diagrammatic (or semi-diagrammatic) language, and provided the ultimate multi-purpose tool for the job.
UML positioned itself throughout the “software life cycle” (another curious term) but particularly in the design phase. It was supposed to be the vocabulary in which you expressed the bulk of your design work. You crafted UML diagrams from a requirements specification, then, once the UML “model” was complete, it became a blueprint with which you could hammer out the code in trivial time.
There are probably quite a few ways to explain why (in many cases or even most cases) this doesn’t really work. UML has a role in SE, but not one quite as celebrated as its evangelists might have thought. It is a vocabulary, one used to communicate complex, abstract ideas quickly. But not completely.
UML serves a useful role as an informal language, not a specification language, and the difference is completeness. UML can be complete — that was the whole idea according to some people — but practically speaking you don’t usually want it to be so. At the day-to-day level of human communication, you don’t need to be complete — you merely say as much as you need to say before the other person “gets it”. We trade off completeness for efficiency. When you want someone to understand what you’re thinking, you estimate the differences between your understanding and their understanding, and you communicate only those differences, not the sum total of your thoughts. In UML, you would draw only those entities and relationships that are relevant to the immediate issue at hand. (We take a very different approach when writing code and specifications, in which all details must be carefully articulated.)
In the second half of 2012, 11 years after I took the UML unit as a student, I was asked to teach it. The unit had evolved slightly in the way that units do, but the approach was broadly the same. Over the years, it had occasionally attracted the nickname “Diagrams 252”. People knew that the emphasis of the unit was misplaced. Now that I was on the other side of the educational fence, I came to see the problem in our teaching approach — not just in what we were telling students about UML, but in what we were failing to tell them about software design more generally.
UML is a vocabulary, formal or informal, but so what? Software design isn’t about syntax. It’s about ideas. What should you actually do with all those notations? Where was the actual design? Where was the engineering?
In many an SE textbook, there is no shortage of advice on what you shouldn’t do in software engineering. There are rules about how not to use inheritance, what language constructs you should avoid at all costs, what kinds of coupling are unacceptable, etc. There is usually not a great deal of advice about what you should or even can do.
Exposing students only to a set of rules and notations, as we did previously, is really just fiddling around the edges of SE education. The knowledge that creates a competent software engineer is not UML or design checklists. Rather, a competent software engineer first and foremost needs a mental toolbox of design options — a large collection of adaptable solutions to small problems, stored in one’s brain. These are not memorised in the way that students often try to memorise bullet point lists. They are not catalogued in a neat little taxonomy as might appear in a traditional textbook. They are haphazard fragments of possible design approaches — the result of seeing how design could be done in various ways. The technical term from cognitive science, as I understand it, is “plan”. Plans are building blocks for the creative and investigative processes.
One can acquire such a mental toolbox through sheer brutal personal experience — that’s how they did it in the old days, of course. But education is supposed to short-circuit that, or else what’s the point?
In teaching the unit for a second time in 2013, I made some significant changes, one of which was to teach software design patterns1. It’s easy to make the argument for teaching patterns, because they have that aura of academic respectability that accompanies things Published by Reputable Authors. Patterns, of course, are broadly defined as reusable solutions to common problems. They are implemented independently by different engineers in different contexts, and later discovered for what they are. Familiar?
The logic here is more convoluted than it first appears. A pattern is not a plan — not exactly. Each pattern is a named phenomenon (the “Strategy Pattern”, “Observer Pattern”, “Composite Pattern”, etc.), analysed, documented with UML and catalogued. The widely-known seminal list of software patterns was laid down in a book by the “Gang of Four”. So, for educational purposes, patterns sound a lot like a giant list of bullet points that students would simply try to memorise.
But patterns are important for educational purposes because (unlike UML itself or the usual what-not-to-do list of SE design rules) they show you what you can do. Patterns are solutions known to work well, assuming you understand what each one is for. Moreover, it has been my hope that teaching patterns also reveals some of the more fundamental ideas about software design. That is, even if you can’t remember a single actual pattern after taking the unit, you might nonetheless remember some interesting things you can do with polymorphism. Hopefully some knowledge underlying those patterns will have rubbed off, and given you the beginnings of that mental toolbox.
- There had always been a single lecture on patterns anyway, but it didn’t cover much material. [↩]