Você está na página 1de 11

Refactorizacin en la prctica: peligros y soluciones

Jess Prez y Jorge Ferrer AgileSpain (http://www.agile-spain.com/) Introduccin a la refactorizacin La refactorizacin es uno de los nuevos conceptos que se han introducido en la terminologa del mundo del desarrollo apoyado por las metodologas giles. Extreme Programming, una de las metodologas giles ms extendida, la incluye dentro del declogo de prcticas que propone como fundamentales. Sin embargo la idea de refactorizacin no es nueva, lo que resulta novedoso es la forma en que se lleva a cabo, una forma gil y agresiva, pero al tiempo ordenada y segura. Refactorizar es una idea apoyada por una tcnica que debemos controlar si queremos llevar a cabo un diseo evolutivo y un desarrollo gil de nuestra aplicacin. Qu significa Refactorizar? La mejor definicin la obtenemos de uno de los padres de esta tcnica, Martin Fowler, que dijo: "Refactorizar es realizar modificaciones en el cdigo con el objetivo de mejorar su estructura interna, sin alterar su comportamiento externo". De esta definicin extraemos ideas muy importantes y conceptos que a veces estaban equivocados. Refactorizar no es una tcnica para encontrar y corregir errores en una aplicacin, puesto que su objetivo no es alterar su comportamiento externo. De hecho, no modificar el comportamiento externo de la aplicacin es uno de los pilares de cualquiera de las prcticas que forman parte de la tcnica, para lo que en muchas ocasiones se hace uso de las pruebas unitarias. La esencia de esta tcnica consiste en aplicar una serie de pequeos cambios en el cdigo manteniendo su comportamiento. Cada uno de estos cambios debe ser tan pequeo que pueda ser completamente controlado por nosotros sin miedo a equivocarnos. Es el efecto acumulativo de todas estas modificaciones lo que hace de la Refactorizacin una potente tcnica. El objetivo final de Refactorizar es mantener nuestro cdigo sencillo y bien estructurado. Refactorizar nos propone seguir las tcnicas matemticas que consiguen reducir frmulas muy complejas en frmulas equivalentes pero ms sencillas. En el entorno matemtico estas simplificaciones consiguen eficiencia, adems de facilitar el clculo de problemas libre de errores, muy fciles de cometer cuando las formulas son muy complejas. No obstante conseguir un cdigo sencillo es una tarea muy compleja Como dice Carver Mead: "Es fcil tener una idea complicada. Es muy, muy complicado tener una idea simple." Por qu debemos Refactorizar nuestro cdigo? Existen muchas razones por las que deberamos adoptar esta tcnica: Calidad. La ms importante. Conseguir ser un buen profesional pasa inevitablemente por conseguir que tu trabajo sea de calidad. Refactorizar es un continuo proceso de reflexin sobre nuestro cdigo que permite que aprendamos de nuestros desarrollos en un entorno en el que no hay mucho tiempo para mirar hacia atrs. Un cdigo de calidad es un cdigo sencillo y bien estructurado, que cualquiera pueda

leer y entender sin necesidad de haber estado integrado en el equipo de desarrollo durante varios meses. Se acabaron los tiempos en que lo que imperaba eran esos programas escritos en una sola lnea en la que se hacia de todo, tiempos en los que se valoraba la concisin aun a costa de la legibilidad. Eficiencia: Mantener un buen diseo y un cdigo estructurado es sin duda la forma ms eficiente de desarrollar. El esfuerzo que invirtamos en evitar la duplicacin de cdigo y en simplificar el diseo se ver recompensado cuando tengamos que realizar modificaciones, tanto para corregir errores como para aadir nuevas funcionalidades. Diseo Evolutivo en lugar de Gran Diseo Inicial: En muchas ocasiones los requisitos al principio del proyecto no estn suficientemente especificados y debemos abordar el diseo de una forma gradual. Cuando tenemos unos requisitos claros y no cambiantes un buen anlisis de los mismos puede originar un diseo y una implementacin brillantes, pero cuando los requisitos van cambiando segn avanza el proyecto, y se aaden nuevas funcionalidades segn se le van ocurriendo a los participantes o clientes, un diseo inicial no es ms que lo que eran los requisitos iniciales, algo generalmente anticuado. Refactorizar nos permitir ir evolucionando el diseo segn incluyamos nuevas funcionalidades, lo que implica muchas veces cambios importantes en la arquitectura, aadir cosas y borrar otras. Evitar la Reescritura de cdigo: En la mayora de los casos Refactorizar es mejor que rescribir. No es fcil enfrentarse a un cdigo que no conocemos y que no sigue los estndares que uno utiliza, pero eso no es una buena excusa para empezar de cero. Sobretodo en un entorno donde el ahorro de costes y la existencia de sistemas lo hacen imposible. Refactorizar es por tanto un medio para mantener el diseo lo ms sencillo posible y de calidad. Qu se entiende por sencillo y de calidad? Kent Beck define una serie de caractersticas para lograra un cdigo los mas simple posible: - El cdigo funciona (el conjunto de pruebas de la funcionalidad de nuestro cdigo pasan correctamente). - No existe cdigo duplicado. - El cdigo permite entender el diseo. - Minimiza el nmero de clases y de mtodos. A pesar de todo ello, refactorizar parece ser muchas veces una tcnica en contra del sentido comn. Por qu modificar un cdigo que funciona? (si funciona no lo toques) Por qu correr el riesgo de introducir nuevos errores?, cmo podemos justificar el coste de modificar el cdigo sin desarrollar ninguna nueva funcionalidad? No siempre es justificable modificar el cdigo, no se reduce a una cuestin esttica. Cada refactorizacin que realicemos debe estar justificada. Slo debemos refactorizar cuando identifiquemos cdigo mal estructurado o diseos que supongan un riesgo para la futura evolucin de nuestro sistema. Si detectamos que nuestro diseo empieza a ser complicado y difcil de entender, y nos est llevando a un situacin donde cada cambio empieza a ser muy costoso. Es en ese momento cuando debemos ser capaces de frenar la inercia de seguir desarrollando porque si no lo hacemos nuestro software se convertir en algo inmantenible (es imposible o demasiado costoso realizar un cambio). Tenemos que estar atentos a estas situaciones donde lo ms inteligente es parar, para reorganizar el cdigo. Se trata de dar algunos pasos hacia atrs que nos permitirn tomar carrerilla para seguir avanzando. Los sntomas que nos avisan de que nuestro cdigo tiene problemas se conocen como Bad Smells. En qu momento debemos Refactorizar?, es necesario planificar tareas especficas de refactorizacin? La Refactorizacin no es un proceso que podemos aislar como una tarea. Es necesario que lo incluyamos como una actividad que realizaremos cuando estemos desarrollando. No tiene que ser exactamente en el mismo instante en que identifiquemos un "Bad Smell", ya que como se ha apuntado anteriormente, la funcionalidad no debe verse modificada. Por ello, debemos acabar lo que estemos haciendo (recuerda, pasos pequeos). Una vez finalizado el paso que nos ocupa,

es el momento de abarcar la refactorizacin que debe realizarse de forma natural como parte del mismo desarrollo. La adopcin de la refactorizacin como parte de nuestros desarrollos no resulta muchas veces sencilla, puesto que intuitivamente no proporciona la sensacin de avanzar en la finalizacin de nuestro desarrollo. No obstante el tiempo empleado en refactorizaciones se ver muy justificado a la hora de seguir con el diseo, realizar modificaciones o buscar errores en el cdigo para subsanarlos. Como dice el refrn: Vsteme despacio que tengo prisa. Cuales son estos Bad Smells?, cules son los sntomas de que la evolucin de nuestro desarrollo se encamina hacia un caos?, cundo nuestro cdigo empieza oler?. En [Fowler] podemos encontrar una lista de ellas como Cdigo Duplicado, Mtodos largos, Clases Largas, Clusulas Switch, Comentarios, etc. Existen herramientas en "Ant" como "checkstyle" que permiten automatizar la identificacin de algunos "Bad Smell" (con "checkstyle" es posible fijar el numero mximo de lneas de un mtodo, o el mximo nmero de parmetros de un mtodo). Una vez identificado el "Bad Smell" deberemos aplicar una refactorizacin que permita corregir ese problema. Para comenzar a Refactorizar es imprescindible que el proyecto tenga pruebas automticas, tanto unitarias como funcionales, que nos permitan saber en cualquier momento al ejecutarlas, si el desarrollo sigue cumpliendo los requisitos que implementaba. Sin pruebas automticas, Refactorizar es una actividad que conlleva un alto riesgo. Sin pruebas automticas nunca estaremos convencidos de no haber introducido nuevos errores en el cdigo al trmino de una refactorizacin, y poco a poco dejaremos de hacerlo por miedo a estropear lo que ya funciona. Refactorizar sin tener un conjunto de pruebas asociado al proyecto debe dejrselo a los profesionales y no intentarlo en su casa, claro que los profesionales lo primero que harn para Refactorizar ser implementar las pruebas automticas que cubran la funcionalidad que se ve cubierta por el cdigo objetivo de la refactorizacin. Cmo debe aplicarse una refactorizacin?, cules son los pasos a seguir? La mejor forma de comprender el proceso es llevar a cabo una refactorizacin. Ejemplo de aplicacin de una Refactorizacin Refactorizar es una prctica, por lo que la mejor forma de entender esta tcnica es aplicarla. Lejos de pretender enumerar aqu todos esos patrones, mostraremos uno de ellos a modo de ejemplo: Reemplazar los condicionales con polimorfismo. Esta refactorizacin nos convierte el tradicional autmata de estados realizado con switchs en algo extensible y orientado a objetos, ms fcil de mantener y de arreglar al adoptar el patrn State. Para centrar ideas, supongamos que tenemos que actualizar un control de las puertas del suburbano de alguna ciudad. El problema es que est realizado a la antigua usanza, con un mtodo que se encarga a base de ifs (que podemos ver como un caso degenerado de switches que funcionara tanto con cadenas como con otro tipo de objetos) de pasar de un estado a otro: public class Metro { private int estado; static final private int PARADO = 0; static final private int EN_MARCHA = 1; static final private int PARANDO = 2; static final private int ARRANCANDO = 3; public void cambiaEstado() { if(estado==PARADO) { estado = ARRANCANDO; } else if(estado==EN_MARCHA) { estado = PARANDO; } else if(estado==PARANDO) { estado = PARADO;

} else if(estado==ARRANCANDO) { estado = EN_MARCHA; } else { throw new RuntimeException("Estado desconocido"); } } } Tras cada paso de los que vamos a dar, ejecutaremos los tests para ver que se pasan convenientemente. Lo primero que deberamos hacer sera separar las condiciones en un nico mtodo y subir dicho mtodo lo ms alto posible en la jerarqua. En nuestro ejemplo no es necesario dado que ya cumple las condiciones pedidas. A continuacin creamos una clase por cada posible estado y sustituimos los == por instanceof y las variables estticas enteras por referencias a instancias de esas clases. Obviamente, necesitaremos una interfaz base para nuestras clases de estado que por ahora ser un simple marcador. public interface Estado {} public class Parado implements Estado {} etc... public class Metro { private Estado estado; static final private Estado PARADO = new Parado(); static final private Estado EN_MARCHA = new EnMarcha(); static final private Estado PARANDO = new Parando(); static final private Estado ARRANCANDO = new Arrancando(); public void cambiaEstado() { if(estado instanceof Parado) { estado = ARRANCANDO; } else if(estado instanceof EnMarcha) { estado = PARANDO; } else if(estado instanceof Parando) { estado = PARADO; } else if(estado instanceof Arrancando) { estado = EN_MARCHA; } else { throw new RuntimeException("Estado desconocido"); } } } Nuestro siguiente y penltimo paso ser proveer de control a las clases nuevas para que sean ellas las que decidan el paso de un estado a otro. Implementando el patrn Estado (las diferencias entre ste y el Estrategia son de interpretacin), asignaremos un mtodo a la interfaz creada que nos devuelva el siguiente estado, y daremos contenido a dicho mtodo en las clases de estado: public interface Estado { public Estado siguiente(); } public class Parado implements Estado { // Por eficiencia, implementamos ya el patrn singleton private static final Parado instance=new Parado(); public static Parado getInstance() { return instance; } private Parado() {} public Estado siguiente() { return Arrancando.getInstance(); }

} etc... public class Metro { private Estado estado; public void cambiaEstado() { if(estado instanceof Parado) { estado = estado.siguiente(); } else if(estado instanceof EnMarcha) { estado = estado.siguiente(); } else if(estado instanceof Parando) { estado = PARADO; } else if(estado instanceof Arrancando) { estado = estado.siguiente(); } else { throw new RuntimeException("Estado desconocido"); } } } Por fin tenemos nuestro cdigo casi refactorizado. Ahora nos falta eliminar los ifs intiles y hacer desaparecer el throw que no se va a dar nunca si hemos implementado bien los distintos estados: public class Metro { private Estado estado; public void cambiaEstado() { estado = estado.siguiente(); } } La refactorizacin ya ha terminado. Por la simplicidad del cdigo que requiere un ejemplo escrito sera discutible si esta refactorizacin era necesaria. Pero en la prctica es muy habitual encontrar mquinas de estados ms complejas codificadas en forma de switches muy difciles de mantener. Esta refactorizacin demuestra cmo es posible organizar ese cdigo paso a paso y con poco riesgo. Implantacin de la refactorizacin Adems de conocer los aspectos tericos de la refactorizacin, tambin es importante profundizar sobre los aspectos ms prcticos de la aplicacin de esta tcnica en un proyecto de desarrollo real. En el caso de comenzar un proyecto desde cero, la refactorizacin continua es una prctica que conlleva un gran nmero de beneficios y evita de forma natural algunos peligros mencionados. Sin embargo, no siempre se parte de cero, y lo habitual es encontrarnos con cdigo cuyo diseo y/o estructura est lejos de ser los ms apropiados. Esta situacin puede darse cuando tenemos que ampliar la funcionalidad de cdigo previamente existente o simplemente porque en un proyecto empezado desde cero no se detect la necesidad de refactorizar a tiempo.. En estos casos nos encontramos con una refactorizacin a posteriori y deben tomarse medidas especficas para que afecte lo menos posible al ritmo normal de desarrollo. Pasos para implantar la refactorizacin en un equipo Implantar la refactorizacin debe realizarse de una manera progresiva. Nuestra experiencia en la implantacin de esta tcnica nos dice que es necesario seguir los siguientes pasos:

* Escribir pruebas unitarias y funcionales. Refactorizar sin pruebas unitarias y funcionales resulta demasiado costoso y de mucho riesgo. * Usar herramientas especializadas (ms informacin en [PerezFerrerColado60]). Las refactorizaciones en muchas ocasiones obligan a pequeas modificaciones muy simples en muchas clases de nuestro cdigo. Con herramientas especializadas estas refactorizaciones se realizan automticamente y sin riesgo. * Dar formacin sobre patrones de refactorizacin y de diseo. Una buena base terica sobre las refactorizaciones ms comunes permite al programador detectar Bad Smells de los que no es consciente y que harn que su cdigo se degrade progresivamente. * Refactorizar los principales fallos de diseo. Nuestra recomendacin es comenzar realizando refactorizaciones concretas que corrijan los principales fallos de diseo, como puede ser cdigo duplicado, clases largas, etc que son refactorizaciones sencillas de realizar y de las que se obtiene un gran beneficio. * Comenzar a refactorizar el cdigo tras aadir cada nueva funcionalidad en grupo. Una vez corregido los errores del cdigo existente, la mejor manera de aplicar Refactorirzacion suele ser al aadir una nueva funcionalidad, de manera que se desarrolle de la manera mas eficiente. Realizar discusiones en grupos sobre la conveniencia de realizar alguna refactorizacin suele ser muy productivo. * Implantar refactorizacin contnua al completo. Esta es la ltima fase y es cuando cada desarrollador incorpora la Refactorizacion como una tarea mas dentro del su proceso de desarrollo de Software. Refactorizacin continua Refactorizar de forma continuada es una prctica que consiste en mantener el diseo siempre correcto, refactorizando siempre que sea posible, despus de aadir cada nueva funcionalidad. Esta no es una prctica nueva pero esta adquiriendo mayor relevancia de mano de las metodologas giles.. Dado que una refactorizacin supone un cambio en la estructura del cdigo sin cambiar la funcionalidad, cuanto mayor sea el cambio en la estructura ms difcil ser garantizar que no ha cambiado la funcionalidad. Dicho de otra forma, cuanto mayor sea la refactorizacin, mayor es el nmero de elementos implicados y mayor es el riesgo de que el sistema deje de funcionar. El tiempo necesario para llevarla a cabo tambin aumenta y por tanto el coste se multiplica. Cuando un diseo no es ptimo y necesita ser refactorizado, cada nueva funcionalidad contribuye a empeorar el diseo un poco ms. Por ello cuanto ms tiempo esperamos mayor es la refactorizacin necesaria. Esta es la mayor de las justificaciones de una refactorizacin contnua, que trata de evitar las refactorizaciones grandes haciendo refactorizaciones pequeas muy a menudo. En concreto se refactoriza de forma inmediata a la inclusin de una nueva funcionalidad. Esta prctica tiene dos ventajas principalmente: El cdigo afectado es el mismo que el que se modific para aadir la funcionalidad y por tanto se reduce o evita completamente los inconvenientes para otros desarrolladores. El tiempo que se debe dedicar es reducido dado que en ese momento se tiene un conocimiento preciso del cdigo que se ver afectado. Las claves para poder aplicar refactorizacin contnua son: Concienciacin de todo el equipo de desarrollo.

Habilidad o conocimientos necesarios para identificar qu refactorizaciones son necesarias. Compartir con todo el equipo de desarrollo la visin de una arquitectura global que gue las refactorizaciones en una misma direccin. Lo ms habitual es que este tipo de refactorizaciones surjan nada ms implementar una funcionalidad y dejar los tests pasando satisfactoriamente. Estos mismos tests nos garantizarn que el cdigo sigue funcionando despus de la refactorizacin. Sin embargo no siempre resulta evidente para todos los desarrolladores la necesidad de una refactorizacin. En estos casos el uso de herramientas como javastyle y jcsc pueden emplearse como ayuda para identificar bad smells adems de unificar criterios entre todo el equipo. En cualquier caso es importante que estas herramientas no sustituyan nunca al sentido comn y se usen nicamente como ayuda. La refactorizacin continua tambin es una muy buena estrategia para evitar la proliferacin de ventanas rotas. Este trmino, presentado por Dave Thomas y Andrew Hunt en The Pragmatic Programmer, representa todo aquel aspecto del cdigo que un desarrollador percibe como negativo. Segn Thomas y Hunt un desarrollador no tiene muchos escrpulos en dejar una ventana rota ms, en un cdigo en el que l percibe o es consciente de muchas otras ventanas rotas. Sin embargo cuando el cdigo no tiene ninguna, ningn desarrollador quiere ser el primero en romper una ventana. El principal riesgo de la refactorizacin continua consiste en adoptar posturas excesivamente exigentes o criterios excesivamente personales respecto a la calidad del cdigo. Cuando esto ocurre se acaba dedicando ms tiempo a refactorizar que a desarrollar. La propia presin para aadir nuevas funcionalidades a la mayor velocidad posible que impone el mercado es suficiente en ocasiones para prevenir esta situacin. Si se mantiene bajo unos criterios razonables y se realiza de forma continuada la refactorizacin debe tender a ocupar una parte pequea en relacin al tiempo dedicado a las nuevas funcionalidades. El desarrollo dirigido por pruebas incluye de forma natural la refactorizacin continua, es lo que se conoce como TDD (Test Driven Development), prctica en la que se se hace la prueba, se aade la funcionalidad necesaria para satisfacerla, se generaliza la prueba y se refactoriza. La consecuencia inmediata de la aplicacin de est prctica suele ser la evolucin de la arquitectura inicial, en beneficio de un cdigo bien estructurado, de una arquitectura orientada en todo momento a la funcionalidad implementada y por tanto, clara y sencilla, caractersticas necesarias para que un cdigo sea mantinible y extensible.

Dificultades de la refactorizacin en la prctica Si para afirmar que sabemos refactorizar basta con conocer los principales patrones y seguir una serie de sencillos pasos, para refactorizar con xito es necesario tener en cuenta otros muchos factores propios de los proyectos de desarrollo reales. En un proyecto real hay que ser consciente de que no refactorizar a tiempo un diseo degradado puede tener consecuencias muy negativas, pero a la vez debe tener en cuenta que el tiempo dedicado a refactorizar no suele ser considerado como un avance del proyecto, por los usuarios, clientes o gestores del mismo. Otros factores clave para una correcta aplicacin de la refactorizacin son la forma en que afecta a otros miembros del equipo, el hecho de que un desarrollador realice refactorizaciones sobre cdigo en el que todos estn trabajando, el que una refactorizacin provoque que el cdigo est mucho tiempo sin funcionar o el efecto negativo de no refactorizar, en el nimo de los desarrolladores por la sensacin de no estar haciendo un trabajo de calidad.

Pero antes de tratar estos temas y cmo base para entender sus verdaderas implicaciones comenzaremos por tratar un factor raramente considerado en los libros o artculos sobre refactorizacin: el factor humano. Es decir, cmo afecta al desarrollador o equipo de desarrollo el refactorizar poco o demasiado, el hacerlo pronto o tarde, etc. El factor humano Una realidad a veces olvidada es que cualquier desarrollador prefiere hacer cdigo de calidad. Tambin es cierto que esta realidad a veces queda oculta debido a condiciones de presin excesiva o menosprecio del trabajo tcnico. En este sentido refactorizar es una forma de mejorar la calidad y por tanto es una forma de hacer que el desarrollador est ms orgulloso de su trabajo. Puede decirse que la refactorizacin bien realizada, rpida y segura, genera satisfaccin. Pero tambin hay un peligro en este hecho: el exceso de celo para conseguir un resultado de calidad puede llegar a suponer un nmero excesivo de refactorizaciones dando vueltas sobre diseos similares una y otra vez. Una posible solucin consiste en mantener la refactorizacin bajo control, definir claramente los objetivos antes de comenzar a refactorizar y estimar su duracin. Si se excede el tiempo planificado es necesario un replanteamiento. Quiz haya ocurrido que la refactorizacin era ms complicada de lo esperado pero tambin es posible que se est refactorizando ms de lo necesario. Adems de la evidente prdida de tiempo, refactorizar demasiado suele llevar a dos efectos negativos. El primero es que la modificacion del codigo incremente la complejidad de nuestro diseo, que es justo el efecto contrario del que intentabamos lograr al refactorizar. Por otro, es habitual fomentar la sensacin bien del desarrollador o bien de todo el equipo de que no se est avanzando. Una sensacin que conduce a repercusiones anmicas negativas. Trabajo en equipo Un equipo de desarrollo debe ser uno. Todos los miembros del equipo deben conocer la arquitectura en cada momento, el estado actual, los problemas que tenemos y el objetivo que se busca. Una reunin diaria es una prctica que facilita la comunicacin entre todos los miembros del equipo, y supone una prctica que proporciona un momento a todos los miembros del grupo para plantear sus ideas, dudas e inquietudes respecto al proyecto. Cuando un desarrollador refactoriza, afecta al resto del equipo. En este sentido, las refactorizaciones internas a una clase son menos problemticas, pero con las arquitecturales es necesario tener mucho cuidado. Este tipo de refactorizaciones supone cambios en un gran nmero de ficheros y por tanto es probable que se afecte a archivos que estn siendo modificados por otros desarrolladores. La comunicacin y coordinacin entre los afectados es fundamental para que esto no se convierta en un problema. Por tanto es necesario que en la reunin diaria del equipo (u otro mecanismo de comunicacin equivalente) se planteen las refactorizaciones de este tipo. De esta forma se sabr en todo momento quienes son los afectados y cual es el objetivo de la refactorizacin. De esta forma se promueve la colaboracin de todos en la refactorizacin arquitectural que se va a llevar a cabo. A veces, el comentar con el resto del equipo una refactorizacin que parece muy necesaria, puede hacernos ver que lo que pareca una muy buena idea, no lo es tanto por otros factores que ven otros compaeros y de los que no eramos conscientes. Esto evita tambin refactorizaciones en sentidos contrarios propias de equipos en los que falta comunicacin. Las refactorizaciones en sentidos contrarios suelen estar motivadas por tener cada miembro del equipo una idea diferente del diseo hacia el que debe dirigirse ese cdigo. Este problema de

comunicacin puede tener repercusiones bastante negativas en el diseo resultante. Una vez ocurre debe volverse a una situacin en la que todo el equipo comparta una misma visin de la arquitectura y diseo del sistema. Para ello la mejor manera es parar el desarrollo y reunir al todo equipo para alcanzar un acuerdo comn. En estas reuniones es muy til el uso de pizarras y diagramas UML si son conocidos por el equipo. Incluso los miembros del equipo que no se haban visto involucrados en la situacin aprendern de la experiencia para evitar que vuelvan a darse en el futuro. Una vez extraidas conclusiones, es posible que sea necesario realizar una refactorizacin ms para devolver el cdigo y el diseo a parmetros acordes con nuestros requisitos de calidad. Refactorizacin a posteriori En este apartado nos referimos con el trmino refactorizacin a posteriori a todas aquellos cambios estructurales que se realizan un tiempo despus de la implementacin de la funcionalidad existente. Existen varios motivos para encontrarse con esta situacin. Algunos de ellos son: Un equipo comienza a trabajar con cdigo desarrollado por un equipo anterior que o bien no tiene buena calidad o bien no est preparado para que se incorporen nuevas funcionalidades. Se ha aplicado refactorizacin continua pero la calidad del cdigo o el diseo se ha degradado porque no se identific a tiempo la necesidad de una refactorizacin o bien se equivoc la refactorizacin necesaria. Este tipo de refactorizaciones tiene un riesgo mucho mayor que los que nos encontramos con refactorizacin continua. Otra caracterstica de estas refactorizaciones es que afectan no slo al desarrollador o desarrolladores que van a aplicar la refactorizacin, sino a todos aquellos que trabajan con la parte del cdigo afectada: por un lado no pueden trabajar con el cdigo o deben hacerlo con mayor precaucin durante un tiempo; y por otro cuando vuelvan a trabajar con l se encontrarn con un diseo desconocido. La mejor estrategia a seguir en estos casos es tratar de dividir la refactorizacin en el mayor nmero de pequeos pasos posible. Tras cada paso el cdigo debe seguir funcionando sin fallos. Antes de abordar cada uno de estos pasos se debe comunicar a todas las personas afectadas por los cambios que se van a realizar. De esta forma se evita que cuando vuelvan a trabajar con ese cdigo se encuentren con un panorama completamente desconocido. En ocasiones tambin es recomendable dar explicaciones despus de la refactorizacin para explicar el diseo final. Si este tipo de explicaciones son necesarias con demasiada asiduidad, la solucin no es no realizarlas sino identificar los motivos de tanta refactorizacin a posteriori. Probablemente sea necesario un mayor grado de refactorizacin continua. La refactorizacin por pasos tiene la ventaja de afectar menos al ritmo normal de desarrollo y permite ser intercalada con la implementacin de nuevas funcionalidades. El principal inconveniente es que extiende en el tiempo la existencia de cdigo imperfecto. Por ello siempre que sea posible debe completarse la refactorizacin en el menor tiempo posible. Cuando una refactorizacin es difcil tcnicamente y lleva un tiempo considerable se corre el riesgo de entrar en lo que podramos denominar la espiral refactorizadora. Esta situacin ocurre cuando una refactorizacin se complica y conduce a nuevas refactorizaciones hasta que llega un momento en el que no es posible o es muy difcil estimar cuanto tiempo queda para terminar de refactorizar.

Toda situacin durante un desarrollo de software en la que no puede estimarse la finalizacin debe evitarse. En este caso la situacin se ve agravada porque se frena la adicin de nueva funcionalidad en el cdigo que est siendo refactorizado durante un tiempo indeterminado. Hay varias medidas que pueden adoptarse para evitar caer en la espeial refactorizadora. La primera de ellas es declarar el objetivo de una refactorizacin antes de empezar. Si durante la misma aparece nuevo cdigo susceptible de ser refactorizado debe dejarse sin modificar, por ahora slo apuntaremos esta necesidad para no olvidarnos de hacer la refactorizacin ms adelante. Cuando se considere ms oportuno. Otra prctica muy til consiste en introducir el cdigo en el sistema de control de versiones antes de emprender cualquier refactorizacin que podamos considerar grande. Si cuando se est llevando a cabo una refactorizacin se dispersan los objetivos iniciales, se llevan muchas horas o incluso das sin tener un cdigo que funciona o resulta imposible estimar cuanto queda para terminar es necesario asumir que la refactorizacin no va por buen camino. Para volver a la normalidad se debe devolver el cdigo a un estado en el funcionara correctamente. Esto resulta muy fcil si se sigui el consejo anterior de comenzar con cdigo guardado en el sistema de control de versiones. No deben tenerse reparos en tirar las modificaciones empezadas, estaremos cambiando un poco de tiempo de trabajo por recuperar una situacin estable que nos permite seguir avanzando sin incertidumbres. Lo ms importante ser lo aprendido de la refactorizacin fallida, que nos ser muy valioso para volver a intentarlo. La mejor forma de enfocar correctamente una refactorizacin y evitar caer en espirales de refactorizaciones, es conocer muy bien los patrones de diseo. Los patrones de diseo no son sino soluciones que funcionan para problemas comunes que todos encontramos cuando estamos desarrollando. Conocer perfectamente los patrones de diseo nos permite identificar y ver con claridad el objetivo de la refactorizacin, mejora la comunicacin entre los miembros del grupo al compartir una base de conocimiento muy importante y adems nos hace ms eficientes en la resolucin no slo de problemas conocidos, sino tambin de problemas desconocidos al haber adquirido una forma mejor arquitecturada de enfocar los problemas. Refactorizacin y pruebas unitarias La existencia de pruebas automatizadas facilita enormemente las refactorizaciones. Los principales motivos son: El riesgo de la refactorizacin disminuye, dado que es posible comprobar cuando esta concluye que todo sigue funcionando satisfactoriamente. El desarrollador que realiza la refactorizacin puede comprobar que no ha estropeado la funcionalidad implementada por otros. Evita efectos colaterales. El tiempo necesario para comprobar que todo sigue funcionando es menor lo que permite avanzar en pasos ms pequeos si se desea. Refactorizar sin tests es una actividad de alto riesgo y no debe hacerse salvo para las refactorizaciones ms sencillas y realizadas con herramientas especializadas. En ocasiones incluso algunas refactorizaciones muy pequeas pueden provocar la aparicin de bugs muy difciles de identificar a posteriori. Sin embargo las pruebas tambin pueden llegar a ser un estorbo a la refactorizacin si se emplean de forma inadecuada. En este sentido es muy importante resaltar la importancia de que las pruebas tanto funcionales como unitarias comprueben que el cdigo bajo prueba funcione correctamente independientemente de cmo est implementado. Cuanto mayor sea el acoplamiento de la

prueba con la implementacin, mayores sern los cambios que habr que realizar en esta cuando se lleve a cabo. Pero incluso aunque no exista este acoplamiento las refactorizaciones grandes, que afectan al diseo del cdigo significativamente, obligarn a realizar cambios en las pruebas. Esto provoca una situacin incmoda, las pruebas que deben ser una ayuda se convierten en este caso en un estorbo a la refactorizacin. La mejor solucin es prevenir aplicando refactorizaciones continuas y ms pequeas. Pero una vez nos encontramos con esta situacin, es recomendable cambiar las pruebas antes o a la vez que el cdigo. De esta forma las pruebas colaborarn guiando la refactorizacin. En este sentido tambin resulta til pensar antes de refactorizar en cmo van a afectar a los tests y cmo podemos usarlos en nuestro beneficio en vez de dejar que se conviertan en un problema. Conclusiones El problema de abordar una refactorizacin es que supone un esfuerzo que no se ve compensado por ninguna nueva funcionalidad y por ese motivo muchas veces es complicado de justificar. Sin embargo si introducimos la refactorizacin como parte del desarrollo conseguiremos que nuestro cdigo sea de calidad y la experiencia dice que este tiempo que vamos empleando a lo largo del desarrollo ser recuperado con creces segn el proyecto avance. Se puede afirmar que refactorizar nos facilita enormemente el mantenimiento de un cdigo siempre correctamente estructurado. El hecho de que el cdigo est bien estructurado es una ventaja por su mantenibilidad y extensibilidad. Sin embargo, esta tcnica que parece tan ventajosa, requiere de su aplicacin continua, el empleo de pruebas que proporcionen seguridad a su aplicacin un buen conocimiento de los patrones de diseo que van a permitir al desarrollador saber hacia donde camina y por ltimo importantes dosis de comunicacin con todos los miembros del equipo. Referencias [Fowler] Martin Fowler: Refactoring: Improving the Design of Existing Code. Addison-Wesley Co.[1999] http://www.refactoring.com [Wiki] Pginas Wiki sobre Refactorizacin http://c2.com/ppr/wiki/WikiPagesAboutRefactoring [IntelliJ] Uno de los mejores Entorno de Desarrollo Java para Refactorizar http://www.intellij.com [Refactoring] Pgina de Refactorizacin en Espaol. http://refactoring.blog-city.com [PerezFerrerColado58] Jess Prez, Jorge Ferrer, Csar Colado. Introduccin a la refactorizacin, Mundo Linux n 58. Revistas Profesionales. [PerezFerrerColado60] Jess Prez, Jorge Ferrer, Csar Colado. Refactorizacin en la prctica, Mundo Linux n 60 (pendiente de publicacin). Revistas Profesionales.

Você também pode gostar