Lately, I have been reignited in my desire to learn more about software architecture. While I think of myself as a pretty good "problem solver," I definitely lack a solid understanding of how things should be put together. In a recent stint of research and development on the topic, I came across a fascinating talk titled, "Architecture: The Lost Years," by Robert Martin. While I've heard the name, "Uncle Bob" before, I wasn't too familiar with who Robert Martin was. I was so intrigued by his presentation, however, that I had to immediately go out and buy his book, Clean Code: A Handbook of Agile Software Craftsmanship.
The book is an opinionated (in a good way) view of how to create clean code. It outlines the approaches that Robert Martin has found, over 40 years of programming, to be successful. It was fun to read through each recommendation and think to myself either, "Cool, I already do that," or, "Oh Chickens! I need to start doing that immediately!"
But, the most powerful part of the book, for me, was actually the conclusion of one of the last chapters. I think it speaks directly to many of the fears and anxieties that I have about the way that I currently program:
It is not enough for code to work. Code that works is often badly broken. Programmers who satisfy themselves with merely working code are behaving unprofessionally. They may fear that they don't have time to improve the structure and design of their code, but I disagree. Nothing has a more profound and long-term degrading effect upon a development project than bad code. Bad schedules can be redone, bad requirements can be redefined. Bad team dynamics can be repaired. But bad code rots and ferments, becoming an inexorable weight that drags the team down. Time and time again I have seen teams grind to a crawl because, in their haste, they created a malignant morass of code that forever thereafter dominated their destiny.
Of course bad code can be cleaned up. But it's very expensive. As code rots, the modules insinuate themselves into each other, creating lots of hidden and tangled dependencies. Finding and breaking old dependencies is a long and arduous taks. On the other hand, keeping code clean is relatively easy. If you made a mess in a module in the morning, it is easy to clean it up in the afternoon. Better yet, if you made a mess five minutes ago, it's very easy to clean it up right now.
So the solution is to continuously keep your code as clean and simple as it can be. Never let the rot get started. (Page 250 of 316)
This segment feels like a serious kick to the head! And, worst of all, I think it touches on a deep anxiety that I have, that my current approach to software development is, "unprofessional." But, at least I can take comfort in knowing that this anxiety stems from a deep-seated desire to improve - to always be getting better. And it's books like this - Clean Code - that help me make continual progress on that front.
While the above segment probably struck the deepest chord, I'd like to share a few other segments that I happen to really like for their architectural suggestions:
Flag arguments are ugly. Passing a boolean into a function is a truly terrible practice. It immediately complicates the signature of the method, loudly proclaiming that this function does more than one thing. It does one thing if the flag is true and another if the flag is false. (Page 41 of 316)
Command Query Separation
Functions should either do something or answer something, but not both. Either your function should change the state of an object, or it should return some information about that object. Doing both often leads to confusion. (Page 45 of 316)
Prefer Exceptions to Returning Error Codes
Returning error codes from command functions is a subtle violation of command query separation. (Page 46 of 316)
Don't Repeat Yourself
Duplication may be the root of all evil in software. Many principles and practices have been created for the purpose of controlling or eliminating it. Consider, for example, that all of Codd's database normal forms serve to eliminate duplication in data. Consider also how object-oriented programming serves to concentrate code into base classes that would otherwise be redundant. Structured programming, Aspect Oriented Programming, Component Oriented Programming, are all, in part, strategies for eliminating duplication. It would appear that since the invention of the subroutine, innovations in software development have been an ongoing attempt to eliminate duplication from our source code. (Page 47-48 of 316)
Don't Return Null
If you are tempted to return null from a method, consider throwing an exception or returning a SPECIAL CASE object instead. If you are calling a null-returning method from a third-party API, consider wrapping that method with a method that either throws an exception or returns a special case object. (Page 110 of 316)
The Single Responsibility Principle
To restate the former points for emphasis: We want our systems to be composed of many small classes, not a few large ones. Each small class encapsulates a single responsibility, has a single reason to change, and collaborates with a few other to achieve the desired system behaviors. (Page 140 of 316)
Concurrency Defense Principles
Recommendation: Keep your concurrency-related code separate from other code. (Page 181 of 316)
How Did I Do This?
If we have learned anything over the last couple of decades, it is that programming is a craft more than it is a science. To write clean code, you must first write dirty code and then clean it. (Page 200 of 316)
I really love that last line, "To write clean code, you must first write dirty code and then clean it." One of the great things that Uncle Bob talks about is how iterative programming is - how on one pass, he'll factor logic out into its own function; then, on a second pass, decide that it would be better to inline the logic back into the original function.
I think I tend to have this picture in my head that "master programmers" just get it "right" on the first pass. It's incredibly comforting to know that being a great programming is not about never making mistakes; rather, it's about knowing how to continually iterate and improve on a solution. And probably, to know about a lot of good design patterns to begin with.
I read Clean Code on the Kindle App on my iPad. And, when I was reading reviews of the book, I saw a number of people say to stay away from the Kindle version. After having finished the book, I see what they were talking about. The first half of the book is completely fine, covering many design patterns and recommendations. The second half of the book, however, deals more with code samples and refactoring case studies, and is definitely a bit wonky at parts.
Overall, however, the book is definitely a worthwhile read (hopefully evident from the excerpts above) and one that I would highly recommend. It's a lot to take in and I'm sure it will serve a good reference manual that I'll have to periodically bring back into my consciousness.
To further our Twitter discussion, the guys teaching our TDD class recommended the TDD by Example book by Kent Beck first, followed by Clean Code for our further reading. I got about 5 chapters into Clean Code before the class started.
Ben, for some reason the Facebook Like is not functioning. Thanks for the review.
If you write code, you should read this book on an annual basis. Absolutely fantastic book for everybody from beginners to seasoned professionals.
Uncle Bob is presenting at the SCNA conference in Chicago (http://scna.softwarecraftsmanship.org/speakers) in November. I for one plan on being there.
Oh cool, thanks for the recommendation - I'll have to check out out!
Hmm, that's odd - maybe it was a glitch or the script didn't load or something. I'll take a look.
I think you bring up a great point - regularly re-grounding yourself. I tend to read a lot of the same types of material. It can seem repetitive; but, it serves as a reminder about a better way to be. It's like Church for developers :)
Very cool - I didn't know about that conference! Taking a look now.
Uncle Bob also as a great video series: http://www.cleancoders.com/ and the book Clean Coder (http://www.amazon.com/The-Clean-Coder-Professional-Programmers/dp/0137081073/ref=sr_1_1?ie=UTF8&qid=1340910234&sr=8-1&keywords=clean+coder) which I recommend. For conference videos NDC here in Norway where Uncle Bob as spoken the last 4 years also release their videos for free, here are for this year: http://vimeo.com/tag:robertcdotmartin
I've not seen Clean Coder yet, thanks for the heads-up. Also, thanks for the Vimeo links - putting them on the background right now :)
Listening to one of the talks and I love this quote by Bob Martin:
"A good architect maximizes the number of decisions not made."
Cool! I read Perl Best Practices by Damian Conway. It has a lot of these same suggestions but obviously focused only on Perl.
I resonate with your "Oh Chickens!" comment. There are some real pearls of wisdom in these books. Even just making code more readable is great and there are a lot of good techniques for that.
Yeah, that's how I try to look at these books. Sometimes, there's a lot of repetition with other books that I've read. But, reading it drives home the message and provides different opportunities for those pearls of wisdom to resonate with your current understanding of the programming world. It's awesome!
I've noticed my first pass always ends up working, but not necessarily the best way to do things. Usually AFTER you've written the code, you have the 20/20 hindsight of knowing what the other side looks like so you have a, "Oooh, y'know, I could speed up this here and not duplicate there."
The problem lies with clients. The client always want you to produce code and demos. Many times, lines of code mean, "He must be doing something," whereas fewer lines of code mean, "He must not be doing much."
You, me, and all your readers know the exact opposite might be true. The best code might be the code that takes the longest to write, refine, and, sometimes, redo. We know that taking the extra time at the beginning may pay dividends in the long run. Most clients -- and co-workers -- don't see it this way. They think code that works equate to "good code."
Same with me, it usually takes many passes and much refactoring to get code in to the kind of condition it needs to be in. If the next guy to pick up the code doesn't spend half a day cursing at me, I probably did well.
I find the code generally gets much more concise with each pass, making it even easier for further cleaning. That function that actually is doing two things can't hide so easily. That subtle bug suddenly sticks out like a sore thumb.
There is some saying about a guy writing a letter that turned out long, and he said something like 'I apologize for the length of my letter. I didn't have the time to write a short one.'
Code Craft is another good book along these lines.
My biggest problem is that I have 20/20 hindsight to say, "this was a bad idea"... but, I don't always know how to change it :( That's what I'm really trying to think more deeply about these days.
In the book, Robert Martin talks about the "Boyscout Rule" - always leave code better than the way you found it. That's what I'm really trying to do now, so the code actually does get better over time. I'm hope to have your kind of experience, were bugs start to stick out like sore-thumbs!
Nice one Ben - just bought a few copies for the office.
Thanks Ben. Have added the *paperback* version to my Amazon Wishlist. :)
I remember paperbacks ;)
Writing clean code really is an art rather than science. Having just written my first application in over 13 years (have been a non-hands-on-manager since), I'm looking over my work with disgust! It's not that it's terrible, but that it could be so much better!
I loved this quote from the book, "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." (pg 58 of 462)
I've recently starting watching the "Clean Coder" video series by Uncle Bob:
So far, I'm really liking it!