archivo

Archivo de la etiqueta: refactorización

La tentación, muchas veces motivada por las circunstancias, es obviar la mejora de la factura técnica del producto, para centrarnos en corregir errores y en incrementar las funcionalidades.

El usuario siente la calidad del software con lo que ve: cumplimiento de sus expectativas de funcionamiento y buen rendimiento y disponibilidad, por eso pondrá resistencia a invertir tiempo en reducir la deuda técnica.

No debemos olvidar que desarrollamos para el usuario y él es quien tiene la última palabra, lo cual no quita que le expongamos la ventaja que tiene la realización de este tipo de tareas, como una inversión que permita no solo incrementar la capacidad de trabajo que puede abordar el equipo, sino además, reducir la posibilidad de efectos colaterales que provoquen errores cuando y donde menos los esperamos.

De serie, un desarrollador debe tener en cuenta estas prácticas y tenerlo en cuenta a la hora de definir su velocidad. El tiempo que se puede dedicar a esto puede ser prácticamente ilimitado porque todo es susceptible de ser mejorado, por ese motivo, ese tiempo de más sobre las buenas prácticas de programación cotidiana es el que se tiene que discutir con el cliente.

Comenta Mary Poppendieck: “La refactorización continua no es opcional. Si se elige no refactorizar se elige no pagar la deuda técnica que con el tiempo demostrará que la posibilidad de fracaso aumenta”.

La clave es mantener la deuda técnica bajo control y esto requiere un esfuerzo desde la programación de base como de las tareas adicionales de refactorización, de acuerdo siempre con las necesidades de quién paga, el cual debe estar siempre informado de las consecuencias que tiene realizar desarrollos sobre un software de baja calidad.

Tal vez de base la pregunta esté mal planteada porque estamos tratando con dos conceptos que deberían ser complementarios y obligatorios en todo desarrollo de software: que el software permita trabajar al usuario con normalidad y que sea fácilmente mantenible.

Esto es la teoría y lo que en la práctica debería de llevarse a cabo. Sin embargo, siendo realistas gran parte de los proyectos en los que trabajamos están mal planteados (plazos y presupuestos insuficientes) y hay cambios de enfoque o prioridades que ponen más complicada todavía la situación de partida, ¿qué hacemos aquí?, dirigir los esfuerzos hacia un software que funcione aplicando buenas prácticas de programación para que el código de partida tenga la mayor calidad posible.

Lo ideal es que no se tenga que llegar a la situación de tener que prescindir de la refactorización pero no sería realista no contemplar ese escenario porque todos sabemos que existe y nos lo encontramos más veces de lo que desearíamos.

Como he comentado en reiteradas ocasiones, gran parte de la suerte del proyecto se juega al inicio, cuando se negocian las condiciones y como consecuencia de las mismas se establecen las primeras restricciones al proyecto (después vendrán más).

Esto no sería tan determinante si el cliente entendiera que el desarrollo de software es de naturaleza evolutiva en un entorno de incertidumbre lo que hace que la estimación económica y temporal inicial puedan quedar echas trizas a lo largo de la ejecución del proyecto. Incluso entendiéndolo, también tendrá en muchas ocasiones restricciones presupuestarias y de otra índole, de personas que están en otro nivel de la organización y que van a estar más lejos todavía de esa realidad (y estas a su vez pueden depender de otras que estén todavía más lejos y así sucesivamente).

También los proveedores tienen mucho que ver en esas condiciones cuando presentan o aceptan ofertas fuera de mercado.

En las situaciones de Death March Project donde la carga de trabajo te impide y bloquea la posibilidad de refactorización muchas veces suena la música de fondo por parte de los gestores (del cliente, del proveedor o de ambos) en las que habrá una segunda fase del proyecto que se basará principalmente en refactorizar.

¿Cuántas veces se cumple esto?.

Muy pocas o ninguna. La segunda fase no existirá o de existir el presupuesto se dirigirá a realizar evoluciones y parcheo del sistema, algo normal en proyectos hechos de esa forma y que requerirán también más esfuerzo al trabajar sobre un software con una deuda técnica alta.

Si la refactorización no forma parte del proceso quedará a la voluntad de los desarrolladores aplicarla o no.

Pero, ¿es la solución introducirla como elemento de proceso? La respuesta es difícil. Todo es mejor cuando surge de manera natural, cuando entiendes que el desarrollo de software se tiene que hacer de esa manera. Sin embargo, llegar a asumir que el código debe ser lo más mantenible e inteligible posible no es algo que se encuentra de serie en nuestro ADN.

Por mucho que nos cuenten tendremos que ser nosotros mismos los que entendamos que esta forma de trabajar es la correcta, esto se descubre a veces al poco tiempo de empezar a desarrollar, otras veces se tarda mucho más y en algunos casos no se compartirá nunca esta visión.

Refactorizar lleva tiempo pero en términos de coste/beneficio siempre será mucho más rentable hacerlo que dejar más deuda técnica sirviendo de resistencia. Sin embargo ese tiempo es el que termina muchas veces impidiendo refactorizar, ya que si te piden un Death March Project en el que en dos meses tengas que desarrollar un proyecto de seis, te dedicarás a ejecutar y ejecutar trabajo, cuanto más y cuanto antes mejor, ya que con jornadas maratonianas prácticamente todos los días, tu cabeza por muchas buenas ideas o prácticas que tenga consolidadas no querrá otra cosa que ver la luz al final del túnel.

La realidad en este caso vence al deseo natural de querer refactorizar. Esta realidad hace mucho daño a nuestro negocio pero no por ello debemos dejar de obviarla pese a que intentemos combatirla a diario.

Cuando se está realizando labores de mantenimiento de un sistema de información nos encontraremos muchas ocasiones en el contexto en que arreglando una funcionalidad o evolucionando el sistema vemos secciones del código “oscuras e ininteligibles” que funcionan no se sabe muy bien cómo y que cuando hay que tocarlas (porque no hay más remedio) buena parte del funcionamiento de la aplicación salta por los aires (porque además se suelen caracterizar por su alto acoplamiento).

Llegado el momento habrá que hacerse la pregunta, ¿resolvemos de una vez el problema o lo dejamos como está y vamos parcheando conforme se necesite?.

La respuesta puede o debería ser obvia: refactorizar y cuanto antes, sin embargo hay que entender también a quiénes en determinadas circunstancias toman la decisión de no hacerlo (más de una vez yo mismo he tomado esa decisión). Hay que tener en cuenta la criticidad del sistema y nuestra capacidad de respuesta ante posibles pasos a producción con efectos colaterales como consecuencia de esos cambios.

En el desarrollo de software hay que tomar decisiones y en muchas ocasiones tendremos que dejar a un lado nuestra propia filosofía de trabajo y optar por la solución que entendemos más adecuada (que podrá ser acertada o errónea) al contexto en el que nos encontramos (el desarrollo software es adaptación al cambio y también adaptación a las circunstancias).

El artículo publicado ayer en el que comentaba los beneficios de la refactorización, lo contextualicé con una cita de Ron Jeffries en la que venía a decir que una aplicación bien diseñada y programada de base podría convertirse en un elemento complicado de mantener si no se revisaba con la frecuencia necesaria el código, sobre todo en contextos iterativos, evolutivos o de mantenimiento del sistema.

Y es que queramos o no, si no se hace esta tarea el programa se convierte en un conjunto de parches cada uno de ellos con el sello de su programador y cada vez resulta más costoso de mantener a la vez de que se incrementarán las posibilidades de efectos colaterales.

Jeff Atwood realiza la siguiente cita que complementa perfectamente a la de Jeffries: “Si no te paras de vez en cuando (frecuentemente, en realidad) en revisar y limpiar el código que ya has escrito, terminará convirtiéndose en una gran y descuidada bola de código”.

No es necesario poner ejemplos sobre esto porque la mayoría de vosotros habréis tenido la oportunidad de padecer y sentir las consecuencias de código de baja calidad y/o parcheado. Pese a esto y como ya comenté en el artículo de ayer no se le presta en la mayoría de los casos la atención que se merece a la refactorización, algo que resulta todavía más sangrante cuando el producto que desarrollas es para tu organización ya sea de uso interno o para comercializarlo ya que en estos casos no se tiene la excusa de que el cliente no valora este tipo de esfuerzos.

La reducción de la deuda técnica y la mejora en la legibilidad del código, así como evitar la consolidación de antipatrones del tipo ancla de barco o lava seca son algunos de los objetivos principales de la refactorización.

Hay quienes incluyen la refactorización como una fase final del desarrollo de una determinada tarea y otros que la incluyen como tareas concretas. Habría que analizar qué es más conveniente en cada caso, lo que en cualquier caso resulta incontestable son los beneficios de la refactorización. Pese a ello, muchos equipos de desarrollo no la tienen en cuenta entre sus hábitos de desarrollo y muchos clientes no valoran la realización de este tipo de actividades (tal vez porque no se les ha explicado bien sus ventajas).

La siguiente cita de Ron Jeffries contextualiza perfectamente la refactorización: “La razón por la cocina es un desastre no es porque la cocina esté mal diseñada sino porque no se lavan los platos después de cada comida”.

Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.

Únete a otros 3.215 seguidores