Fundamentos de la Refactorización

30
Fundamentos de la Refactorización Marcos Montaño Javier Pérez

description

Slides del taller presentado por mi persona y Marcos Montaño en el Regional Scrum Gathering Bolivia 2014. Contiene una corta introducción sobre lo que es refactorización y una pequeña demostración del proceso.

Transcript of Fundamentos de la Refactorización

Page 1: Fundamentos de la Refactorización

Fundamentos de la Refactorización

Marcos MontañoJavier Pérez

Page 2: Fundamentos de la Refactorización

https://bitbucket.org/jperezq/refactoring-fundamentals

http://bit.ly/1gVzxcI

Código de ejemplo

Page 3: Fundamentos de la Refactorización

“The process of changing a software system in such a way that it does not alter the external behaviour of the code, yet improves its internal structure.”

Martin Fowler, “Refactoring: Improving the Design of Existing Code”, Addison-Wesley,1999.

El proceso de cambiar un sistema de software de manera que no se altere el comportamiento externo del código, pero si se mejore su estructura.

¿Qué es la refactorización?

Page 4: Fundamentos de la Refactorización

Mejora la calidad del código:◦ Reduce la duplicidad◦ Mejora la mantenibilidad◦ Acelera la implementación de nueva

funcionalidad◦ Previene la permanencia de las malas practicas

en el código (code smells)

¿Por qué refactorizar?

Page 5: Fundamentos de la Refactorización

Código duplicado Métodos largos Clases grandes Largas listas de parámetros (argumentos) Generalización innecesaria Atributos temporales Middle Man Intimidad inapropiada Clases tontas Comentarios excesivos

¿Cuáles son las malas prácticas?

Page 6: Fundamentos de la Refactorización

No hay un “tiempo de refactorización” , es un hábito

Antes de agregar nueva funcionalidad◦ Encontrar código a modificar◦ Reparar el código para prevenir mas repetición

Cuando necesitas arreglar un bicho◦ Hace el código mas compresible◦ Ayuda a encontrar el bicho

Durante los Code Reviews◦ Un nuevo enfoque ve las cosas de forma diferente◦ Una revisión mas efectiva

¿Cuándo refactorizar?

Page 7: Fundamentos de la Refactorización

Añadir nuevas capacidades al sistema

Añadir nuevos tests Mantener los tests

corriendo

No agrega nueva funcionalidad

No agrega tests (pero pueden haber cambios menores)

Reestructura el código para eliminar redundancia

Añadir nueva funcionalidad VS Refactorización

Page 8: Fundamentos de la Refactorización

A un cliente técnico, no es difícil indicarle los beneficios

A un cliente enfocado en la calidad, hacer énfasis en aspectos de calidad◦ Presentarlo como un proceso de revisión

A un cliente enfocado en los plazos, no le digas◦ Encuentra una manera de integrarlo en tu trabajo

cotidiano◦ Ahorra tiempo, pero algunos de los clientes no lo

notaran

¿Cómo lo vendes?

Page 9: Fundamentos de la Refactorización

Tests pasando La aplicación funcionando Necesitamos poder probar que no rompimos

nada con la refactorización

NUNCA refactorizar una aplicación rota

¿Qué necesitas para comenzar?

Page 10: Fundamentos de la Refactorización

Ciclo de refactorización

Page 11: Fundamentos de la Refactorización

Partimos de un sistema que representa la simulación de una red local. El equipo de desarrollo inicial ha trabajado en satisfacer muy rápidamente los requerimientos iniciales y ha logrado lanzar la versión 1.4 del sistema; y ésta contiene toda la funcionalidad deseada para la primera etapa.

El cliente ahora quiere funcionalidad nueva y el equipo de desarrollo teme que el diseño actual no sea lo suficientemente flexible.

El problemaBROADCAST PACKET

Page 12: Fundamentos de la Refactorización

Red Token Ring

Page 13: Fundamentos de la Refactorización

lanSimulation lanSimulation.internalsNetwork

LANSimulation

Packet

Node

lanSimulation.tests

LANTests

El diseño

Page 14: Fundamentos de la Refactorización

lanSimulation

lanSimulation.internals

Network

+defaultExample(): Network+isInitialized(): boolean+hasWorkstation(nm: String): boolean+requestWorkstationPrintsDocument()+requestBroadcast(report: Writer)+printOn(buffer: StringBuffer)+printHTML(buffer: StringBuffer)+printXML(buffer: StringBuffer)

LANSimulationPacket

+message_:String+origin_:String+destination_:String

Node

+type_:byte+name_:String+nextNode_:Node

El diseño

Page 15: Fundamentos de la Refactorización

Versión 1.0: Impresión básica del documento◦ Las estaciones de trabajo solicitan a la red de trabajo

de Token Ring el entregar un documento a un nodo que representa una impresora.

Versión 1.1: Registro de paquetes enviados◦ Cada vez que un nodo envía un paquete al siguiente

nodo, debería guardarse el evento en un registro. Versión 1.2: Impresión en PostScript

◦ Un paquete puede empezar con “!PS” en cuyo caso las impresoras deberían reconocerlo como PostScript e invocar el trabajo de impresión adecuado.

Funcionalidad existenteVersión 1.4

