Clean Code Explained - Une introduction pratique au Clean Coding pour les débutants

"N'importe quel imbécile peut écrirecode qu'un ordinateur peut comprendre. Les bons programmeurs écrivent du code que les humains peuvent comprendre. "- Martin Fowler

Ecrire un code propre, compréhensible et maintenable est une compétence que chaque développeur doit maîtriser.

Dans cet article, nous examinerons les principes les plus importants pour améliorer la qualité du code et je vous donnerai des exemples de code pour chacun d'entre eux.

La plupart des exemples sont tirés du Clean Code de Robert J. Martin . C'est un classique de la programmation et je vous suggère de lire l'intégralité du texte lorsque vous en avez le temps.

Comment nommer des variables (et autres)

"Il n'y a que deux choses difficiles en informatique: l'invalidation du cache et la dénomination des choses." - Phil Karlton

Il y a une raison pour laquelle nous n'utilisons pas d'adresses mémoire et avons des noms à la place: les noms sont beaucoup plus faciles à rappeler. Et, plus important encore, ils peuvent vous donner plus d'informations sur la variable, afin que quelqu'un d'autre puisse comprendre sa signification.

Cela peut prendre un certain temps pour trouver un bon nom, mais cela vous fera gagner encore plus de temps à vous et à votre équipe à l'avenir. Et je suis sûr que la plupart des lecteurs ont été confrontés à la situation où vous visitez votre code seulement quelques mois plus tard et avez du mal à comprendre ce que vous faisiez auparavant.

Comment créer des noms significatifs

N'utilisez pas de commentaires pour expliquer pourquoi une variable est utilisée. Si un nom nécessite un commentaire, vous devriez prendre votre temps pour renommer cette variable au lieu d'écrire un commentaire.

"Un nom doit vous dire pourquoi il existe, ce qu'il fait et comment il est utilisé. Si un nom nécessite un commentaire, alors le nom ne révèle pas son intention." - Code propre

Mal:

var d; // elapsed time in days

J'ai vu ce type de code tant de fois. C'est une idée fausse courante que vous devriez cacher votre désordre avec des commentaires. N'utilisez pas de lettres comme x, y, a ou b comme noms de variables à moins qu'il n'y ait une bonne raison (les variables de boucle sont une exception à cela).

Bien:

var elapsedTimeInDays; var daysSinceCreation; var daysSinceModification;

Ces noms sont tellement meilleurs. Ils vous indiquent ce qui est mesuré et l'unité de cette mesure.

Évitez la désinformation

Faites attention aux mots qui signifient quelque chose de spécifique. Ne faites pas référence à un regroupement de comptes comme accountList sauf si son type est en fait une liste. Le mot a une signification particulière et peut conduire à de fausses conclusions.

Même si le type est une liste, les comptes sont un nom plus simple et meilleur.

Mal:

var accountList = [];

Bien:

var accounts = []

Évitez les mots de bruit

Les mots de bruit sont les mots qui n'offrent aucune information supplémentaire sur la variable. Ils sont redondants et doivent être supprimés.

Certains mots de bruit populaires sont:

  • Le (préfixe)
  • Info
  • Les données
  • Variable
  • Objet
  • Directeur

Si votre classe s'appelle UserInfo, vous pouvez simplement supprimer les informations et en faire un utilisateur. Utiliser BookData au lieu de Book comme nom de classe n'est qu'une évidence, car une classe stocke de toute façon des données.

Vous pouvez également lire l'article de blog de Jeff Atwood sur la dénomination de SomethingManager ici.

Utiliser des noms prononçables

Si vous ne pouvez pas prononcer un nom, vous ne pouvez pas en discuter sans paraître idiot.

Mal:

const yyyymmdstr = moment().format("YYYY/MM/DD"); 

Bien:

const currentDate = moment().format("YYYY/MM/DD");

Utiliser des noms interrogeables

Évitez d'utiliser des nombres magiques dans votre code. Optez pour des constantes nommées et consultables. N'utilisez pas de noms à une seule lettre pour les constantes car elles peuvent apparaître à de nombreux endroits et ne sont donc pas facilement consultables.

Mal:

