← Volver

De qué hablo cuando hablo de refactorizar

Refactorizar mejora gradualmente el diseño interno del software y, junto con las pruebas, ayuda a construir aplicaciones más comprensibles, mantenibles y fáciles de evolucionar.

Refactoring

Me propongo aclarar algunos términos.

Cuando comenzamos un nuevo proyecto de software, sea cual sea el tipo de aplicación, rara vez sabemos con exactitud cómo lo vamos a implementar. Me refiero a qué estructura de clases tendrá, cuál será la mejor forma de organizar los recursos del proyecto, qué interfaces surgirán e incluso qué decisiones de diseño y arquitectura tendremos que tomar. Como mucho, tendremos una idea aproximada, pero no conoceremos la forma completa y exacta que adoptará la solución.

Es cierto que, con el tiempo y la experiencia, uno va teniendo una idea más clara antes de empezar, según el tipo de proyecto y de aplicación.

Por tanto, en realidad no sabremos cuál es la mejor forma de hacer las cosas hasta que empecemos a implementar funcionalidad. Es otra versión de aquello de «caminante, no hay camino: se hace camino al andar».

Puedo asegurar esta ley universal: la primera aproximación nunca es la mejor.

Lo peor que le puede ocurrir a una aplicación es quedarse exactamente tal y como surgió en su implementación inicial, sin refinar ni mejorar nada de su estructura ni de su diseño. Y cuando hablo de una aplicación, podemos bajar de nivel a una biblioteca, un módulo, una clase o un método: el principio sigue siendo el mismo.

Construir una aplicación de calidad es un proceso de mejora incremental y continuo y, en realidad, siempre quedará algo por mejorar.

Todo se complica cuando vamos añadiendo más y más funcionalidad, a veces incluso alguna que no esperábamos ni imaginábamos. Es algo completamente natural en el desarrollo de software, pero el peor error que podemos cometer es añadir esa funcionalidad al esqueleto existente de cualquier manera. Con el tiempo, estaremos preparando el terreno para una aplicación inmantenible, difícil de entender y de evolucionar.

Refactorizar es esencial para evitar esa situación. Cuando hablamos de refactorizar, nos referimos específicamente a aplicar determinadas técnicas que mejoran el microdiseño del código que hemos escrito. Son pequeños pasos, cada uno de los cuales mejora un aspecto diminuto de la solución.

Por extensión, también hablamos de refactorizar como sinónimo de mejorar cualquier elemento de una aplicación. Está bien extender el concepto, aunque originalmente se refiere exclusivamente a la aplicación de técnicas muy concretas y bien documentadas para mejorar el código. Por eso, aunque no sea del todo preciso, también se entiende qué queremos decir cuando hablamos de refactorizar el diseño de una base de datos, un script u otra cosa.

Ahora bien, ¿para qué refactorizar si un fragmento de código o la solución completa «ya funciona»?

Toda solución de software debe diseñarse para que pueda admitir cambios con facilidad, algo que tiene un 99 % de probabilidades de ocurrir. Por tanto, refactorizar nos permite tener una aplicación con mejor diseño y estructura, más comprensible y más fácil de mantener.

Pero también hay aspectos sutiles que solo se aprenden con la experiencia: al refactorizar, conseguimos que el código se pueda probar mejor, pero también sucede lo contrario: el interés por escribir pruebas nos lleva a la necesidad de refactorizar, consciente o inconscientemente. Este es uno de los aspectos del desarrollo de software que más me gustan, porque muchos elementos de la naturaleza del código son sutiles y hay que aprender a reconocerlos.

Refactorizar va de la mano de dos conceptos, y está tan unido a ellos que es imposible hablar de una cosa sin la otra: la orientación a objetos y las pruebas.

Una aplicación programada en un lenguaje orientado a objetos puede tener una mejor estructura y ofrecer una mejor solución, porque nos permite abstraer un problema en entidades mentales más comprensibles para nuestra forma de pensar: los objetos. Por su parte, las pruebas son un requisito ineludible para garantizar la calidad y el correcto funcionamiento de la aplicación.

Si cambiamos algo en el código, por mínimo que sea, ¿cómo sabemos que todo sigue funcionando? Exacto: con pruebas.

Por tanto, aplicar técnicas de refactorización en una aplicación que no está suficientemente cubierta y respaldada por pruebas es imposible o incluso peligroso.

En el desarrollo de software no es una buena práctica dejar cualquier mejora para el final. Es más productivo incorporarla al trabajo cotidiano, como parte de la propia actividad de desarrollo. Eso dice la teoría, pero también lo he comprobado durante todos estos años. Mejorar el código continuamente permite, sin ninguna duda, alcanzar una mayor velocidad de desarrollo.

Es decir, las técnicas de refactorización se aplican de forma continua e incremental. Resulta sorprendente cómo cambios diminutos en una aplicación pueden tener un efecto enorme y acumulativo en el producto final.

Desde que este concepto apareció en el libro de Martin Fowler y Kent Beck, se han documentado muchas técnicas, y distintos autores han propuesto muchas otras desde que nuestra industria asumió que el código debe mejorarse continuamente mediante pequeños pasos incrementales.

Incluso una aplicación que nunca se haya refactorizado de esta manera y que no tenga una buena cobertura de pruebas puede mejorarse, aunque haya que empezar la refactorización desde cero y avanzar poco a poco.

Si quieres saber más sobre refactoring, explico las técnicas más comunes en mi último trabajo, El Libro Práctico del Programador Ágil, junto con infinidad de prácticas esenciales para crear código de calidad.