Clean Code 214
Clean Code - A Handbook of Agile Software Craftsmanship | |
author | Robert C. Martin |
pages | 431 |
publisher | Prentice Hall |
rating | 10 |
reviewer | Cory Foy |
ISBN | 978-0-13-235088-4 |
summary | A great book for anyone wanting to really improve how they write code |
The book wastes no time diving in covering "Meaningful Names", "Functions" and "Comments" right in the first several chapters. While I could sum up the chapters by saying, "Use them", "Keep them small" and "Comments don't make up for bad code" it wouldn't do the wisdom in the book justice. For example, in the meaningful names chapter, he talks about making pronounceable and searchable names — staying away from things like "genymdhms" (Generation date, year, month, day, hour, minute and second) and preferring things like MAX_STUDENTS_PER_CLASS.
After touching on formatting rules (including some very interesting graphs on the file and function length distributions in some common open source projects) he dives back into some more controversial topics — "Objects and Data Structures", and "Error Handling". The Objects chapter does a great job of drawing a line in the sand between Objects and Data Structures and why it really is both important, and clearer, to keep your privates in your private classes.
The Error Handling chapter is important because of the application of earlier chapters — the Do One Thing rule. Your functions should do one thing — either handle business logic, or exception handling, but not both. It's the difference between this:
try { s = new Socket(4000); s.OpenSocket(); string data = s.ReadFromSocket(); if(data == "32") data = "42"; printer.print(data); } catch(Exception ex) { if(ex == NetworkInterruptException) { //do something } if(ex == PrinterOnFireException) { //do something } logException(ex); }
And this
try { tryToPrintDataFromSocket(); } catch(Exception ex) { logException(ex); }
We then move on to "Boundaries" and "Unit Tests" — the critical points where we tend to really let code go. If we work hard, usually we can keep our own code clean. It's when we have to begin interacting with other systems that things start to go astray. In these chapters, Bob and James Grenning show us how to keep our code at the boundaries clean — and how to keep our code working, period. The authors are proponents of Test-Driven Development, and the chapter on unit tests is a fresh reminder that those tests are just as much code, and need to be kept just as clean as any other code we write.
We then begin to move at a higher level, starting with "Classes" and "Systems". The classes section should be familiar to most any OO programmer — keep the classes small, with a single responsibility, and low coupling. He also talks about Organizing for Change which is a great section on how to structure classes in a way that keeps them open to change. The Systems section continues along the path with the great reminder to "Separate Constructing a System from Using It". Here they go into Dependency Injection and Aspect-Oriented Programming, which I'll address in a bit.
Moving even higher up the chain, the book then tackles "Emergent Design". The key is to keep the design simple, which according to Kent Beck, means:
- Runs all the tests
- Contains no duplication
- Expresses the intent of the programmer
- Minimizes the number of classes and methods
With the above list given in order of importance. Really this breaks out to "Runs all the Tests" and "Refactoring" or making the code better. Simple design is perhaps one of the harder things out there, and yet the most important. When you look at systems that highly scale, it's because they are made up of simply designed components which work very well together.
After the Emergent Design chapter there is suddenly a chapter on Concurrency. This was not something I expected to see, but was very glad to. Too many times books about patterns and design don't address problems like scaling and concurrency. But this chapter does a great job of introducing the necessary steps that need to be taken to deal with concurrency — while still keeping your code clean. The book also provides an appendix which goes even deeper into the concurrency topic which I found to be quite good. Both this chapter and the appendix provide some very valuable rules that I personally have used when writing concurrent systems — like "Get your nonthreaded code working first" and "Run with more threads than processors" to flush out problems.
Chapters 14-16 cover the cleaning up of three different sections of code — an argument processor, JUnit and SerialDate, which is part of the org.jfree package. These chapters really hold true to the warning in the introduction that we'd be going through some code. However, the refinements work very well, and I think that each of them show the value of how much cleaning up the code can improve the readability of even code that works well and seems clean.
The last chapter is a "Smells and Heuristics" chapter which I'm finding to be a handy reference guide for code smells I see. When something is bothering me with code I'm reading, I flip to this section first to see if they have it listed. And with things like "Replace Magic Numbers with Named Constants" you can be sure that all of the advice that should have been beaten into your head long ago is still there, and relevant.
All in all I think this is a very valuable book for any developer wanting to improve how they write code. For senior level people, some things may seem trivial, but if you really take the time to look at the structural changes being made and apply them, you will write better code. For functional developers — the authors believe in OO, but there are still valuable nuggets that are applicable outside of that (like "Use Copies of Data" in the concurrency section). And for any developer, the insights are really good, and you'll find yourself writing down little snippets to hang on the wall.
The challenges with the book are first that it is just as they said — hard work. This is not a flip-through-with-your-mind-shut-off type book. If you want the most out of it, you have to be willing to really work at it. The other challenges are that at times it gets way too Java-centric. All of the code examples being in Java is fine, but some of the chapters (most notably the Systems chapter) really go heavy into Java tools and the Java way which, to me, weren't always applicable across languages.
All in all, I'd highly recommend this book to anyone wanting to improve how they write code. You likely will find yourself violently disagreeing with parts, but the total sum more than makes up for it.
You can purchase Clean Code - A Handbook of Agile Software Craftsmanship from amazon.com. Slashdot welcomes readers' book reviews — to see your own review here, read the book review guidelines, then visit the submission page.
I really want a copy of this... (Score:5, Funny)
Re:I really want a copy of this... (Score:5, Funny)
"How to Write Unmaintainable Code".
Use Perl!
God's code... (Score:5, Funny)
According to xkcd
http://xkcd.com/224/ [xkcd.com]
Re:I really want a copy of this... (Score:3, Funny)
yay! (Score:5, Funny)
hot damn. a new and useful [SI] unit. thanks
Re:Good review (Score:5, Funny)
Bob's your uncle? (Score:3, Funny)
"Bob Martin (Uncle Bob)'s"
No wonder he's so good at making clean code... Bob actually is this guy's uncle!
Of course... (Score:5, Funny)
So Dijkstra is no longer the go-to guy on this? (Score:3, Funny)
If you think THAT's clean code (Score:5, Funny)
You should see the SOAP request I wrote last year!
[rim shot]
Good night! Don't forget to tip your waiters!
Re:yay! (Score:5, Funny)
who wants (Score:4, Funny)
Re:yay! (Score:5, Funny)
wtfs-per-minute [think-box.co.uk]
Re:I really want a copy of this... (Score:3, Funny)
A real programmer is lazy and uses a random character generator. ;p
Re:yay! (Score:3, Funny)
Re:I really want a copy of this... (Score:5, Funny)
Mod parent redundant, gp already said 'Use Perl!'
Re:Run with more threads than processors (Score:1, Funny)
It's amazing how much code there is that doesn't run as expected when you run it with fewer threads than processors.
Especially on a single-processor machine.
Re:I really want a copy of this... (Score:2, Funny)
whitespace (Score:4, Funny)
you can't get cleaner than that [wikipedia.org]!
Re:I really want a copy of this... (Score:5, Funny)
to set right next to my "How to Write Unmaintainable Code".
It's an artform, some people make it look so easy, but to write truly horrible code takes lot of practice. The key is gotos and ifs (preferably nested deeply). Consider the first "clean" sum generator:
int sum(int n) {
if(!n) return 0;
return sum(n-1) + n;
}
We'll see about that:
int sum() { int n,ro,r; ro=-1; n=r=0;
f: if(n<10) {
ro=r;
r=r+n++;
}
if(!(ro^r)==0) goto f2;
if(n>=10) goto f2;
goto f;
f2:
return r;
}
It's important to note just how unmaintainable this function is. It's hard coded (the limit is stored in two different places), so that it only calculates the sum of 1...10, (so, in fact, the entire function could be replaced by a a constant integer). It also has a redundant check, to make sure that the two are the same (so that it doesn't get too large), but it might get too small. Naturally, goto is cruise control for cool.
Re:Depends on function (Score:3, Funny)
Re:Good review (Score:5, Funny)
Good meta-meta... I... joke.
Good recursive [ERROR: STACK OVERFLOW]
Re:yay! (Score:5, Funny)
Re:I really want a copy of this... (Score:1, Funny)
(define (fib n)
(if (< n 2)
1
(+ (fib (- n 1)) (fib (- n 2)))
))
Re:yay! (Score:4, Funny)