miércoles, 6 de octubre de 2010

Code Smell - Codigo Duplicado

Queridos Chimpances entrenados, Recuerdan lo que eran los Code Smells?

Bien, si tuvieramos que entregar el Oscar a los Code Smells, el número uno, el primer premio se lo lleva sin dudarlo el código duplicado.

Codigo duplicado implica tener la lógica del sistema duplicada en dos o mas lados, en la misma o distintas clases, incluso en distintas capas.

Porque esto es malo?

El primer problema es que cuando tengamos que modificar el código duplicado (y SI,antes de que pregunten les digo: Vamos a tener que modificarlo con 100% de seguridad) es muy probable que nos olvidemos de cambiar alguna ocurrencia de la duplicación, introduciendo bugs.
En segundo lugar estamos salteando una relación de ese código con alguna de las clases. Es decir, a alguna clase realmente le corresponde ese comportamiento que está duplicado y en el resto de los lugares de la duplicación no estamos honrando está relación que mas pronto que temprano nos traerá problemas.
Es fundamentalmente en este sentido en que es un Code Smells de nuestro diseño. Algo malo esta pasando, falta un método y ese método debe ir en alguna clase lo cual causará un rediseño de nuestro sistema.
En tercer lugar el código duplicado produce que el código sea más dificil de leer y de entender.

Además, el código duplicado tiende a ser modificado de maneras ligeramente distintas en cada una de las copias, con lo que suele pasar que después de un tiempo ya no es trivial decir si dos fragmentos de código que originalmente eran duplicados siguen haciendo lo mismo o no.

En sintesis, el problema fundamental de tener la lógica duplicada es que hace al sistema más dificil de mantener, y ya sabemos que la mantenibilidad es la propiedad numero #1 que debemos procurar para nuestro codigo.

Ahora bien, la lógica duplicada a menudo se presenta en formas mucho más sutiles que una duplicacion literal de codigo, si bien hemos visto más de un ejemplo de estos.

Podemos encontrar los siguientes tipos (principales) de duplicacion de código:

1 - Duplicacion simple: Es la forma más común de duplicacion. Sucede cuando se tiene la misma expresión (identica o diferentes en variables) en dos métodos de la misma clase. La solución es aplicar el refactoring "Extract Method" extrayendo el código duplicado en un método privado y llamando desde ambos lugares de la duplicación al nuevo método.

2 - Duplicación en clases relacionadas : Es cuando se encuentra la misma expresión en dos o más subclases de una misma jerarquia de Clases. Es una duplicación bastante común también ya que provienen de comportamientos comunes de clases hermanas hijas de una misma Clase padre. La forma de solucionarlo es extraer el codigo duplicado en ambas subclases con "Extract Method" y luego si aplica a todas las subclases subirlo a la clase padre, si no aplica es una indicación de que hay un problema de diseño con la jerarquía de clases. A veces hay parte de una logica duplicada y otra parte no, en ese caso se puede convertir el método en un "Template Method" en la clase padre, abstracto y luego implementar la parte que es diferente en ambas subclases.

3 - Duplicación en clases no relacionadas : Como el titulo lo indica, es tener duplicación en dos métodos de dos clases A y B no relacionadas por herencia ni interfases. En este caso se debe considerar extraer el comportamiento duplicado en la clase A y generar una nueva clase C que contenga este codigo (refactoring "Extract Class") y luego reemplazar el código duplicado en la segunda clase B por una invocación a la nueva C. Otra posibilidad es que la lógica duplicada realmente pertenezca a una de las dos clases, y la otra debe invocar a la clase a la que pertenece el codigo. Una tercera posibilidad es que pertenezca a otra clase ya existente. Aplicando la Ley de Demeter, el Single Responsability Principle y el sentido común tenemos que encontrar el lugar adonde esta lógica pertenece y removerla de todo otro lugar.

4 - Duplicación en distintos lenguajes : Por ejemplo, validaciones que tenemos que hacer tanto en la GUI (por ejemplo en Javascript) y en el backend (por ejemplo en Fortran... :)). Este es un tipo de validación dificil de evitar. Una manera posible es escribir el código para uno de los lenguajes y generar el código del otro automáticamente a partir de este.

Para terminar les dejamos una regla práctica para aplicar cuando estamos ante una duplicación de código.

La regla del tres (Don Roberts)

La primera vez que uno escribe una lógica la escribe y listo. La segunda vez que uno hace algo similar debe fruncir el ceño, tomar nota y dejar la duplicacion de cualquier manera. La tercera vez que aparece la duplicación, bang!, uno debe eliminarla, a través de la refactorización.

Entonces, recuerden, Una de las Buenas Practicas de programación que más recomendamos es buscar todo Code Smell que encuentren en el codigo y removerlo a través de la refactorización.
Y si pensamos que el código duplicado es el origen de muchos males (Duplication is evil) y uno de los Code Smell más comunes, aprender a buscar, detectar y remover duplicaciones de código es una actividad a la que debemos aplicarnos si queremos convertirnos en Programadores (así con "P" mayúscula).

No hay comentarios:

Publicar un comentario