¿Qué son los code smells?
A todos nos ha pasado: abrimos el refrigerador y nos llega una oleada indeterminada de podredumbre. En ese momento nos ponemos en nuestro rol de sabueso, haciendo un assessment organoléptico producto por producto. Ah, es el bloque de queso que se convirtió en un zoológico fúngico otra vez. A la basura.
En el software pasa algo parecido. El código no tiene olor, pero puede apestar fácilmente. Existen pistas de que ciertos pedazos de código funcionan, pero no están bien diseñados. A esto se les suele llamar code smells. Y nunca son buenos smells.
Mientras uno va aprendiendo en el rol de ingeniero de software, uno deja de “tirar líneas de código” para empezar a diseñar código. Esto no solo es branding para buscar un aumento de sueldo. Significa ir formando una intuición de cosas que funcionan bien y cosas que no. Idealmente se llega al punto en el que revisando el código de alguien con menos experiencia se gatillan todas las alarmas al ver algo feo. La idea será hacer una reescritura del código antes de que se publique en producción.
¿Y cómo se ven?
Vienen en muchos sabores y colores. Pero algunos de los más típicos son:
- Clase / Función muy larga: tal como suena. Hay una función que tiene 250 líneas y es doloroso entender qué hace. Probablemente calcula lo que le piden, pero además aprovecha de calcular tu devolución de impuestos, te hace un café y quizás qué más. ¿Cómo remediarlo? Aplicando el principio de Single responsibility: una función debe hacer una sola cosa. Si la función se llama calculatePriceAndMakeCoffeeAndDoYourTaxes probablemente tienes un problema.
- Código duplicado: el mismo código (o uno sospechosamente similar) aparece en dos o más lugares del código. Es decir, si cambia un supuesto o requerimiento en el futuro (spoiler: it will), el código deberá cambiarse en todos esos lugares. Y si no se cambia en todos los lugares, las inconsistencias pueden brotar como malezas. ¿Cómo remediarlo? Ponerse el sombrero ecológico y reutilizar el código en todos los lugares que tenga sentido.
- Generalización especulativa: esto ocurre cuando construimos muchas cosas que “se ocuparán a futuro”. Es decir, muchas cosas que no se ocupan ahora y que quizás tendremos que eliminar. Por supuesto que es importante mantener la flexibilidad para desarrollos futuros. Pero el tiempo del programador es valioso, por lo que debería dedicarlo a programar las cosas que definitivamente se ocuparán ahora. Lo peor es que —además del tiempo perdido— la complejidad del código probablemente aumente, y con esto la legibilidad se desplome. Ocurre cuando en vez de hacer un desarrollo iterativo, donde al producto se le van agregando funcionalidades de manera incremental y acotada, nos lanzamos a crear cosas que quizás no necesitemos. ¿Cómo lo remediamos? Crear features cuando se necesitan. Convencerse de que flexibilidad no es igual a programar por si acaso.
Fuente: https://xp123.com/articles/speculative-generality/
¿Y por qué ocurren?
- Porque a veces somos ignorantes.
- Porque es más rápido hacer algo de una mala manera antes que reorganizar todo el código.
- Porque estamos desconcentrados.
- Porque el feature era para ayer.
- Porque la peer review se fijó en errores ortográficos y no en la estructura.
O simplemente porque no existe el código perfecto, y perseguirlo es carísimo (y lo opuesto a la agilidad que busca el buen software).
En conclusión
La distancia entre el (teórico) software perfecto y el actual se llama deuda técnica. Y, como cualquier tipo de deuda, puede permitirnos crecer rápidamente o arruinarnos por completo. Una de las responsabilidades del equipo de ingeniería es entender cuándo y dónde vale la pena dejar un poco de deuda técnica y en qué casos es inaceptable. Pero si entrenamos nuestra intuición o “nariz” para los code smells, nunca publicaremos un código subóptimo sin darnos cuenta: solo lo dejaremos pasar en situaciones muy particulares.
Y, en cuanto tengamos un minuto libre, podremos aplicarnos en mejorar un poco la base de código. Así vamos pagando la deuda, poco a poco, mientras nuevos desarrollos insertan nueva deuda.