Index

Writing code does not only mean making a programme work, but also making it readable, maintainable and efficient. The concept of ‘Clean Code’ is based on a set of principles and good practices that enable developers to write code that is clear, intuitive and easy to edit. In this article, we will explore the basic principles of Clean Code, taking a cue from Robert C. Martin's famous book, "Clean Code - A Handbook of Agile Software Craftsmanship".
A foundation called Clean Code
The 17 chapters cover topics such as naming variables, writing tests and the structure of functions and classes. Each chapter has further subsections that follow a similar structure: A negative example is used to explain a messy code practice and then how to proceed in its place.
Moreover, there are summary chapters on more complex topics, such as software architecture or concurrent programming.
Code examples in the book are written in Java, so prior knowledge of the language is an advantage. Nevertheless, this is not absolutely necessary, as many of the examples are easy to understand and can be transferred to other programming languages.
What is clean code?
A famous quote by Grady Booch states: ‘Clean code reads like well-written prose.’ This means that the code should be intuitive and self-explanatory, reducing the need for superfluous comments.
But how can one improve the readability of code and make it accessible to other developers? Robert C. Martin's book answers this question by providing a number of best practices, such as using clear names for variables and methods, reducing complexity and writing functions with one responsibility. Even small details, such as avoiding returning null or abusing switch statements, can make a big difference in the quality of the code.
Let us consider the following code:
ListName list = new ListName(); list.add(‘Alice’); list.add(‘Bob’); if (list.size() > 0) { System.out.println("First element: ’ + list.get(0)); }
At first glance, the code seems to work correctly, but it can be improved. Instead of, for example, manually checking the size of the list before getting the first element, we could delegate this logic directly to the ListName class:
How about directly providing a method to get the first element without having to manually check the size of the list?
ListName list = new ListName(); list.add(‘Alice’); list.add(‘Bob’); System.out.println("First element: ’ + list.first());
In this way, the code becomes more readable and intuitive. Furthermore, the logic for handling the absence of elements can be hidden within the ListName class, reducing the risk of errors and making the code more maintainable.
Clean code principles
Simplest possible code: KISS
Avoid unnecessary repetition: DRY
Please note: The opposite term to DRY is WET (We enjoy typing). Code is called WET when unnecessary duplications occur in the code.
The following example illustrates the DRY-Clean-Code principle. Let us imagine that we have to calculate the discount on two types of products in an online shop.
public class Discount { public static double calculateDiscountElectronics(double price) { return price - (price * 0.10); // 10% discount on electronics } public static double calculateDiscountElectronics(double price) { return price - (price * 0.15); // 15% discount on clothing } public static void main(String[] args) { double priceElectronics = 1000; double priceClothing = 200; System.out.println("Electronics discount price: ’ + calculateDiscountElectronics(priceElectronics)); System.out.println("Discounted price clothing: ’ + calculateDiscountClothing(priceClothing)); } }The problem here is repetitive code that is difficult to maintain. If we have to change the logic for calculating the discount, we have to modify each method separately. Now we see an improved version, which follows the DRY principle and makes the code more maintainable:
public class Discount { public static double calculateDiscount(double price, double percentageDiscount) { return price - (price * percentageDiscount / 100); } public static void main(String[] args) { double priceElectronics = 1000; double priceElectronics = 200; System.out.println("Electronics discount price: ’ + calculateDiscount(priceElectronics, 10)); System.out.println("Discounted price clothing: ’ + calculateDiscount(priceClothing, 15)); } }In the latter case, there is no more duplication, because the logic of the discount is centralised in one method. If we need to change the discount formula, we only do so in one place. Finally, we can easily add new discounts without writing new methods.
Single Responsibility Principle (SRP)
For better understanding, here is an example: let us imagine a class that is responsible for handling orders and printing invoices. According to the principle of single responsibility, this class should be divided into two separate classes:
- Order - handles orders.
- Invoice printer - prints invoices.
Single Level of Abstraction (SLA)
As an example to illustrate this concept, let us imagine the driving function of a car. A method called drive() should deal exclusively with driving logic, such as accelerating, braking and steering. Yet, if low-level implementation details, such as engine activation or combustion management, were to be included within the same method, different levels of abstraction would be mixed in, making the code more complex to read and maintain.
A convenient indication of different abstraction levels is the presence of code blocks separated by comments or spacing. By moving such blocks into separate functions, the structure and readability of the code can be improved.
Composition by inheritance
An effective alternative is composition, which achieves the same code reuse without introducing excessive dependencies between classes. Rather than extending a class, it is preferable to create independent classes that collaborate with each other through well-defined interfaces.
Coherence in the code
- Uniform naming conventions for variables, methods and classes.
- Predictably organised code structure.
- Use of recurring design patterns for similar problems.
Consistency makes it easier to understand the code and reduces the time needed to familiarise oneself with new designs.