Want to read Slashdot from your mobile device? Point it at m.slashdot.org and keep reading!

 



Forgot your password?
typodupeerror
×
Programming

Clean Code 214

Cory Foy writes "As developers, system admins, and a variety of other roles in IT, we have to deal with code on a daily basis. Sometimes it's just one-off scripts we never have to see again. Sometimes we stare at something that, for the life of us, we can't understand how it came out of a human mind (or, as the book puts it, has a high WTF/minute count). But there is a time when you find code that is a joy to use, to read and to understand. Clean Code sets out to help developers write that third kind of code through a series of essay-type chapters on a variety of topics. But does it really help?" Read below to find out.
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
I had the pleasure of attending Bob Martin (Uncle Bob)'s sessions at several agile software conferences over the past several years. In them, Bob has a unique way of showing us the value of clean code. This book is no different. There is a warning in the introduction that this is going to be hard work — this isn't a "feel good" kind of book, but one where we slog through crappy code to understand how to make it better. The authors also point out that this is their view of what clean code is all about — and fully acknowledge that readers may "violently disagree" with some of the concepts.

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.

This discussion has been archived. No new comments can be posted.

Clean Code

Comments Filter:
  • Good review (Score:5, Interesting)

    by raddan ( 519638 ) on Wednesday September 24, 2008 @01:25PM (#25138829)
    Wow, good review. I usually skip over the reviews, because I find that they're filled with inside jokes and wandering monologues, but in this case, the review was well-written, thoughtful, and the book seems interesting. I'll probably pick it up. If this was a Slashvertisement, well, it worked.
  • Bravo! (Score:2, Interesting)

    by fferret ( 58662 ) on Wednesday September 24, 2008 @01:27PM (#25138863) Homepage Journal
    Even if I was still coding, (moved on to sys/netadmin several years ago,) this book would deserve a huzzah! OK, now we've made it readable, when can we make it efficient, and get rid of all the bells&whistles that have turned software into bloatware!?
  • by The Clockwork Troll ( 655321 ) on Wednesday September 24, 2008 @01:29PM (#25138893) Journal

    I don't know that this is the right book for the general problem.

    In my career, the engineers who have been the most effective and most pleasant to work with usually do what they can to be better teammates. This includes but is not limited to: writing good code (or improving/refactoring existing code), and managing their personal interactions with teammates toward rational consensus and general embetterment (a perfectly cromulent word).

    In my experience, the guys who consistently write the worst code also tend to have "lone wolf" mentalities. These are the guys who say, "if it was hard to write, it should be hard to read", and not half-jokingly. I honestly get the impression that growing up they might not have had the sorts of personal interactions that lead a person to be mindful of "playing nice with others". Coding serves a much more selfish end. This doesn't mean they are not "productive" in the absolute sense, but they are solo silo stars and it's hard to pair or team them.

    Put another way, the kind of engineer that would actually benefit from a book like this, has probably already read a book like this.

    The needed book I think is for the manager: psychology of the antisocial geek

  • Depends on function (Score:2, Interesting)

    by BountyX ( 1227176 ) on Wednesday September 24, 2008 @01:39PM (#25139083)
    Preformance related code and highly efficent code is the opposite of clean code. Clean code is often high level in nature, while efficient and robust code is low level and not pretty. Comments are for readabilty, not the code. Always go for efficiency.
  • Re:yay! (Score:5, Interesting)

    by myvirtualid ( 851756 ) <pwwnow@ g m ail.com> on Wednesday September 24, 2008 @02:02PM (#25139499) Journal

    high WTF/minute count

    hot damn. a new and useful [SI] unit. thanks

    All kidding aside, WTF/minute is a deceptive metric.

    I remember poring over about 30 lines of C for about two plus days with a WTF/minute ratio in the hundreds or thousands. And I knew what the code was supposed to do! It wasn't that I didn't understand it, I didn't understand why the guy who wrote it, a brilliant, brilliant hacker, wrote it the way he did.

    Over two days of following the nested ifs, the gotos (no STL, no exception handling, the gotos made perfect sense), the logic, then BAM!

    "Wow, that's fast!"

    It was the most difficult-to-read code I'd ever read - and it was brilliantly brilliantly fast. (It was a network proxy involving PKI-related messages embedded in LDAP, all based on ASN.1 - all speed improvements were important, his were amazing.)

    Most of the time, high WTF/minute is a good indication that the coder should never, ever have been allowed near a keyboard. Live an awful lot of Java.

    But every now and again, high WTF/minute is a sign of absolute genius. Like a lot of really cool Haskell code. Or wicked perl.

    Hmm, perhaps it's not WTF/minute that we need to consider, but its first order derivative. WTF/minute that peaks then declines to zero suggests genius. WTF/minute that remains constant suggests a bad day or a lot of PHB pressure. WTF/minute that increases without bound suggests brain-damage and a potential career in sales.

  • by Zet ( 178940 ) on Wednesday September 24, 2008 @02:18PM (#25139801)

    This is dead wrong. It's true that sometimes
    purity is sacrificed for performance. But in
    general, good clean code matches a good clean
    design, which emerges when a problem is
    well-understood. Even code that has been
    tweaked to exploit certain compiler anomalies
    can remain clean.

  • by dubl-u ( 51156 ) * <2523987012@pota . t o> on Wednesday September 24, 2008 @02:23PM (#25139875)

    I totally agree with Bob Martin here.

    Suppose I go into the doctor and say, "I'm tired and not getting enough done. Please give me a bucket of amphetamines." The doctor will say no, as that would be likely to cause harm, followed by death. Instead, they'll try to figure out what's really going on, and help me appropriately. That's what professionals do.

    If a boss comes to me and tells me that for the new banking software they'd like me to skip testing, exception handling, and error logging, I'll say no. Instead, I'll ask them what their real goal is, and suggest ways they can achieve that.

    Over and over I see developers offering to write unmaintainable garbage, only to get in hot water in a year's time because productivity is in the toilet. It's not even fun the first time, but people keep on doing it. They should stop.

  • by tjwhaynes ( 114792 ) on Wednesday September 24, 2008 @04:06PM (#25141663)

    Consider the first "clean" sum generator:

    int sum(int n) { if(!n) return 0; return sum(n-1) + n; }

    It's interesting you chose this one. I write a lot of Perl (tens of thousands of lines a year) and you might have done this in perl:

    sub sum {
    my $input = shift;
    if ($input =< 0) return 0;
    return sum($input - 1) + $input;
    }

    at which point you would tried it out on some large number and cried about the performance. Now the code is clean (albeit somewhat lacking in type checking) and it would be a shame to lose that cleanliness in the search for performance. This function is deterministic, so if we can cache the result, we can get the performance we want at the expense of memory usage. So we add the following to our code:

    use Memoize;
    memoize('sum');

    and magically, we get caching on the sum subroutine. And our code remains clean and understandable.

    Just because anyone can write unreadable, unmaintainable Perl doesn't mean you have to...

    Cheers,
    Toby Haynes

I have hardly ever known a mathematician who was capable of reasoning. -- Plato

Working...