c4 conference, Buzz Andersen said in his talk Apple to Indie:
Professional code is ugly
If I understood him correctly, as he started to work at Apple, he was expecting the code there to be beautiful. Paraphrasing: These guys are the keepers of the APIs. The code they write has to be beautiful!
If you are reading this, you probably believe that you, too, can write beautiful (or at least, aesthetically pleasing) code. And you are probably correct.
Your code probably starts out as beautiful, or as beautiful as you can make it. You are the only one working on it. It is your design, your vision. You are proud of it. This is good.
If you are part of a team, your code probably gets in a common source code repository. Then your colleagues start to work on it, because a of an edge case you had not anticipated. They are motivated by the best intentions, but unfortunately, smallest common denominator sets in. “Monkey-see, monkey-do”-type code cannot lead to beautiful code: it has to be designed.
Design is hard
Design is hard. It’s also hard to maintain as you are fighting barbarians at the gate: deadlines, colleagues, new features, even bugs.
Good design is obvious, especially in hindsight. It can be enforced by the design patterns, the unit tests, the compiler macros or the C++ templates.
Your code also has to interface with other code, be it the operating system, or the Perl script that talks to your printer-plotter over a RS-232 connection.
Maybe you control the interface, and can keep the design. Usually, you don’t. And then you’re stuck interfacing with ugly code, which tends to infect your code by imposing its own constraints. Lowest common denominator again.
No code can handle everything. There are some extreme cases where requirements don’t change, and the person/team in charge of those requirement know everything in advance. If that is the case, congratulations, you can use the waterfall development model. The rest of us have to deal with change.
When a change in requirements happens, maybe your design can accomodate it, maybe not. Usually, you have to refactor.
You may have some budget for refactoring? Well-planned. But remember, the ultimate goal of refactoring is to ensure that your code performs in the same way as before. This is a win for you, and future versions of your product, but does nothing for the current customer.
The “business case” for refactoring tends to diminish with time. As deadlines loom, those two months that you had planned to rewrite the print engine will fly by, and if you are not 80% done in 20% of the time, you should seriously think about how important this is. Because if you are committing your whole team for two months, that’s a lot of (wo)manpower. And if you take a subset of the team, they might feel like they are left behind, working on something that has no user-visible impact while someone else works on a whiz-bang shiny feature.
Refactoring is not undertaken lightly. There is a very distinct possibility that your refactoring will break the app. One way to alleviate those concerns is to use unit tests. When automated (and run as often as possible, for instance on every check-in), they can increase your confidence that you did not break anything important by re-writing a critical subsection of your code.
Test-driven development (TDD)
I love TDD. I love writing a test for a bug, exposing it and fixing the code to make the test pass. I also love to develop “framework-level” features, for example File I/O, using tests to create, open, parse, and save files in the new disk or network format.
However, test-driven development leads to utilitarian code. Literally, “write enough code to cover the unit tests, and then no more.”. While some interesting designs may arise from this, more often than not the code is textbook-like, driven by the requirements imposed by the tests.
Any of these features can lead to ugly code:
- Several people working on it
- Changing requirements
- Interfacing to non-beautiful code
- Test-driven code
I would be hard-pressed to find some code that does not have at least one of these characteristics.
So I agree with Buzz. Professional code is ugly. When you see beautiful code (and you will know when you see it), treat it like a endangered species. Protect it, nourish it, make it regain some strength. Educate others about it. Because one day you will look at it again and think proudly: this is beautiful code.