Code design: how to write a clean code?

Published by

Published by

Published at

    Categorias:

    Development
    Quality
 

It is usual that developers spend more time trying to understand a bad code than writing a new one. Due to the establishment of bad principles, during the reading and writing on a source code, we tend to spend 10 times more time trying to figure out a code that already exists than creating a new one.

Robert Cecil Martin, also known as Uncle Bob, is a reference to applying good practices in coding. The author has been working in the tech field since the 70s and was involved in creating the Agile manifesto (2001). In 2008, he wrote a book called Clean Code, in which there are many methods of software development regarding agile principles.

The greatest insight of his work is that maintenance is the main issue in software development. In other words, a running code that is badly written since its first version may cause huge damage.

Here we have listed the main steps to keep the code clean and understandable:

 

Nomenclature: names are important!

Name the variables in the descriptive form indicating what it stocks. A variable named as fn does not give any information, for example. However, naming the variable as fullName gives more information for who is reading and will be doing the maintenance of the code. Functions, classes and methods names follow the same principles of variables nomenclature.

// before
// after
// more improvements

Keep the code cleaner than it was

Either changing or maintaining a code that has been already written, try to keep it more semantic as it was. For instance, when refactoring variable names - breaking bigger functions into smaller functions - remove the obsolete comments.

// before
// after
 

Avoid repetitions

It is not ideal to repeat the code. If you are doing it in different places something can be improved. The modifications through the code should be applied in every place where the code is repeated as a way to avoid ambiguous ideas.

 

Smaller functions with only one responsibility

Function names should follow the same pattern as variable names which means being semantic and descriptive. Whenever it is possible the functions should have just one or a few

responsibilities. Smaller functions with a few branches can be reused in other places in a body of code. Thus, repetitions are avoided.

// before
function emailClients(clients) {
  clients.forEach((client) => {
    const clientRecord = database.get(client);
    if (clientRecord.isActive) {
      sendEmail(client);
    }
  });
}
// after
 

Comments

Avoid comments as much as possible! A well-written code does not need extended comments on various lines. In general, the code is updated, but the comments are not, causing a great misunderstanding.

A clean code shows by itself what is being performed.

// before
// after 
function throwsErrorIfUserDataIsInvalid (userData: UserDTO) {
  if (!isValidEmail(userData.email)) {
    throw new Error('Invalid email');
  }
  if (!isValidCpf(userData.cpf)) {
    throw new Error('Invalid cpf');
  }
  if (!isValidPhoneNumber(userData.phoneNumber)) {
    throw new Error('Invalid phone number');
  }
}
 
 

Error treatment

Ideally, the places in the body of the code where errors are more likely to occur should be treated in a specific way. Since they are unpredictable, dealing with them in a non-generic way might avoid hours of ‘bebug’.

// before
try {
  functionThatThrow();
} catch (error) {
  console.log(error);
}
// after
try {
  functionThatThrow();
} catch (error) {
  console.error(error);
  notifyUserError(error);
  reportErrorToService(error);
}
 

Tests

Tests should be able to be executed quickly, independently, and repeatedly in order to test deterministic conditions and pre-following the software development. Thus, the quality of what has been developed is more likely to be guaranteed.

Therefore, even though a system is considered ready and has been working properly, it is not completely done. There is always a need for updates and implementation of new features because the code gets old and becomes obsolete.

 

In summary, talking about coding a clean and easily maintained code involves creating a code with low coupling, high cohesion, using SOLID, applying Design Patterns, reducing side effects, maximizing pure functions, and so on. Thus, making a good code design is essential for code maintenance.