if (student.classes.length < 7) { // Do something }

Bien:

if (student.classes.length < MAX_CLASSES_PER_STUDENT) { // Do something }

C'est bien mieux car MAX_CLASSES_PER_STUDENT peut être utilisé à de nombreux endroits dans le code. Si nous devons le changer à 6 à l'avenir, nous pouvons simplement changer la constante.

Le mauvais exemple crée des points d'interrogation dans l'esprit du lecteur, comme quelle est l'importance de 7?

Vous devez également utiliser les conventions de dénomination et de déclaration constantes de votre langage, telles que private static final en Java ou const en JavaScript.

Être cohérent

Suivez le mot unique pour chaque règle conceptuelle . N'utilisez pas fetch , retrieve et get pour la même opération dans différentes classes. Choisissez l'un d'entre eux et utilisez-le partout dans le projet afin que les personnes qui gèrent la base de code ou les clients de votre API puissent facilement trouver les méthodes qu'ils recherchent.

Comment écrire des fonctions

Gardez-les petits

Les fonctions doivent être petites, vraiment petites. Ils devraient rarement faire 20 lignes. Plus une fonction est longue, plus elle est susceptible de faire plusieurs choses et d'avoir des effets secondaires.

Assurez-vous qu'ils ne font qu'une chose

Les fonctions doivent faire une chose. Ils devraient bien le faire. Ils devraient le faire seulement. - Code propre

Your functions should do only one thing. If you follow this rule, it is guaranteed that they will be small. The only thing that function does should be stated in its name.

Sometimes it is hard to look at the function and see if it is doing multiple things or not. One good way to check is to try to extract another function with a different name. If you can find it, that means it should be a different function.

This is probably the most important concept in this article, and it will take some time to get used to. But once you get the hang of it, your code will look much more mature, and it will be more easily refactorable, understandable, and testable for sure.

Encapsulate Conditionals in Functions

Refactoring the condition and putting it into a named function is a good way to make your conditionals more readable.

Here is a piece of code from a school project of mine. This code is responsible for inserting a chip on the board of the Connect4 game.

The isValidInsertion method takes care of checking the validity of the column number and allows us the focus on the logic for inserting the chip instead.

public void insertChipAt(int column) throws Exception { if (isValidInsertion(column)) { insertChip(column); boardConfiguration += column; currentPlayer = currentPlayer == Chip.RED ? Chip.YELLOW : Chip.RED; } else  if (!columnExistsAt(column)) throw new IllegalArgumentException(); else if (isColumnFull(column - 1)  }

Here is the code for isValidInsertion, if you are interested.

 private boolean isValidInsertion(int column) { boolean columnIsAvailable = column = 1 && numberOfItemsInColumn[column - 1] < NUM_ROWS; boolean gameIsOver = getWinner() != Chip.NONE; return columnIsAvailable && !gameIsOver; } 

Without the method, if condition would look like this:

if (column = 1 && numberOfItemsInColumn[column - 1] < NUM_ROWS && getWinner() != Chip.NONE)

Gross, right? I agree.

Fewer Arguments

Functions should have two or fewer arguments, the fewer the better. Avoid three or more arguments where possible.

Arguments make it harder to read and understand the function. They are even harder from a testing point of view, since they create the need to write test cases for every combination of arguments.

Do not use Flag Arguments

A flag argument is a boolean argument that is passed to a function. Two different actions are taken depending on the value of this argument.

For example, say there is a function that is responsible for booking tickets to a concert and there are 2 types of users: Premium and Regular. You can have code like this:

 public Booking book (Customer aCustomer, boolean isPremium) { if(isPremium) // logic for premium book else // logic for regular booking }

Flag arguments naturally contradict the principle of single responsibility. When you see them, you should consider dividing the function into two.

Do Not Have Side Effects

Side effects are unintended consequences of your code. They may be changing the passed parameters, in case of passing by reference, or maybe changing a global variable.

The key point is, they promised to do another thing and you need to read the code carefully to notice the side-effect. They can result in some nasty bugs.

Here is an example from the book:

public class UserValidator { private Cryptographer cryptographer; public boolean checkPassword(String userName, String password) { User user = UserGateway.findByName(userName); if (user != User.NULL) { String codedPhrase = user.getPhraseEncodedByPassword(); String phrase = cryptographer.decrypt(codedPhrase, password); if ("Valid Password".equals(phrase)) { Session.initialize(); return true; } } return false; } }

Can you see the side-effect of this function?

It is checking the password, but when the password is valid, it is also initializing the session which is a side-effect.

You can change the name of the function to something like checkPasswordAndInitializeSession to make this effect explicit. But when you do that, you should notice that your function is actually doing two things and you should not initialize the session here.

Don't Repeat Yourself

Code repetition may be the root of all evil in software. Duplicate code means you need to change things in multiple places when there is a change in logic and it is very error prone.

Use your IDE's refactoring features and extract a method whenever you come across a repeated code segment.

Bonus

Do not leave code in comments

Please, do not. This one is serious because others who see the code will be afraid to delete it because they do not know if it is there for a reason. That commented out code will stay there for a long time. Then when variable names or method names change, it gets irrelevant but still nobody deletes it.

Just delete it. Even if it was important, there is version control for that. You can always find it.

Know your language's conventions

You should know your language's conventions in terms of spacing, comments, and naming things. There are style guides available for many languages.

For example, you should use camelCase in Java but snake_case in Python. You put opening braces on a new line in C# but you put them on the same line in Java and JavaScript.

These things change from language to language and there is no universal standard.

Here are some useful links for you:

  • Python Style Guide
  • Google's Javascript Style Guide
  • Google Java Style Guide

Conclusion

Clean coding is not a skill that can be acquired overnight. It is a habit that needs to be developed by keeping these principles in mind and applying them whenever you write code.

Thank you for taking your time to read and I hope it was helpful.

If you are interested in reading more articles like this, you can subscribe to my blog.