I’ve heard of some people following the Clean Code methodology and some people reacting against it. It’s not been on my reading list before so I got hold of Clean Code by Robert C. Martin. I think it has some good ideas and a few bad ideas. My biggest problem is that these are often presented as rules, rules to be followed. I don’t think one set of rules works everywhere and for everyone. They can be a good source of ideas but you should think about them as well. Here are my highlights, agreements and disagreements from each chapter.
The big idea
I agree with the big idea. Making good code is worth it and bad code, in the long run, isn’t. That is, you should spend time and effort on code and, if you do, overall costs will go down. Developers will get more done and managers will be happy. The author dismisses the idea of accepting a bad version now and fixing everything next time. Either next time won’t come or it will have the same pressures as before. You should do better now.
He also quotes the boy scout rule:
Leave the camp ground cleaner than you found it.
I haven’t followed this specifically but it feels very familiar. When adding extra features I often end up refactoring as well. I don’t want extra code to mean extra complexity.
Meaningful names
I’ve already had my say about this, this is similar but different.
The author favours longer names with more information.
I think that can be taken too far and be distracting.
He’s against member variable prefixes (m_
) which I definitely disagree about.
He claims that you don’t need them any more given modern editors.
I see all sorts of editors, plus source control, browser based tools and more.
I’d prefer to spend an extra couple of characters to just to be sure.
However there are a lot of good things here about consistency, professionalism and context.
Functions
Clean Code is based on small functions that do one thing and only that thing. That makes sense.
The author says that each function should stick to one level of abstraction. So one function might deal with a document as a whole but another function would add individual characters during editing. It’s not something that I’ve kept in mind before but I’ll try it out in the future.
The author thinks functions should have at most, say, three arguments and ideally less. In my experience this seems impractical. Not that I want my functions to have lots of arguments, it’s just sometimes they do. Sometimes you can create sensible structures to encapsulate the arguments. Other times it doesn’t make sense to wrap things up in a structure only to unwrap them immediately. He is very into DRY, probably a bit too much.
Comments
It feels like this is where the No Comment Code movement started. The author concentrates more on alternatives to comments and what to avoid in comments. They sound more balanced here than where the movement got to eventually. I still like comments more than him.
Formatting
This is mostly a high level discussion rather than a specific format to follow, although we do get an example at the end. I like that it goes beyond the old fashioned line length of 80 characters and suggests 120 instead. The more detailed formatting rules he thinks should be decided, and followed, at at a team level.
Objects and data structures
The author gives some useful advice to consider during planning stages.
Using procedural code, using struct
, makes it easy to add new functions but hard to change the structures.
Using object-oriented code, using class
, makes it easy to add new classes but hard to change the functions.
The circumstances will determine what makes the most sense.
He talks about “train wreck” code which chains together function calls:
const auto path = context.GetOptions().GetScratchDirectory().GetAbsolutePath();
and thinks it’s better to split them up or refactor so that context
can provide the information directly:
const auto options = context.GetOptions(); const auto directory = options.GetScratchDirectory(); const auto path = directory.getAbsolutePath();
I find this bizarre and far prefer the compact version.
It doesn’t leave any unnecessary variables or turn context
into a heavyweight class.
He does back this up a discussion of Law of Demeter
which I’ll think about.
Error handling
The author wants to use exception handling rather than special return codes. This allows you to have a clear main code path and separate out the error handling. I wonder if this is of it’s time. I remember exception handling becoming a bigger thing in the 1990-2000s. However exception handling makes control flow harder to understand and special consideration is need in destructors or other exception handling. I tend to like having error codes and, if there are problems, returning from a function early. This forces you to think about the error and leads to fewer surprises.
Boundaries
In dealing with third-party code the author has some useful ideas. A library developer tends to strive for broad applicability, something that will work for everyone. This can introduce unnecessary flexibility or complexity. You can wrap libraries to provide the exact services you need. As a bonus the wrapped library is much easier to replace if necessary. Having clean minimal boundaries reduces dependencies between systems.
Unit tests
The author quotes the three laws of test driven development (TDD):
- You may not write production code until you have written a failing unit test.
- You may not write more of a unit test than is sufficient to fail, and not compiling is failing.
- You may not write more production code than is sufficient to pass the currently failing test.
While he doesn’t mandate this he does like unit tests. Given my own like of refactoring good and easy testing, unit tests or otherwise, are great but I don’t follow true TDD. I like that he passes by the “one assert per test” idea and goes with “one concept per test” instead. Here “one concept” might be all the various uses of a single function.
Classes
Similar to functions, classes should be small and do one thing. He likes, same as me, hiding things inside classes. The less access of developers have the less they have to worry about and the fewer problems they can cause. He does allow for practical reasons for opening things up.
On balance
Those are my big takeaways although he also covers:
- Emergence: Design rules for clean code.
- Concurrency: Special considerations for parallel code.
- Successive refinement: A big example code refactor.
- Smells and heuristics: A (mostly) good set of bullet points to watch for.
I don’t agree with everything in this book but it has good ideas and has given me things to think about. Don’t treat it as a bible but do let it inspire you to write better code.
Leave a Reply