Clean Coding: or how to be nice to your fellow developers

Michelle Gleeson
Xero Developer
Published in
11 min readAug 7, 2017

--

Over a million small businesses, and their advisors are looking for the best cloud apps that integrate with Xero. Partner with us, and we’ll make sure they find yours.

After about 8 ignorant years of coding I had an epiphany. It was not an original thought but it was certainly an awakening and, in retrospect, career-defining. My pair-programming coach introduced the idea of Clean Coding, and I felt like I had been under rock until that moment. In the next few months I embraced it wholeheartedly. I could feel myself growing from ‘just a coder’, to a craftswoman. Since then I have been talking about Clean Code, and training emerging developers.

As amazing as the book is, I often get asked for the short version. I give presentations to convey the essence of clean code so people are aware of the ideas and hopefully find their own way. The talks have evolved over time as certain programming anti-patterns have come in and out of fashion. The clean code principles form the basis of the accepted coding standards used across our industry today. I would like to share my views on what clean coding means in today’s development world, why it matters, and how to get started.

tl;dr

  • Clean code focuses on making code more readable so it can be easily maintained and allow us to be more productive.
  • We should always try to clean a little more code than we wrote to keep a code base maintained.
  • Name classes and methods with meaningful intention-revealing, pronounceable names, and don’t abbreviate.
  • Functions should be small, do only one thing, have less than three parameters, and no boolean or output arguments. Stick to one level of intending, avoid nested loops and switch statements.
  • Remove duplication with extension methods and well-named single-purpose helper classes. Avoid using base classes as a way to reuse code.
  • Comments in code are not necessary and can be avoided.
  • Classes should be less than 200 lines, do only one thing and every public method should use all its dependencies.
  • Proximity of variable declarations should be used to imply association: don’t declare all locally-scoped variables at the top of the method

What is it? Why Does it Matter?

Clean code is a reader-focused development style that produces software that’s easy to write, read and maintain. As developers, we often consider our task done when the code we write operates as expected, and (hopefully) makes our unit tests pass. But we’re not merely writing code for computer consumption. Clean code is about recognising that your audience isn’t just a computer, it’s real-live people!

Code is clean when it is understood easily by everyone on the team, and can be read and enhanced by any developer, not just the original author. Readability is the most important attribute of clean code. We spend 90% of our dev time reading code and only 10% writing it. Be nice to the person who has to maintain your code. Please don’t write code to show everyone how clever you are and how many complex, over-engineered patterns you can shove in it. Job-retention coding styles went out with the 90's.

When code is easily understood it’s more readable, changeable, extensible and maintainable. Bad code is eventually so un-maintainable, it cannot be updated and it’s no longer possible to be productive.

How does code get dirty in the first place?

The biggest factor of unreadable code is time pressures. You can write it fast, or you can write it well. So often I have seen manager types put arbitrary time pressure on developers which just produces messy technical debt. The time hit up front will be paid back to you tenfold if you can build on and easily change your code base. In order to go fast, we must have clean code.

Programmers need to stand up for clean code just like managers stand up for requirements and schedules. Managers rely on programmers, not vice versa. Be confident in resetting expectations early. Everyone wins in the end.

Inexperience is also a factor. The tech industry is growing so fast now, that half the developers in world have less than five years experience. Look to the seniors around you for guidance.

As developers we are always learning and improving and we do that by writing code. I have been guilty of clicking ‘git blame’ to see who wrote that horrendously complex code, only to see my own name starting at me. We also need to show trust and support. You can’t judge others for their unclean code, you just don’t know the context and time pressures they had.

The boy scout rule

Leave the code-base a little cleaner than you found it. Clean code is a journey. Each time you open a code base you will probably see something that can be improved on. My previous life as a chef taught me the importance of ‘cleaning as you go’. Its doesn’t have to be big changes, just small, incremental improvements make maintaining the code base a whole lot easier. Look at the whole class you are modifying for example, not just the bits you write. Check it in in a nicer state than how you found it.

Naming

It is often said that finding good names for classes, methods, even entire solutions is one of the most challenging parts of our job. It is important to use meaningful, intention-revealing, pronounceable names. It should ‘roll off the tongue’. If it’s easier to say out loud it’s quicker to read in your head.

