If I could recommend only a single book to (Agile) developers that want to improve their skills, it would be ‘Clean Code’ by Robert C. Martin (lovingly called Uncle Bob by the community). I’ve certainly read my share of books on writing code, but few books have had such a profound influence on how I write and think about code. In fact, I’ve made this book a pretty much mandatory read at NowOnline. If there’s any book out there that tells you how to avoid the buildup of technical debt, this book is it.
How come? Well, most books on software development focus on how to use a specific language (C#, Java, etc) to write software. They’re like Dutch study books that explain how to write ‘good morning’ or ‘is this crocodile edible?’. These books are about grammar and spelling. Although you will be able to write a grammatically correct e-mail with few spelling mistakes after a few months of practice, you’re still far away from writing an eloquent, convincing essay on some topic. This is where style comes in; the skill to use language correctly to convey intent and meaning. If we go back to software development, the aforementioned books are mostly about the spelling and grammar of a programming language. ‘Clean Code’ - on the other hand - is all about style. In fact, ‘Clean Code’ is not written specifically for any language, like C# or Java. Although most of it’s examples are in Java, the concepts in the book transcend any specific language.
But why is this book so important for (Agile) developers? The first chapter of ‘Clean Code’ begins with this cartoon:
For me, This cartoon pretty much sums up the point of the book; high-quality code is easier to understand than low-quality code. Although both will have their share of ‘WTF!?’ moments, high-quality code will have dramatically less. To make the point, Martin describes a familiar pattern that I’ve often witnessed in codebases. Initially, the codebase is ok and everyone pretty much understands what’s going on. But as time progresses, it transforms into an ever increasing mass of knots, twists and tangles. Because there’s never time to write good code or clean up existing code, productivity decreases as complexity increases. Eventually, productivity drops to such a low that developers start rooting for a complete rewrite of the codebase. Although this remedies the problems for a while (at great cost for the business), the cycle usually simply repeats. Martin uses this familiar pattern to describe the process of ‘code rot’; the apparently inevitable buildup of technical debt in a codebase. And as with all debt, you have to pay interest. In this case in the form of loss of productivity, and probably stability and enjoyability as well.
In his book, Martin describes a number of key principles and strategies that help developers prevent code rot. First and foremost is ‘The Boy Scout Rule’: “leave the campground cleaner than you found it”. This principle calls on developers to prevent and remove code rot wherever they see it happening. If everyone in a team touches up the code they’re working on (even if it was written by someone else), the entire codebase will improve over time. Martin is not referring to complete rewrites, but to simple touch ups like improving naming, removing useless comments or splitting up large blocks of code into classes or methods.
The remaining chapters of the book are dedicated to strategies to avoid code rot, clustered around topics like naming, class structure, exception handling, unit testing, arguments, comments and many more. Of course you should just buy the book and read it, but let me share some of my favorites:
- Don’t use comments unless they are absolutely necessary. I can’t tell you how often I’ve seen (or written) the comment ‘Iterate through the list and find the record’ above a ‘for each’ loop. The problem with comments is that they have no compile-time check and tend to be forgotten. It’s very easy to change your code but forget about the comments. Over time this will greatly confuse developers as the code they’re working on does not match the comments. A much better alternative is to make sure that your classes, methods and variables describe their purpose (not ‘x’ or ‘i’). It’s better to name a method ‘SplitTimecardsByDay’ instead of ‘Process’ with a comment that explains that this method is splitting time cards by day;
- Prefer many small classes over several large ones. As a guideline, Martin uses what he calls the ‘Single Responsibility Principle’: “Every class or module should have one responsibility - one reason for change”. The upside of this approach is that you have many small classes, each of which is easy to understand or change. The same applies to methods and functions, by the way;
- Don’t return null from methods. Martin makes a point of not returning null from methods. At first, this seemed impractical to me. But there’s a good point to be made here. Whenever methods start returning null, you have to check for nulls in the calling code. If you ever forget this, you run the risk of a null reference exception. In most cases, code can be rewritten to not return null. Take a method that returns a list of products. If there are no products, don’t return null (as I often used to do). Just return an empty list;
- Methods with boolean parameters indicate bad design. Whenever you have methods that have boolean parameters, that’s a strong indicator of bad design. Usually, a boolean parameter is supposed to toggle between two modes of operation. Take a method called ‘Insert(object, bool commit)’. This method always inserts objects into a transaction, but it only commits the transaction when the parameter is ‘True’. For understandability and clarity, this method should be split into two versions, like ‘InsertAndCommit(object)’ and ‘Insert(object)’. This approach is self-documenting;
- Don’t comment out code; remove it. The problem here is that it’s very tempting never to remove old code, perhaps out of fear to lose it. Other developers may not understand why code was commented out, and leave it there. This will polute the codebase significantly. Instead of commenting out your code, just remove it. You have version control systems for keeping track of older versions of your code and what you changed. Make use of it;
- When writing unit tests, test a single concept per test. This is less specific than the ‘one unit test per code path’-approach that I often used. If you have a method that finds gaps in date ranges, just test all possible scenarios in a single unit tests instead of writing separate unit tests per codepath/scenario. This is a lot easier to understand for other developers and you have to spend less time maintaining thousands of small unit tests;
The book finishes with an interesting chapter on what Martin calls ‘code smells’. He uses these smells as heuristics to determine if the codebase is rotting. An example of a code smell is ‘too many arguments’. If a method has a large number of arguments, this is an indicator for bad design. The same goes for the ‘obscured intent’ smell. If methods are very dense and hard to decipher, they should be rewritten.
As you can see, I’m very excited about this book. If I have to name a downside, it is that it is mostly written from a Java perspective. Although 90% of the book is perfectly applicable for .NET developers, the remaining 10% is too specific (like JUnit or some Java code listings). Thankfully, this is not a big issue as the book is concerned with style (which is language-independent) and not with grammar or spelling. So, if you are a developer and you want to improve your skills, make sure to read this book. It will help you distinguish good code from bad code and avoid the seemingly inevitable build up of technical debt.