What I learned reading Robert C. Martin’s Clean Code book

Note: This is the English version of my previous post: “Cosa ho imparato leggendo il libro Clean Code di Robert C. Martin”, that you can find here: https://bit.ly/33VLXm6

Danilo Del Fio
7 min readSep 28, 2020

--

Introduction

In these days of transition from one project to another, I started, with some perplexity to tell the truth, reading the Clean Code book which, as the name suggests, defines guidelines for writing clean code.
What does it mean to write clean code? Well, first of all write some code that is clear what it does at first glance. Although we often get pressure to deliver the required software, it is a good idea to write code that does not need to be explained, that you can get your hands on even after some time or that is clear even to those who have not developed that. part.

Let me be clear, my baseline start to the fact that:

Done is better than perfect

It is also true that writing “self-explanatory” and “self-documenting” code, requires only common sense and a few simple rules to follow.

In this way the speed with which we are able to release our artifacts is not affected, but it could even accelerate.

The book focuses on various aspects all more or less important, but which require more or less effort on the part of those who implement code and refer to Java code in its examples, but it can be easily adapted to any programming language you use.
This does not pretend to be an exhaustive overview of everything you will find in the book, but a flouring of some of the topics covered in the book.

Classes and methods

Let’s move, therefore, from advice on variable names that must be “pronounceable” and easily searchable within the code, to class names that must not be verbs, but names or phrases, for example WikiPage or Customer. For methods, however, it is better that they are verbs or sentences containing verbs, for example postPage:

The first rule of a class is that it should be as small as possible.

We do not count the lines of code as in the case of methods, but we do count the “responsibilities” and the name of the class should help to understand the responsibilities of it.

In this context, the Single Responsability Principle (SRP) is defined as the condition that a class or module should have one reason, and only one, to change.

An important piece of advice is that if we overload the constructor, it would be better to use static factory-type methods whose names allow us to describe the arguments with which we want to construct our object. For example:

We can even force this use by setting the corresponding constructor private (as is done in the Singleton pattern, for example).

Writing our code we must avoid duplication, because in this way we ensure its expressiveness and we can shrink the number of classes and methods.

Care is a precious resource.

Comments

Generally, well-documented code is better than one that isn’t, but that’s not always the case.

The book explains, in fact, how complicated it is to keep comments aligned with the code you write and the fact that it is easy, however, that a comment written at a given moment loses its effectiveness after some time and with the update. of the software, because by refactory the programmer generally does not bother to modify the comment too.

A separate mention must be made for the commented code, yes, the one that you don’t really know if it has to be deleted or not, because, although during coding it may happen that we have to use this technique to understand if a modification we have made has had the desired effects, it is also true that if it remains of the commented code we would not know if has been commented on for a reason or is just a typo by the programmer who left it.
As far as I’m concerned this is one of those situations in which I never know how to behave, because, in general, having absolute respect for the work of others, I tend to never delete commented code, but I believe that this is a very common practice ( apart from some cases that I will talk about in a future post).

Test

A separate discussion must be made for the tests. In the book it is written:

Test code is just as important as production code.

In general, unit tests (ie the tests we do to test a single functionality regardless of where it is integrated), allow for a flexible, maintainable and reusable code. The reason is quite simple. If you have tests that cover a large part of your code, you are not afraid to make changes to the code. Without testing, any small code changes could be a possible bug.

What makes a clean test? Three things. Readability, readability, and readability

A good rule of thumb for testing is that we need to test a single concept in each test function.

Object Vs Data Structure

Objects hide their data through abstraction and expose methods or functions that operate on data, while data structures expose their data and do not have functions that operate on data. I would like to dwell on this point a bit, because long ago I was told that a data structure must also have some logic that operates on them, but my thinking is more akin to that of the book, because the entities that hold the data structures data, in my opinion, should not have the methods to modify them (if not the classic setProperty ()).

The definition that makes objects and data structures complementary presents us with a dichotomy:

  • Procedural Code (code that uses data structures), gives the possibility to add new functions without modifying the data structures on which they operate, while the Object Oriented code allows to define new classes without having to modify the functions.
  • The procedural code makes it difficult to add new data structures because all functions will have to change. Object Oriented code makes it difficult to add new methods and functions, because the classes will have to change.

So what is complex in OO programming is made simple in procedural, while what is complex in procedural code is simple in OO.

The Law of Demeter. Demeter’s heuristic law states that a module should not know how an object it manipulates is implemented.

More precisely, this law says that a method f of a class C should call certain types of methods:

  • C.
  • An object created by f
  • An object passed as an argument to f
  • An object contained in an instance variable of C.

The method must not invoke methods on objects returned by any of the allowed functions. In other words:

Talk to friends, not strangers.

Design

A design is considered simple when it follows a simple rule: “run all tests”

A fully tested system that passes all tests at all times is termed testable.
Obviously this is an obvious definition, but very important, in fact systems that are not testable are not verifiable and probably a system that has not been properly verified should not be released.

Concurrency

Objects are abstractions of processing. Threads are abstractions of schedule.

Concurrency is a strategy that allows for decoupling. It allows you to decouple what needs to be done from the moment you do it.

One of the most difficult problems to manage in concurrency is when several processes (threads) access shared objects and this can create unexpected behavior.

A possible solution is the use of the synchronized keyword that allows you to protect critical sections that use shared objects. It is important to limit the number of these areas, because otherwise you could run into various problems.

  • We may forget to protect one of these critical areas.
  • Duplication of our efforts to make sure that everything is protected correctly (violation of the DRY principle: Don’t Repeat Yourself)
  • It will be difficult to determine the points in which the system has malfunctions (already difficult in itself to be found).

The recommendation in these cases is to limit access to data that could be shared, taking into account the encapsulation of them.

By allowing data to be copied, rather than having to access and synchronize shared data, it helps avoid blockages due to this way of managing data. This solution would compensate for the need to create new objects with the consequent overhead of garbage collection.
A further recommendation is to avoid using more than one method on a shared object.
There might be cases we can’t avoid it. When we are forced to face these situations we have three possible ways of managing:

  • Client-Based Locking: In this case the client sets the lock on a server before calling the first method and takes charge of the lock extending to the last method called.
  • Server-Based Locking: Inside the server we call a method that puts the lock on the server, calls all the necessary methods, and then releases the lock.
  • Adapted Server: We create a proxy that will take care of locking the necessary server methods.

However, you should always follow a recommendation, namely that you must keep the synchronized sections as small as possible.

I leave you with a sentence that should be underlined and that actually can make sense in a context such as the drafting of Clean Code.

To write clean code, you must first write dirty code and then clean it.

Conclusion

I found the book too slow in some parts, but very interesting and full of ideas in others.
I recommend it as a book to keep on the bedside table when you realize that your code is suffering from some problems of effectiveness, readability and maintainability.

--

--

Danilo Del Fio

Transparency, respect and self-discipline, mixed with great passion!