Código limpio explicado: una introducción práctica a la codificación limpia para principiantes

"Cualquier tonto puede escribir código que una computadora pueda entender. Los buenos programadores escriben código que los humanos pueden entender ". Martin Fowler

Escribir código limpio, comprensible y fácil de mantener es una habilidad crucial que todo desarrollador debe dominar.

En esta publicación, veremos los principios más importantes para mejorar la calidad del código y le daré ejemplos de código para cada uno de ellos.

La mayoría de los ejemplos se toman del Código limpio de Robert J. Martin . Es un clásico de la programación y te sugiero que leas el texto completo cuando tengas tiempo.

Cómo nombrar variables (y otras cosas)

"Sólo hay dos cosas difíciles en la informática: invalidación de caché y nombrar cosas". - Phil Karlton

Hay una razón por la que no usamos direcciones de memoria y en su lugar tenemos nombres: los nombres son mucho más fáciles de recordar. Y, lo que es más importante, pueden brindarle más información sobre la variable, para que otra persona pueda comprender su significado.

Puede llevar algún tiempo encontrar un buen nombre, pero les ahorrará a usted y a su equipo aún más tiempo en el futuro. Y estoy seguro de que la mayoría de los lectores se han enfrentado a la situación en la que visita su código solo unos meses después y tiene dificultades para comprender lo que hizo antes.

Cómo crear nombres significativos

No utilice comentarios para explicar por qué se utiliza una variable. Si un nombre requiere un comentario, entonces debe tomarse su tiempo para cambiar el nombre de esa variable en lugar de escribir un comentario.

"Un nombre debe decirle por qué existe, qué hace y cómo se usa. Si un nombre requiere un comentario, entonces el nombre no revela su intención". - Código limpio

Malo:

var d; // elapsed time in days

He visto este tipo de código muchas veces. Es un error común pensar que debe ocultar su desorden con comentarios. No use letras como x, y, a o b como nombres de variables a menos que haya una buena razón (las variables de ciclo son una excepción a esto).

Bueno:

var elapsedTimeInDays; var daysSinceCreation; var daysSinceModification;

Estos nombres son mucho mejores. Te dicen qué se está midiendo y la unidad de esa medida.

Evite la desinformación

Tenga cuidado con las palabras que significan algo específico. No se refiera a una agrupación de cuentas como accountList a menos que su tipo sea realmente una Lista. La palabra tiene un significado específico y puede llevar a conclusiones falsas.

Incluso si el tipo es una lista, las cuentas son un nombre mejor y más simple.

Malo:

var accountList = [];

Bueno:

var accounts = []

Evite las palabras ruidosas

Las palabras irrelevantes son las palabras que no ofrecen información adicional sobre la variable. Son redundantes y deben eliminarse.

Algunas palabras irrelevantes populares son:

  • El (prefijo)
  • Info
  • Datos
  • Variable
  • Objeto
  • Gerente

Si su clase se llama UserInfo, puede simplemente eliminar la información y convertirla en usuario. Usar BookData en lugar de Book como nombre de clase es una obviedad, ya que una clase almacena datos de todos modos.

También puede leer la publicación del blog de Jeff Atwood sobre los nombres de SomethingManager aquí.

Utilice nombres pronunciables

Si no puede pronunciar un nombre, no puede discutirlo sin sonar tonto.

Malo:

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

Bueno:

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

Usar nombres que se pueden buscar

Evite el uso de números mágicos en su código. Opte por constantes con nombre que se puedan buscar. No utilice nombres de una sola letra para las constantes, ya que pueden aparecer en muchos lugares y, por lo tanto, no se pueden buscar fácilmente.

Malo:

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

Bueno:

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

Esto es mucho mejor porque MAX_CLASSES_PER_STUDENT se puede usar en muchos lugares del código. Si necesitamos cambiarlo a 6 en el futuro, podemos simplemente cambiar la constante.

El mal ejemplo crea interrogantes en la mente del lector, como ¿cuál es la importancia del 7?

También debe hacer uso de las convenciones constantes de nomenclatura y declaración de su lenguaje, como private static final en Java o const en JavaScript.

Se consistente

Siga una palabra para cada regla de concepto . No utilice buscar , recuperar y obtener para la misma operación en diferentes clases. Elija uno de ellos y utilícelo en todo el proyecto para que las personas que mantienen el código base o los clientes de su API puedan encontrar fácilmente los métodos que están buscando.

Cómo escribir funciones

Mantenlos pequeños

Las funciones deben ser pequeñas, realmente pequeñas. Rara vez deben tener 20 líneas. Cuanto más dura una función, es más probable que haga varias cosas y tenga efectos secundarios.

Asegúrese de que solo hagan una cosa

Las funciones deberían hacer una cosa. Deberían hacerlo bien. Solo deberían hacerlo. - Código limpio

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.