Don’t abbreviate. Gone are the days where our variable name lengths are restricted by compilers, yet we are still in the habit of writing half a word. This makes us pause when reading code, introduces ambiguity and slows us down. Which is more recognisable? addr or address

Single letter variable names are considered okay for lambdas or for loop counters, though I would suggest you can find a short, sharp name to help out the next coder.

You can use naming to add meaningful context. Extract your if statements to private methods to explain the behaviour you are evaluating. As an example, the first if statement, is less understandable than the refactored line below it:

if (age > 4 && age < 18)...if (IsOfSchoolAge(age))

Functions

Functions should be small and do only one thing. The function name should say what it does. Long descriptive names are better than short, less clear names, though if you have more than 3 words in the name, perhaps the function is doing too much.

Nested control structures make the code harder to read and can bloat code and create unnecessary execution paths, so avoid switch statements and if-else-if chains. These introduce high cyclomatic complexity and user has to keep all those paths in their head before getting to the detail. A good rule of thumb is to stick to 1 level of nesting, 2 at most. Three or more, and it’s time to refactor. Start by inverting if statements and go from there.

Function arguments should ideally be avoided where possible. Too many parameters means it’s doing too many things. They make functions harder to grasp. It makes your code harder to interpret at a glance and readers will ignore long lists of parameters and miss details. Try introducing conceptual helper classes or turning arguments into member variables. If your function has three or more arguments is indication that function should be broken down.

Booleans are the worst type of argument. As soon as you pass a flag argument to a method, already you are saying it’s doing one thing if true, another if false, and it is also harder to read. Consider coming across this call:

render(true)

What does true mean? I have to switch context and read the function to find out. I could using naming to provide context:

render(isRenderAll)

Or better yet, I could split the method into two:

renderAll()
renderSingle()

Output arguments are harder to understand than input arguments and should be avoided. Output arguments means the function is already doing more than one thing. It’s so easy to use return values instead. This leads in nicely to command query separation, which tells us functions should change the state of an object or return info about the object, and should not have any side effects. For example, a method called ‘Get’ should not also write to a database.

Don’t Repeat Yourself (DRY) concepts are essential to clean coding. Duplication bloats code and makes it less readable and harder to maintain. In saying that, be careful not to code for the future. The time to extract the code into a separate method or class is the second time you need it, not the first.

When we do abstract out reusable components there is a tendency to do it quickly without much thought to making it maintainable or readable. Too often we find helper methods in classes called ‘Common’, ‘Utils’ or ‘Helpers’ which becoming dumping grounds for unrelated reusable methods.

Extension method are more readable than helper classes, and highly useful if your language of choice supports them. I like to write more readable extension methods on existing libraries too. For example,

if (firstName.HasValue() || lastName.HasValue())

is faster to read and easier to understand than something like this:

if (!string.IsNullOrWhiteSpace(firstName) || !string.IsNullOrWhiteSpace(lastName))

Base classes are seen as an easy way of sharing code that doesn’t require thought. We often see them doing more than one thing and contain methods that are not used by many of their inheritors. Use them for real inheritance reasons, not code reuse. Code tends to get ‘hidden’ in base classes. Consider using a well-named provider so it’s clear what your classes dependencies are at a glance. Consider using a ConnectionProvider in a repository class, instead of shoving the connection in a BaseRepository, for example.

Now Breath! That is so much to think about, and quite overwhelming. The best way to write clean functions is to get down a draft first: just like writing a blog. Your code will start out long and complicated, with lots of indenting, nested loops and long argument lists. The names may be arbitrary, and contain duplicated code. Then you restructure and refine, splitting out functions, changing names, eliminating duplication, shrink methods and reorder them. Break out whole classes if needed. Doing this, all the while keeping the unit tests passing, will produce clean functions.

Comments

Comments should, and can, be avoided completely. This tends to be the most contentious idea of clean code, often producing quite emotional objections from people who have accepted everything else so far. Certainly when I learned to code I was taught that comments meant quality and the more the better.

Comments may seem necessary at the time, though old comments are often not maintained and can lead to confusion. Readers focus on left-over comments and assume they are still accurate, but the compiled code is really all that can be relied on for accuracy. The use of comments is often used to compensate for our failure to express ourselves in code. It is very possible to explain yourself in code.

