Trabajando con código legacy: Sprout methods

El código legacy es ineludible.

Por más que procuremos crear la arquitectura perfecta, que tengamos cuidado al crear código nuevo, que tengamos todo el tiempo del planeta para vertebrar nuestro código perfectamente… Tarde que temprano brotan inconvenientes.

El código que una vez fue creado para solventar un inconveniente, ahora debe solventar otros muy diferentes

¿Cuáles son las causas de la aparición de código legacy?

Por norma general acostumbra a surgir por el hecho de que por más que procuremos pronosticar el futuro, al final aparecen casos de empleo con los que no contamos, funcionalidades que cambian, otras que surgen…

Y el código que una vez fue creado para solventar un inconveniente, ahora debe solventar otros diferentes.

Con el tiempo, todas y cada una estas pequeñas inconsistencias van a hacer que debamos pelearnos con un código que ya no es el ideal para solventar el inconveniente que soluciona.

Y esto es en el mejor caso. En el peor, deberás pelearte con código que estuvo mal desarrollado desde sus principios.

La problemática de trabajar con código legacy

Lo idóneo sería que cualquier código nuevo que agreguemos a un código legacy sí que incluya sus tests pertinentes

Uno de los mayores inconvenientes al trabajar con código legacy acostumbra a ser la imposibilidad de incorporar código testeado a las clases.

Podemos llegar a aceptar que no valga la pena que se escriban tests para el código viejo, en tanto que en general no va a estar listo para ello y la cantidad de inconvenientes y tiempo preciso para refactorizar los cambios puede ser inasumible en el instante en el que precisamos tocarlo.

Mas lo idóneo sería que cualquier código nuevo que agreguemos sí que incluya sus tests pertinentes.

¿De qué manera podemos hacer esto?

Sprout method

Cuando trabajamos con código legacy, precisamos hacer ciertas concesiones que no nos propondríamos en código hecho desde cero.

Una de las ideas que nos deja el libro de Working Effectively with Legacy Code (libro que te invito a si te resultan de interés estos temas), de Michael Feathers, es la de los Sprout methods.

Suponiendo que nuestra nueva funcionalidad afecte a un solo punto del código, podemos extraer ese código a un procedimiento, y hacer testing de ese procedimiento de forma independiente.

Estos serían los pasos precisos para incluir el nuevo código:

Identifica dónde precisas efectuar el cambio en el código
Si el cambio puede ser elaborado como una sola secuencia de sentencias en un solo sitio de un procedimiento, escribe la llamada al nuevo procedimiento que efectuará el trabajo y coméntala.
Determina qué variables locales precisas del procedimiento original, y pásalos como razonamiento de la llamada.
Determina si el procedimiento extraído precisará devolver valores al procedimiento original. De se de este modo, cambia la llamada a fin de que el valor de retorno sea asignado a una variable.
Incorpora el procedimiento extraído a través de TDD.
Suprime el comentario del procedimiento original para habilitar la llamada.

Va a haber ocasiones en las que no sea nada simple instanciar un objeto y ejecutar este procedimiento sin alterar algo de la clase.

La única solución que queda llegados aquí es la de hacer el procedimiento estático. Semeja ir un tanto contra toda lógica, mas será la única forma que vamos a tener de hacer este código testable.

Cuando trabajamos con código legacy, precisamos hacer ciertas concesiones que no nos propondríamos en código hecho desde cero.

Ejemplo

Si bien el ejemplo es bastante fácil, vamos a verlo de forma rápida. Imaginemos que tenemos un procedimiento que recorre una lista de registros y los guarda en base de datos:

public void saveRecords(List records) undefined

Un nuevo requisito nos solicita ahora que solo guardemos los diez últimos registros, que el resto son intrascendentes. Siguiendo la idea del Sprout method podemos hacer:

public void saveRecords(List records) undefined

List filterTenLatestRecords(List records) {
int size = records.size()
if (size