Many companies around the world run book clubs. I am not talking about the Jane Austen kind of book club, but a developer book club; one that covers a textbook. At Mudbath, we have just finished our first book: Clean Code by Robert C. Martin. Now that we have reached the end, it's good to stop and reflect on all we have learnt.
There is a lot of content in Clean Code, so I will try to keep the summary below as succinct as possible, but it is no substitute for the real thing.
While this was not directly addressed as a chapter in the book, I think consistency is the single most important factor in writing clean code. It’s about reducing cognitive load and setting expectations so you don’t catch out whoever follows you, which could even be yourself! I will give you a few examples of what I mean:
Follow the language specification
Writing code to closely follow the guidelines from the authors of the language has many benefits, like not having to write your own style guide. However one of the biggest benefits is that it is easier to onboard new developers. They can hit the ground running faster and not have to spend more time coming up to speed.
Follow the project and team’s specifications
When you’re jumping into an existing project, write your code to fit into the code around it, like a chameleon. Use a linter which enforces code style so that it is trivial to keep the code consistent. When you are starting a new project, this is not the opportunity to change the standards to whatever you prefer, use a standard approach and language that has been vetted by the team.
Follow your own style
Many challenges that present themselves when coding can often be grouped into similar types of problems. You should make a conscious effort to solve these problems the same way, e.g. selecting a unit test framework, utilising a design pattern, or designing a database schema. This means you end up producing more intuitive solutions, and even if it differs to others approach they can still understand how you approach problems.
Naming is hard, but since it is a fundamental part of writing software we should be doing it well. I would argue that if you need to spend an extra 10 minutes coming up with a name for a variable or asking a team member for their opinion, it's better than potentially introducing confusing code that could cause problems later.
All of your variables, functions, classes (etc.) should be:
Provide a clear explanation of what it is which hopefully also reveals its intended use. This means we do not have to dig through code to find out what it is used for. Avoid single character names, except for a few cases like
Have a meaningful distinction between other objects so that it is clear how similar things are different from each other, e.g. it’s difficult differentiating customer, customerData and customerInfo from each other without getting into the code.
When you are working with a team, you’ll probably end up talking about the code, perhaps when you’ve hit a block you need help through. Communication is impeded when you aren’t using real words.
Aim for as few comments as possible by writing code that is easy to read and understand. However, that does not mean you should not write comments.
Use comments to explain the why behind the code, or the intent of the code, which is essentially why they exist and the code works this way. This includes any warnings about the code like how it could break if not maintained correctly, or why it has to work in a particular way.
Try and avoid comments on how it works, since this should already be clear by the way you’ve written your code. However, it would help to clarify what it does, don’t be shy!
Definitely reconsider removing those comments about what it is since it’s almost always redundant and should be obvious from the code.
And finally, without a doubt, remove code instead of commenting it out!! I can’t stress this enough. You should use source control to get the history of the file if you need an earlier version.
It's best to describe your functions using verbs since this is the action that will be performed when this is called. In addition to this, your functions should follow some pretty simple principles:
One of the mistakes I have made in the past is to only split function so they can be reused, but there are many more benefits, such as it makes the code much easier to read (by reducing cognitive load), test, maintain and troubleshoot.
Perform a Single Operation
For similar reasons above, you should reduce the complexity of a function by limiting the number of actions it is performing per function. Even if you are calling them one after another, it will probably help the next person coming through.
Prefer Fewer Arguments
If you are calling a function with many arguments, it increases the risk of making a mistake when calling it, especially if you have many forks in the code based on flags. If you can keep it as short as possible. Consider passing a class or struct that is assembled prior to calling it.
After reading this chapter I realise that a lot of the tests I have worked with in the past were not very clean. I now think differently about tests - they should be as high quality as the production code since they are our safety net! Every single test should be:
Tests should run as quickly as possible to improve productivity and reduce time waiting for tests to finish so the code can be shipped quickly. Write code that enables unit tests rather than requiring integration tests.
Ensure tests aren’t reliant on each other. If you remove a test it won’t affect any of the remaining tests.
When you test yesterday, today and tomorrow the outcome will remain the same. This also means avoiding using production data-driven tests, since it can change and break the tests. Intermittent failures cause distrust of the tests, and developers will write them off.
Keep the test down to a single outcome you are testing for, and ensure that the code around it like scaffolding or even mock data are separated for reuse.
Ok, summary over. Hopefully, I haven’t overwhelmed you with too much information! Clean Code was a really good read, and I wish I had picked it up earlier on in my career. If you are eager for more, then grab a copy of the book at one of the links below: