jueves, 6 de octubre de 2011

Refactoritis


Hoy vamos a tratar una enfermidad muy común de los programadores "experimentados": La Refactoritis.

La refactorización se lleva haciendo durante décadas. No es algo nuevo, a pesar de que siempre se cite al bueno de Martin Fowler como referencia, en su libro "Refactoring: Improving the Design of Existing Code". Si no conocéis a Martin Fowler y os dedicáis a la informática, no sé a qué esperáis para leer este libro y saber un poco más de este autor.

La refactorización se define en la Wikipedia como "técnica de la ingeniería del software para reestructurar un código fuente, alterando su estructura interna sin cambiar su comportamiento externo". Es en estos momentos cuando muchos de vosotros estaréis asintiendo con la cabeza y pensando en frases como "pues yo refactorizo mucho o poco", "yo no lo veo una enfermedad", etc, etc.

¿Y qué sería en ese caso la Refactoritis? Pues la podríamos definir como el "trastorno compulsivo que deriva en el uso excesivo de la refactorización del código". Vamos, cuando se le va la mano al programador y no para hasta que ha llegado al final del código, y lo ha dejado todo "a su gusto".

Como hemos visto antes, la refactorización no cambia la funcionalidad. Es decir, no se aporta valor al producto desde el punto de vista de los requisitos. En la metodología SCRUM, estaríamos dedicando horas de trabajo sin implementar ninguna "historia de usuario". En realidad, sería una forma de procrastinación: no hacemos algo que se haya solicitado, sino que estamos haciendo algo que nos gusta o nos parece subjetivamente agradable o necesario. Por supuesto que habrá ocasiones en que sí se ha creado una tarea a realizar de refactorización, pero en esos casos nos deberíamos preguntar si realmente no deberíamos atajar la causa del problema: no generamos código de calidad según estándares, lo que obliga a refactorizar después.

La refactoritis deriva en múltiples problemas. Veamos primero las necesidades que nos pueden llevar a refactorizar el código, y vamos a discutirlas una a una:
  • Calidad. Esta suele ser una de las excusas más usadas. Estamos creando calidad, mejorando la calidad. Y como no sabemos medir la calidad, no hay límite para nuestras ansias de refactorizar. Podemos seguir refactorizando hasta que nuestra sensación subjetiva de calidad consuma el tiempo de desarrollo. Algunos autores defienden que el código de calidad es bueno, y que mientras se satisfagan las pruebas unitarias, no pasa nada. El problema, es que las pruebas unitarias no son perfectas, lo que puede derivar en que a pesar de que "todo parece ir bien" tras refactorizar, en realidad estamos introduciendo bugs en el código.
  • Mala planificación. En ocasiones, se planifica en exceso. Los programadores cuando se encuentran con que han terminado una tarea antes de la fecha planificada pueden hacer varias cosas. O buscan una nueva tarea, o tratan de llenar el tiempo de la tarea terminada. ¿Cómo? Pues refactorizando: mejorando comentarios, encapsulando, quitando código duplicado, etc.
  • Eficiencia. Supuestamente, un código refactorizado es más eficiente. Además, se supone que se entiende mejor y es más claro. Esto último es muy dudoso, ya que es muy fácil refactorizar código y dejarlo de forma que sea muy compleja de entender. En este caso, si no medimos la eficiencia, ocurriría lo mismo que con la calidad. Podemos pegarnos la vida intentando ser más eficientes, que como no se mide esa mejora en eficiencia...no hay límites a nuestra refactoritis.
  • Evolución. A veces, cambios en las normas de programación, en requisitos de calidad, etc., hacen que debamos refactorizar el código para que se cumplan las nuevas normas. Debemos recordar que salvo excepciones, el cliente paga por funcionalidades, no por la refactorización del código. Si no tenemos claras nuestras normas de desarrollo...mal asunto.
  • Evitar la reescritura de código. Es muy discutible que un código refactorizado sea mejor que un código reescrito. Deben establecerse las necesidades, y evaluar qué solución merece la pena en uno y otro caso. Si refactorizar es la alternativa a la reescritura de código, en realidad tenemos un problema mayor: el mero hecho de plantearnos reescribir el código significa que un tiempo invertido en el desarrollo "va a la basura". Los paños calientes y las vendas no van a ocultar que tenemos un problema mayor.
¿Cuáles son las prácticas que deberíamos aplicar?
  • No tocar el código que no se ha solicitado tocar.
  • No tocar el código para el que no se han definido pruebas (automatizadas o no).
  • No tocar el código sin antes realizar un análisis del coste (horas necesarias) para su refactorización, y definirlo como una tarea. Sólo así podremos controlar el tiempo necesario en rehacer las cosas una y otra vez. No deberíamos dedicar más horas de las estimadas a refactorizar, ni tocar más código del inicialmente identificado. Si no conocemos el alcance de nuestras acciones, no sabemos hacia dónde vamos.
  • El código se debe refactorizar ANTES de pasar las pruebas, en la actividad de verificación. Las pruebas son muy costosas (incluso automatizadas), por lo que deberíamos pensar dos veces antes de tocar un código que ha pasado ya las pruebas.
  • No tocar el código que afecte a otros desarrollos (en curso o en producción), sin antes hacer una evaluación del impacto y recibir la aprobación correspondiente. En muchas ocasiones, algo que funciona correctamente según las pruebas unitarias, al subirlo a producción ROMPE OTROS DESARROLLOS con los que interactuaba.

No hay comentarios:

Publicar un comentario