Clean Code - A Handbook of Agile Software Craftsmanship
Buy it now
One Minute Bottom Line
|If you are a professional developer, or aspire to being one, then you owe it to yourself, your team, and your clients to read this book and take it to heart.
In “Clean Code”, author Robert C. Martin (fondly known to many as “Uncle Bob”) not only shows you what clean code looks like and why it is important, but how to take existing code and make it cleaner. This last part is invaluable because you get to see step by step improvement, which makes doing it with your own code much easier.
The chapters of “Clean Code” are grouped into three parts. As it says in the introduction, part one “describes the principles, patterns and practices of writing clean code.” Part two contains “several case studies” showing how to apply the knowledge from part one to actual working code. Part three (which is a single chapter) lists the “heuristics and smells gathered while creating the case studies.”
While the author warns us that there will be lots of code to read and that there’s hard work ahead – I have to say that I found it all worthwhile and I think you will too.
Chapter 1: Clean Code talks a little about why a book about code is important; what constitutes bad code, and the costs of having bad code. Things get a little uncomfortable as the reason that bad code exists is pointed out. We have bad code because we wrote it, or because we aren’t cleaning it up.
Now that we know what bad code is, the next question is “What is clean code?” Uncle Bob asked a number of well-known people that question and includes responses from folks like Bjarne Stroustrup, Grady Booch, Dave Thomas (Pragmatic Programmer, not Wendy’s dad), Micheal Feathers, Ron Jeffries, and Ward Cunningham.
This section ends with Mr. Martin’s own answer, and then points out a couple of important things. First, as programmers we are authors – other programmers read our work and we have the responsibility for communicating the intent of our code to them. Second, it is important to improve the code every time we change it, in order to prevent code rot.
Chapter 2: Meaningful Names builds on the idea of programmers as authors and suggests that when we name things (classes, methods, variables, even ear and jar files) it is important to use a name that communicates clearly what the thing being named is or does. This chapter is full of simple suggestions to help you develop better naming skills.
Chapter 3: Functions focuses on ways to improve the functions you write. It includes ideas like keeping your functions short and focused on doing just one thing, the need to keep the number of arguments small, and why it’s good to have separate commands (modifying the object’s state) and query (returning a value) functions instead of mixing both types of behavior in a single function.
Chapter 4: Comments takes the view that in many cases, comments are a band-aid over poorly written code, and that it would be better to refactor the code and make it readable than to write a comment to explain what it is doing.
However, there are Good comments and reasons for writing them, and the author points this out; legal notices (like copyright info), informative comments (explaining what a regular expression will match on), using a “ToDo” as a reminder of something that should be fixed later, and the like.
There’s also a long list (with examples) of comments to avoid. For example, misleading comments (“this should never happen” in a catch block), comments instead of a well named method or variable (“count represents the number of available database connections”), and the long list of changes (who made them, when, and why) found at the top of far too many class files - use your revision control comments for that.
Chapter 5: Formatting points out that a well written piece of code should be readable. Formatting your code in a consistent manner is a great first step.Vertical alignment makes it easier for you to see blocks of code. Remember to use blank lines to visually group related blocks of code, making it obvious that “these lines” work together to do one thing while “those lines” do something else.
Whitespace may mean nothing to the compiler, but it can make a world of difference in how well a human understands what your code does.
Chapter 6: Objects and Data Structures points out that, according to good Object-Oriented Design principles, Objects are supposed to hide their data and provide methods to modify it or take actions based on it, while Data Structures offer access to their data but no way to manipulate it. So then what’s a JavaBean? It’s a class with private data elements (like an Object), but for each element there is a public method providing access to it. So it looks like an Object but acts like a Data Structure.
The chapter continues with a nice explanation of the Law of Demeter and examples showing how to apply it, then ends with a look at Data Transfer Objects and Active Records
Chapter 7: Error Handling shows how to write “real code” that others can read and understand. Real code means it handles error conditions - unlike most of the example code you see in presentations or books, where there’s nary an exception thrown and try-catch-finally statements are left out to conserve space, or because including them would make the code confusing to read.
Chapter 8: Boundaries is about making a clear demarkation between code we control (the code we write) and code we don’t (like third party libraries or code from another team) so that we can insulate our code from errors and changes. There’s a nice bit on using unit tests to learn how to use libraries, and that the same tests can be used to verify that a newer version still works with our code. The chapter wraps up with an short explanation showing how having clean boundaries lets us write code that use libraries even if they don’t exist yet.
Chapter 9: Unit Tests gives us a quick look at this important topic. There’s a brief description of Test Driven Development followed by a great explanation on why you should write your test code using the same standards as the code intended for production. The rest of the chapter shows some of the important things to do to make sure you get the most out of your unit tests.
Chapter 10: Classes is about creating well designed and written classes. There’s a discussion of the Single Responsibility Principle and how to apply it followed by a section on designing classes that handle change (like new requirements) well.
Chapter 11: Systems looks at taking the principles of writing clean code from the class level to the application level. How do we design programs, frameworks, and libraries, in a clean way? The chapter also looks at ways to instantiate parts of the system using factories and dependency injection, issues with scalability and possible solutions, using Aspect-Oriented Programming to handle cross-cutting concerns, and how to use automated tests to help design the architecture.
Chapter 12: Emergence explores the possibility that following four simple rules could lead to creating well designed software. The rules in question are Kent Beck’s four rules of Simple Design: a design is considered simple of it runs all the tests, contains no duplication, expresses the intent of the programmer, and minimizes the number of classes and methods.
The author admits that a simple set of rules can’t replace experience, but points out that following these rules can reduce the time needed to get that experience.
Chapter 13: Concurrency looks at the challenge of writing concurrent code that behaves properly and some of the things you can do to be successful at it, including some ideas on how to test concurrent code.
Chapter 14: Successive Refinement is a case study showing how the author wrote a command-line argument parser and improved it (more general purpose, easier to use and understand) using techniques from previously chapters. There is a lot of code here, but this is a great example. As the chapter progresses, Uncle Bob doesn’t just tell you what he’s doing, he tells you why, then shows the results so you can see how effective each change is.
Chapter 15: JUnit Internals is more than a peek at how JUnit works; it’s another example of how to refactor existing code (in this case, a portion of JUnit that helps to identify String comparison errors) and make it cleaner and easier to understand.
Chapter 16: Refactoring SerialDate is yet another example of using the skills we’ve gained to examine some existing code (this time from the open source JCommon library) and clean it up. Martin calls this a “professional review” and I suspect we would all benefit, as would our code, from participating in reviews like this.
Chapter 17: Smells and Heuristics is a list (including a title and description) of all the “code smells” and heuristics referred to throughout the book. The list includes many of the smells from Martin Fowler’s book, Refactoring, in addition to those the author identified while reading through a lot of code.
Appendix A: Concurrency II is something of a tutorial and is intended to expand upon the topics presented in Chapter 13. It describes different instances where concurrency can apply and some of the issues surrounding them.
Appendix B: org.jfree.date.SerialDate is a listing of the original SerialDate class that got cleaned up in Chapter 16.
Appendix C: Cross References of Heuristics is essentially an index showing where each of the smells and heuristics from chapter 17 are referenced in the book.
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)