Podemos definir a los code smells como indicadores superficiales de posibles problemas en el sistema. Se tratan de estructuras que se pueden ver en el código y que sugieren la posibilidad de un refactor.
En esta nota trataremos de verlos en profundidad para identificarlos y solucionarlos rápidamente.
Bloaters: representan algo que ha crecido en proporciones tan grandes que resulta complejo tanto de entender como de manejar. Generalmente, se acumulan con el tiempo y no pueden ser detectados hasta que el programa evolucione. Son los siguientes:
Long Method: cualquiera puede notar que mientras más largo sea un procedimiento, más difícil va a ser entenderlo. Aún así, a la mayoría de los programadores les genera desconfianza achicar demasiado los métodos porque temen tener demasiados y que, al leer el código, haya que cambiar de contexto constantemente para saber lo que hace un submétodo. La clave para que los pequeños métodos sean fáciles de entender es nombrarlos bien, con una abstracción simple que permita saber lo que hacen. Sabiendo esto, no necesitaremos ir a ver el cuerpo del mismo y cambiar de contexto. Entonces, Martin Fowler nos dice que debemos ser más agresivos al descomponer los métodos. ¿Cómo identificarlo? Si creemos necesario comentar el código de un método para que se entienda mejor, probablemente debamos sacarlo y ponerlo en un nuevo método para volverlo más expresivo.
¿Cómo solucionarlo? El 99% de las veces usaremos el refactor Extract Method. Si interfieren parámetros y variables locales, podemos emplear otros refactors para usar objetos de parámetros y reemplazar variables temporales con métodos.
Large Class: ¿Cómo identificarlo?Una clase intenta tomar demasiadas responsabilidades, por lo que debería seguir el principio de single responsibility, o sea, cumplir solamente con una de las funcionalidades del software y estar bien encapsulada. Generalmente, muestran demasiadas variables de instancia y código duplicado entre métodos.
¿Cómo solucionarlo? Debemos usar el refactor Extract Class para extraer un conjunto de variables que puedan ir juntas con un nombre descriptivo. Así, evitaríamos el primitive obsession (que ya veremos). También podemos extraer subclases si parte del comportamiento puede ser usado de distintas formas, o extraer una interfaz si se requiere una lista de comportamientos para el cliente. Preserve Whole Object puede servir si hay parámetros que evitan que se pueda extraer la clase.
Primitive Obsession: en realidad es más un síntoma que genera bloats que un bloat en sí mismo. Cuando existe, no hay clases pequeñas para entidades pequeñas (como números de teléfono) y se emplean muchas constantes. Como parece más fácil que crear una nueva clase, se empiezan a acumular. Los data clumps también son causa de bloating: distintas partes del código usan los mismos grupos de variables. Suele pasar cuando se hace mucho copy-paste, por lo que es importante evitar estas malas prácticas para no generar bloats ¿Cómo identificarlo? Por el uso de constantes para la codificación de la información y el uso de las constantes de cadena como nombres de campo para su uso en arreglos de datos ¿Cómo solucionarlo? Si se nos presenta una buena variedad de campos primitivos, podemos agrupar algunos en su propia clase o mover el comportamiento asociado con esta data también a la misma clase. Para hacer esto, podemos probar reemplazando el valor de datos con objeto. Cuando los datos se codifican de modo complicado en las variables, podemos reemplazar código tipo por clases o subclases. Si se nos presentan arreglos entre las variables, debemos hacer el reemplazo de matiz con objeto
Long Parameter List: aparecen cuando un método es muy largo o cuando se intenta independizar a las clases. Pero al delegar menos entre clases, necesitamos utilizar demasiados parámetros para que el método tenga lo que precisa para actuar. De todos modos, nunca hay que pasarle a un método todo lo que necesita, si no lo necesario para que pueda conseguir lo que precisa ¿Cómo identificarlo? Cuando tenemos más de tres o cuatro parámetros para un método ¿Cómo solucionarlo? Debemos chequear los valores pasados como parámetro. Generalmente basta con reemplazar el parámetro con una llamada a otra clase y en vez de pasar una lista de variables como parámetro, debemos enviar el objeto entero. A veces se pueden juntar varios parámetros en un solo objeto antes de ser enviados, como un rango de fechas en vez de fecha de inicio y fin.
Object-Orientation Abusers: la solución a ellos no hace uso de todas las posibilidades que nos ofrece la programación orientada a objetos. Por ejemplo, un switch en objetos es, digámoslo, horrible. Debería entonces hacerse uso del polimorfismo. Repasemos algunos de los object-orientation abusers:
Refused bequest: ¿cómo identificarlo? Una subclase usa sólo algunos de los métodos y atributos de sus superclases. Alguien, probablemente, quiso reutilizar código, pero la jerarquía está mal utilizada porque las clases son totalmente diferentes