BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Articles Book Review: Clean Code: A Handbook of Agile Software Craftsmanship

Book Review: Clean Code: A Handbook of Agile Software Craftsmanship

Leia em Português

Bookmarks

As programmers, our first priority is creating code that works. Unfortunately, code that just "works" just isn't good enough. To provide real, lasting value, code has to be clean. In "Clean Code: A Handbook of Agile Software Craftsmanship", Robert C. Martin makes use of extensive examples and case studies to hone our ability to identifying code that has room for improvement, and provides a multitude of techniques to clean up code, just a little, every time we touch it.

What is Clean Code?

In Chapter 1, Martin convincingly argues that clean code is not just desirable -- it is necessary. Without clean code, development slows over time. Eventually, it hits a point of such uncertainty, pain, and frustration that it seems easier to just start over and rewrite the whole thing from scratch. Of course, if the rewrite isn't done any more cleanly than the original, the problem persists, and in a few years the team ends up where it started!

Everyone defines clean code a little differently. Martin includes descriptions of clean code by such notable developers as Bjarne Stroustrup, Grady Booch, "Big" Dave Thomas, Michael Feathers, Ron Jeffries, and Ward Cunningham. Although they all emphasize different aspects of clean code, there are a few emerging themes: simplicity, lack of duplication, readability, elegance. Code that has these qualities is maintainable, breaking the slowdown/rewrite cycle, and providing true, lasting value.

The Devil's in the Details

Chapters 2 through 6 cover low-level coding decisions: picking meaningful names, defining readable and elegant functions, writing useful comments (and avoid bad ones), formatting your code to improve readability and clarity, and choosing when to use smart objects and when to use dumb data structures.

Martin effectively intermixes theory and explanation with concrete coding examples that illustrate his points. These back-and-forth sections convey a lot of wisdom, but are too lengthy to summarize or reproduce here.

Interspersed with these explanations are lots of concise, thought-provoking gems like these (taken from Chapter 2 through 4):

"The problem isn't the simplicity of the code but the implicity of the code: the degree to which the context is not explicit in the code itself."

"Our goal, as authors, is to make our code as easy as possible to understand. We want our code to be a quick skim, not an intense study. We want to use the popular paperback model whereby the author is responsible for making himself clear and not the academic model where it is the scholar's job to dig the meaning out of the paper."

"The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that."

"Don't be afraid to make a name long. A long descriptive name is better than a short enigmatic name. A long descriptive name is better than a long descriptive comment."

"It is hard to overestimate the value of good names. Remember Ward's principle: you know you are working on clean code when each routine turns out to be pretty much what you expected. Half the battle... is choosing good names for small functions that do one thing. The smaller and more focused a function is, the easier it is to choose a descriptive name."

"Side effects are lies. Your function promises to do one thing, but it also does other hidden things."

"The art of programming is, and has always been, the art of language design. Master programmers think of systems as stories to be told rather than programs to be written. They use the facilities of their chosen programming language to construct a much richer and more expressive language that can be used to tell that story."

These chapters stitch together a cohesive, consistent philosophy of clean code, and provide the pragmatic advice needed to follow that philosophy in practice.

Higher Level Concepts

Chapters 7 and 8 cover error handling and interfacing with third-party code and systems. I found Chapter 7 (written by Michael Feathers) particularly valuable. Error handling is one of those areas that is seldom done well, and is usually skirted around in literature about software design. Feathers delivers a practical approach to keeping error handling separate from the main flow, and keeping both clean and readable in the process.

Chapter 9 covers Unit Tests: why keeping them clean is as important as keeping your production code clean, and how to keep your tests clean. ("Three things. Readability, readability, readability.") The chapter is brief, but contains lots of examples of good and bad tests to illustrate Martin's points.

Chapters 10, 11, and 12 cover higher-level design concepts: classes, systems, and emergent design. Chapter 10 focuses heavily on The Single Responsibility Principle (SRP), a concept from Martin's previous work, Agile Software Development: Principles, Patterns, and Practices. The treatment here is less in-depth, but a good starting point. Chapter 11 talks about clean code in the context of system-level techniques such as Dependency Injection and Aspect-Oriented Programming. Chapter 12 reminds us to rely on tests and refactoring to drive our high-level design as well as our low-level decisions.

Chapter 13 covers Concurrency. It doesn't go into great depth, and feels a little bolted-on, but does contain a good deal of solid advice.

The Case Studies

In chapters 14, 15, and 16, Martin ties the ideas from the previous chapters together. In each chapter, Martin starts with a real example of not-great, not-terrible code, and guides us through the process of refactoring it into something much cleaner.

The code examples are not trivial, but not unnecessarily complicated either. They are complex enough to not feel like "toy" examples, but straightforward enough to understand after some careful code reading. They provide the necessary environment in which to develop a more in-depth understanding of how to apply the concepts presented earlier in the book.

It's one thing to read that refactoring should be done in "baby steps". It's entirely another thing to see a concrete example of how an experienced agile developer picks which baby steps to take. These chapters add a lot of value to this book. This is where everything you've read so far will really begin to sink in and acquire practical relevance. Reading the case studies reminded me of pairing with a really smart, experienced developer -- a testament to the clarity of Martin's writing.

Smells and Heuristics

Chapter 17 wraps up the book with a list of "code smells" and heuristics. It condenses the ideas of the book into a very direct, problem-centric format, ideal for review. And at 29 pages, it makes a nice, concise reference.

Conclusion

This book belongs on the bookshelf of every developer who cares passionately about quality and craftsmanship. Less experienced developers will find it more valuable, and more of a slow read – this book is packed with good advice, without much "filler". Martin uses plenty of examples, and uses clear, concise language, so although inexperienced developers will find it slow going, they are unlikely to feel lost.

Experienced developers would do well to give it a read as well. It will reinforce those things that you already know you should be doing (but which you don't always do), remind you of a few things you've forgotten, and teach you a few new things as well. Most of all, it will give you a fresh perspective on all those seemingly mundane decisions you make hundreds of times a day.

Rate this Article

Adoption
Style

BT