Page 16: Fundamentos de la Refactorización

Versión 1.3: Registro de impresión◦ Las impresoras deberían registrar el autor y el

título del documento que se esta imprimiendo. Versión 1.4: Paquete de difusión

◦ Introduce un nuevo tipo de paquete “BROADCAST” que debería ser aceptado por todos los nodos en la red.

Funcionalidad existenteVersión 1.4

Page 17: Fundamentos de la Refactorización

Versión 2.0: Leer desde un archivo◦ Leer la configuración de una red y los trabajos

que se imprimieron desde un archivo XML Versión 2.1: Nodo de acceso

◦ Introducir un nuevo nodo “Gateway”, que puede reconocer todas las direcciones en su subred actual.

Funcionalidad deseada

Page 18: Fundamentos de la Refactorización

Versión 2.2: Lista de nodos compilada◦ Usando el paquete Broadcast, el gateway pide

periódicamente a todos los nodos que respondan con su nombre.

Versión 3.0: Interfaz Grafica◦ El sistema debería tener una interfaz grafica que

será capaz de mostrar la animación de lo que esta ocurriendo.

Funcionalidad deseada

Page 19: Fundamentos de la Refactorización

lanSimulation

lanSimulation.internals

Network

+defaultExample(): Network+isInitialized(): boolean+hasWorkstation(nm: String): boolean+requestWorkstationPrintsDocument()+requestBroadcast(report: Writer)+printOn(buffer: StringBuffer)+printHTML(buffer: StringBuffer)+printXML(buffer: StringBuffer)

LANSimulationPacket

+message_:String+origin_:String+destination_:String

Node

+type_:byte+name_:String+nextNode_:Node

¿Qué podemos mejorar del diseño?

Page 20: Fundamentos de la Refactorización

¡¡¡Manos a la Obra!!!

Page 21: Fundamentos de la Refactorización

Se puede encontrar en varias partes de la aplicación codigo duplicado:◦ El codigo de registro se repite 2 veces en el

método “printDocument”◦ El codigo de impresion se repite 3 veces, dos

veces en el método “requestWorkstationPrintsDocument” y una en el método “requestBroadcast”.

Para solucionar esto utilizarmos la técnica Extraer Metodo

Código Duplicado

Page 22: Fundamentos de la Refactorización

La clase Network contiene casi toda la logica de la aplicación.

Por ejemplo podemos ver que los métodos que acabamos de extraer utilizan campos internos de Node y Packet.

Eso nos indica que la logica deberia estar en esas clases, para esto utilizarmos la técnica Mover Método

Concentración de Responsabilidades

Page 23: Fundamentos de la Refactorización

Todavia se vé que hay lógica duplicada en el código, la forma en la que se navega a través de los nodos hasta circular por la toda la Red

• Se puede ver lógica duplicada en los métodos “requestWorkstationPrintsDocument” y “requestBroadcast”

Aplicaremos Extraer Método para sacar la lógica duplicada y la optimizaremos.

Lógica de Navegación Duplicada

Page 24: Fundamentos de la Refactorización

Se puede ver que la lógica de impresión por tipo está duplicada en los metodos "printOn", "printHTMLOn", "printXMLOn".

Para encapsular y aislar comportamiento diferente segun el tipo es recomendabe usar una jerarquía de Clases.

Lógica de Tipos Duplicada

Page 25: Fundamentos de la Refactorización

lanSimulation lanSimulation.internals

Network

+defaultExample(): Network+isInitialized(): boolean+hasWorkstation(nm: String): boolean+requestWorkstationPrintsDocument()+requestBroadcast(report: Writer)+printOn(buffer: StringBuffer)+printHTML(buffer: StringBuffer)+printXML(buffer: StringBuffer)

LANSimulation Packet

+message_:String+origin_:String+destination_:String

+getAuthor(): String+getTitle(): String+isPostScript(): boolean

Node

+name_:String+nextNode_:Node+Attribute1

+atDestination(packet: Packet): boolean+atOrigin(packet: Packet): boolean+logPacketPassage(report: Writer)+printDocument(document, report): boolean+printOn(buffer: StringBuffer)+printXMLOn(buffer: StringBuffer)+send(packet, report): boolean

La Refactorización Terminó

Page 26: Fundamentos de la Refactorización

A través del trabajo de refactorización hemos facilitado el mantenimiento del sistema y la implementación de nueva funcionalidad.◦ Versión 2.0: Leer desde un archivo◦ Versión 2.1: Nodo de acceso◦ Versión 2.2: Lista de nodos compilada◦ Versión 3.0: Interfaz Grafica

Conclusión

Page 27: Fundamentos de la Refactorización

Usar un sistema de versionamiento de código.

Hacer correr los tests constantemente (Después de cada cambio).

Recomendaciones

Page 29: Fundamentos de la Refactorización

“Object-Oriented Reengineering Patterns”, Serge Demeyer, Stéphane Ducasse, Oscar Nierstrasz, http://scg.unibe.ch/download/oorp

"Refactoring: Improving the Design of Existing Code", Martin Fowler , Kent Beck , John Brant, http://refactoring.com

Referencias

Page 30: Fundamentos de la Refactorización

¡¡¡Gracias!!!