This was probably the area of clean coding i found the most uncomfortable. Challenging such an ingrained habit felt wrong. Think of this as a rule of thumb; don’t use comments where you can use a well-named variable or method. Once you stop to really think and try to avoid comments, you too will soon find your code ends up more readable without them.

One reason against this I hear is decorating code with attribute comments is necessary for documentation. There are tools available now to extrapolate your api from compiled code, and often if your methods and classes are well named, it’s unnecessary.

I have also heard, sadly, they are necessary to explain your thought process and provide context for a design decision for the next developer. If your code is so complex it needs you to absolve yourself of guilt in comments, I would challenge you to find a nicer way to write the code. If we as a community start to trust that the author was doing her or his best at the time with the given context, such comments become redundant.

Comments that explain business rules can be replaced with well-named methods, for example:

//Check to see if the employee is eligible for full benefitsif ((employee.flags && HOURLY_FLAG) && (employee.age => 65))

can be made easier to read with

if (employee.IsEligibleForFullBenefits())

Even though you have a lot to get through today don’t be tempted to write those 4 little, innocent-seeming letters:

//TODO

It’s just an excuse for lazy coding. If it’s worth writing todo, just write the code! We both know it’s never going to be more of a priority to you than right now.

The worst comment ever is commented-out code. It’s never going to be reinstated, so please just delete it.

// if (code == oldCode) { DeleteIt(); }

Classes

Think of laying out your classes like you would read an English-language book. It should read from top to bottom, ideally be no more than 200 lines, and those lines will be less than 120 characters long. This means you can see your whole class in the IDE window without scrolling sideways or down.

The class starts with your constants, then private fields followed by methods. The first method will be the main public function of your class. Following that will be the first private method called by that public function, then the second and so on. This is called the step-down rule, and it means you can easily read your class from top to bottom and understand the context more clearly.

Keep variables and utility methods private. If they need to be reused, break them out. The proximity of your variables should imply association. For example, declare a locally-scoped variables just before you use them, not at the top of the method. This means you need to hold less information in your head when reading through. You can also use white space to group related items. For example:

[Test]
public void Post_ValidReceipt_SavesToStore()
{
Mock<IAccountRespository> accountRepositoryMock = new Mock<IAccountRespository>();
Mock<IReceiptStore> receiptStoreMock = new Mock<IReceiptStore>();
accountRepoMock.Setup(r => r.Get(id)).Returns(new Account());
receiptStoreMock.Setup(r => r.Upload(Any<Stream>()).Verifiable());
...
}

Can be cleaned with the following refactor

[Test]
public void Post_ValidReceipt_SavesToStore()
{
var accountRepositoryMock = new Mock<IAccountRespository>();
accountRepositoryMock.Setup(r => r.Get(id)).Returns(new Account());

var receiptStoreMock = new Mock<IReceiptStore>();
receiptStoreMock.Setup(r => r.Upload(Any<Stream>()).Verifiable());

...
}

In the above example, I have declared the mock variables just before using them, used white space between the logical groups to imply association and used the keyword ‘var’. Using an explicit type in the declaration is now redundant for readability if I use a well-named variables. I can also instantly see that something is being declared on that line, before my eyes get all the way along to the ‘new’ keyword.

The single responsibility principle applies to classes as well as methods. When writing classes or tests they should do only one thing. Often you won’t have more than one public method in your class.

To support high cohesion, all your public methods should use all the classes dependencies. When your dependency list gets too long, it’s probably time to refactor.

Code smells

Failure to break out duplicated code, having large classes and methods that do multiple things or comments everywhere it’s often referred to as “Code Smells”. When something just doesn’t seem right, it is usually has some, or all, of the following characteristics:

  • It’s rigid: the software is difficult to change and a small change causes a cascade of subsequent changes.
  • It’s fragile: the software breaks in many places due to a single change.
  • We can’t reuse parts of the code in other projects because of involved risks and high effort.
  • There is needless complexity, needless repetition or the code is hard to understand.

If your code base suffers from any of those attributes, it’s time to clean it up.

The ideas outlined here are a great way to get started. Of course, the Clean Code book goes into a lot more depth about clean code, and further explores other ways to improve the quality of your code base.

This is the start of your journey into cleaner code and I hope you enjoy it as much as I have so far.

--

--