How to Write Clean Code: Best Practices
«Writing clean code requires a disciplined use of a myriad little techniques applied through a painstakingly acquired sense of “cleanliness”. This “code-sense” is the key.»
(с) Robert C. Martin
The Dangers of Bad Code
Every code can work and execute the task it is intended to complete. Even poorly written “dirty” code performs a task. But good code writing skills and mastery of software design patterns are not enough for professional developers nowadays. It is also immensely important that they develop a good “coding style” and adhere to universal coding standards.
Bad code wastes a lot of time because it needs a lot more maintenance effort. Plus, the time it takes to modify the code so it complies with new requirements makes error-handling a disaster. What are the reasons behind the bad code? And why does bad code appear on software development projects? Robert Martin takes a thorough and revealing look at this problem in his book, Clean Code: A Handbook of Agile Software Craftsmanship (Prentice Hall/2008).
In his handbook, Martin compares a software development project with a house. When the house is new, the windows are shiny and intact, the walls are clean and everything looks orderly. But at some point a while later, the homeowner will discover a broken window, or see graffiti scrawled on one of the walls.
The same process happens with the software code. Sometimes programmers casually decide to postpone the needed refactoring of a freshly written module. “I’ll do it tomorrow,” they tell themselves. The next day, it slips their mind and they forget to go back and get it into shape. No problem, at first glance anyway. Everything seems to work. Often, modules get created in such a way one by one and all components seem to work as expected. Then, the development team gets tasked with changing some supposedly minor bit of the code, and all hell breaks loose.
When you set your eyes on lines of code written at some earlier date, what do you see? Often it’s a long-forgotten piece of functionality. In order to modify or fix it, you need to understand the code, how it works, and what the developer on the project meant it to do. Sometimes that developer is you. The process of figuring out how the code works takes time. The amount of time clearly depends on the quality of the work. And that’s the sticking point. You have to take so many details into account.!
The rule on how to write code cleaner is simple and true for every software developer and for all programming languages: bad code leads to bad consequences. Today, we don’t get the work done and don’t spend enough time on refactoring the code. By the time a week goes by, we’ve forgotten what this particular piece of code was about. A month goes by and we get a task to modify it. It takes an impermissible amount of time to figure things out. So we miss our deadline. We don’t have time to release the necessary bug fixes and add new functionality. In the end, the project goes to the dogs.
This could have been avoided if we’d simply done our job right from the very beginning.
Bottlenecks and shortcomings of this type tend to accumulate. We may think a flaw in the code is insignificant, dismiss it as not worth our time, the functionality is all that matters now. Do this one more time and your little bits of dirty code start to snowball.
As the snowball grows bigger, it starts to follow us. We find ourselves on a steep slope. In time, it becomes harder and harder to change anything in the functionality. We spend more and more time working things out until the day comes when the snowball overtakes us and we get squashed. The time we could have spent creating new functionality gets wasted on figuring things out, making changes in the existing code, error handling, and bug fixing.
If only we had followed a couple of simple rules, none of this would’ve happened. I would like to make a few recommendations you do well to follow if you want to write code that is clean and maintainable in both back-end and front-end development. Let’s get started!
Write Meaningful Names for Variables and Functions
One of the hardest tasks in programming is declaring good names for variables, functions, and classes. The rule of thumb is this: make sure function and class names are meaningful, i.e.: purposeful, substantial, useful, and worthwhile. Try to use descriptive names that are explicit and fully render both the meaning of and expectations for the method or function. In other words, the name should reveal the intent, for example, create noun or noun phrase names, verb or verb phrase names. The key is to be consistent. Method or function names, names for objects and data structures should be very clear about what they hold. What’s more, declaring pronounceable names can really facilitate the process of writing your code and collaborating with peers. Finally, with time, if the function/method changes, it’s important to update the name so it reflects the new function or method. This is one of those times when it is essential that you put yourself in the next programmer’s shoes.
You also shouldn’t forget about the “magic numbers.” It is highly advisable to replace them with named constants that will be meaningful in the context of a program. Placing the declarations of “magic numbers” together at the top of a function or in a separate file will significantly facilitate code review and change. Check out our code review guide to learn the best practices of code review.
In addition, keep the code style in mind. It’s important to keep everything in one stylistic form. Almost every project has a style that’s convenient for the entire team, a practice that is strongly encouraged.
Methods and Functions
Methods and functions should fulfill only one task at a time. The single responsibility principle is mission-critical in software development.
You shouldn’t provide too many function arguments. If the number of arguments is 4 or more, such functions are questionable and should be avoided if possible. If the function gets 4 and more arguments, you’d better “pack” them into an object.
Always delete functions and methods you don’t use. Nowadays, there’s an array of version control systems that help you easily detect changes.
Avoid duplicating your code. The less code, the less problematic it will be to maintain.
If there ever was a perfect code, it would be the one that doesn’t need any explanations or comments. Clear and comprehensive code with minimum or no comments is far superior to messy code with tons of extra text. Сomments can never make up for bad code, even though in some cases they are necessary.
Sometimes your code might require a comment, especially when it performs some specific task, or the method intention cannot be understood by its name only. In this case, write a single line and don’t go into too much detail. Also, you may come upon certain cases where some part of the method was turned off for some reason. Then you should leave a comment explaining the reason. Finally, TO-DO comments are an important part of writing good code. They can be very useful when you can’t do something immediately and need to keep it in mind for later.
But we should always keep in mind that long, verbose comments are often redundant. Excessive comments are unnecessary, especially when they describe an obvious behavior of a method or function. For example, there’s no need to comment on clear and self-explanatory pieces of code. Generally, if the comments don’t bring any useful info or add any value whatsoever, they should be deleted. And if you’re tempted to write a comment to justify or explain why you made a shady decision, don’t do it. Unfortunately, you won’t make your choice look any better.
NB. It is very important to keep the comments up to date.
Never underestimate the importance of formatting, whatever programming language you use. Well-formatted code is one of the main features of good programming “manners.” Formatting and readability have a direct influence on keeping the code up to date and can help you save tons of time in the long run.
Unit tests are the guardians of your code quality. By covering your code with unit tests in a timely fashion, you’re double-checking yourself and your code. In the future, unit tests and test-driven development will help to detect weak spots and identify where the behavior of the program is distorted or broken.
Refactoring is key, literally. This is what makes our old code beautiful, enhanced and easier to understand. There is always room for improvement. Beware, though, and steer clear of becoming obsessive or overly zealous. If you’re tempted to break the existing code and start to rewrite everything from scratch, you’re probably going overboard. Refactoring should be done carefully and in small chunks, so you don’t mess up one part while trying to fix another. Step by step, go through every single line of code. Do this slowly and your code will become better and better.
If you’ve made it this far, you are a thorough reader. Writing clean code really matters to you. As a reward, I will share the most well-kept secret of writing clean code. Ready? The best way to write elegant, clean code is to do it from the very beginning – write good code from scratch. In fact, there really is no secret, just work to be done and shortcuts to be avoided.
Simply follow the main principles of agile software development. Writing and revising your code iteratively and in chunks can save more time than you can imagine. After you’ve completed a task, you should come back to your source code and see what can be improved. Try to refactor. Do regular peer code reviews; they help you see your work from different angles. There will always be something that can be enhanced by a developer. And don’t forget about unit tests. Unit tests are crucial and can help you save a lot of effort during functionality testing. True software craftsmanship is built on perfectionism.
Finally, treat your code the way you’d treat your ideal living space. Make sure it’s neat and tidy, with everything in place and laid out in an orderly fashion. It’s always easier to find your car key if you know it’s on the shelf near the door where you habitually leave it. You quickly notice if something’s missing in a tidy room, right? It’s similar with your code. When code is clean, it stays readable and transparent, error-proof and easy to modify.