How to teach art (or at least software design)
There are many things that are straightforward to teach. Even some stuff that people consider “a talent”. Drawing technique, for example. You can learn how to draw: buy a couple books or go to classes to learn some theory, then fill 200 pages of drawings. Teaching art, on the other hand, is very difficult: you can draw wonderfully well, but having an idea for a good drawing and executing it well are whole different problems.
In writing this post I had to ask myself: how to teach software design? What have I learned in all these years that could be distilled into a more or less concrete form? At first I was at a loss. It’s not easy to translate it to words!
Then I started to think about what all my projects have in common. And they do have a lot in common, it turns out.
I start my designs with a simple, clean and clear spec. You can’t write software well if you don’t have a clear idea of the what it has to do, at least in its first version! Your spec is good if you can show it to somebody else and they can write the program for you just the way you imagined it. In big projects with a lot of people, detail is never too much in a spec.
Scenarios: while TDD can be tricky to do sometimes, always think about tests and scenarios before you start building. This is actually part of the first item, because if you see a problem in a certain scenario you may have to change everything. But think about the edge cases, about what happens if things go wrong. See below on tests.
At this point you can design your classes and database, if you have one. My class designs follow a very definite pattern:
- There are usually one or two classes to manage the software. They are responsible for initialization and for calling other classes (the main loop).
- There are a few (abstract, usually) base classes; as few as possible, because it makes it much easier to understand the structure of the program. Our web applications have 4 base classes that probably encompass 90% of the code. Our sophisticated 3D engine has only 4 abstract base classes, but they give it great flexibility — the design was never modified since its inception, even though the number of features have been growing constantly and we are doing things that were not imagined at first. Even a large change made when the code was already mature (supporting multiple render backends) did not change the design of the code at all. A good design may suffer modifications over time, but the API will be constant. All (or at least most) changes will be internal.
- Databases should be simple and think about future changes (because they will change!). Think a lot about the primary keys and about relationships (1:n for ever? or perhaps it can become n:m someday?). We ended up abstracting the database in our web applications. The framework does everything we need. There are no manual SELECTs or INSERTs.
Have a powerful Log class. This is something I’ve written about before, in my post about the art of debugging. This is of great help: it makes me think about debugging from the start of the project. If it’s a graphic software, ways to dump screenshots and images at any point are fundamental.
Tests tests tests. If you are writing a function, write the test first or at the same time. Make sure inputs are tested for valid and invalid values. Get 100% coverage and if possible make someone else do the test, because they will see things you are too close to see now.