¿Por qué?
Mito |
---|
[irónicamente] un proyecto de software bien administrado lleva a cabo un desarrollo metódico de requerimientos y define una lista estable de las responsabilidades del programa. El diseño sigue los requerimientos, y se hace con cuidado para que la codificación pueda proceder de forma lineal, de principio a fin, lo que implica que la mayor parte del código se puede escribir, probar y olvidar de una sola vez …
— Fred P. Brooks Jr
The Mythical Man-Month |
Realidad | |
---|---|
|
Creo firmemente que un buen diseño es esencial para un rápido desarrollo de software. Sin un buen diseño, puede progresar rápidamente durante un tiempo, pero pronto el diseño deficiente comienza a ralentizarlo. Dedicas tiempo a buscar y corregir errores en lugar de agregar una nueva funcionalidad. Los cambios requieren más tiempo para comprender el sistema y encontrar el código duplicado. Las nuevas funcionalidades necesitan más codificación a medida que parchea un parche que parchea un parche sobre la base del código original.
— Martin Fowler
Refactoring |
|
No hay software tan grande, enredado o complejo que el mantenimiento no pueda empeorarlo
— Gerald Weinberg
A medida que las personas cambian el código, cambios para lograr objetivos a corto plazo o cambios realizados sin una comprensión completa del diseño del código, el código pierde su estructura. Se vuelve más difícil ver el diseño leyendo el código. La pérdida de la estructura del código tiene un efecto acumulativo. Cuanto más difícil es ver el diseño en el código, más difícil es conservarlo y más rápidamente se deteriora. El problema es que cuando intenta que el programa funcione, no está pensando en el futuro desarrollador.
— Martin Fowler
Refactoring |
¿Qué?
Un cambio hecho a la estructura interna del software para hacerlo más fácil de entender y más barato de modificar, sin modificar su comportamiento observable
Refactoring
Sustantivo | Verbo |
---|---|
Cada una de las modificaciones hechas al código fuente que cumplen con la definición
— Martin Fowler
Refactoring |
El acto de aplicar uno o varios refactorings al código fuente
— Martin Fowler
Refactoring |
I should amplify a couple of points in my definitions: | |
---|---|
Primero, el propósito de la refactorización es hacer que el software sea más fácil de entender y modificar. Puedes realizar muchos cambios en el software que hacen poco o ningún cambio en el comportamiento observable. Solo los cambios realizados para facilitar la comprensión del software son refactorizaciones. Un buen contraste es la optimización del rendimiento.
— Martin Fowler
Refactoring |
¿La refactorización es solo limpiar el código? "En cierto modo, la respuesta es sí, pero creo que la refactorización va más allá porque proporciona una técnica para limpiar el código de una manera más eficiente y controlada.
— Martin Fowler
Refactoring |
Sí cumple | No cumple |
---|---|
|
|
¿Para qué?
Ventaja | Justificación |
---|---|
|
La refactorización le ayuda a hacer su código más legible. Al refactorizar, tiene un código que funciona pero no está estructurado idealmente. Un poco de tiempo dedicado a la refactorización puede hacer que el código comunique mejor su propósito. No soy necesariamente altruista al respecto. A menudo, este futuro desarrollador soy yo. A medida que el código se aclara, encuentro que puedo ver cosas sobre el diseño que no podía ver antes.
— Martin Fowler
Refactoring |
|
Sin embargo, encuentro que si refactorizo el código, trabajo profundamente en la comprensión de lo que hace el código, y vuelvo a poner esa nueva comprensión en el código. Al aclarar la estructura del programa, aclaro ciertas suposiciones que hice, hasta el punto en que ni siquiera yo puedo evitar detectar los errores
— Martin Fowler
Refactoring |
|
Se necesita un cambio de ritmo para realizar cambios que faciliten la comprensión del código. La refactorización le ayuda a desarrollar software más rápidamente, porque evita que el diseño del sistema se deteriore
— Martin Fowler
Refactoring |
|
Sin la refactorización, el diseño del programa se deteriorará. La refactorización metódica ayuda a que el código conserve su forma.
— Martin Fowler
Refactoring |
Excusas | Error |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
¿Cómo?
Bucle de Refactoring
|
|
Invariante del Refactoring
Red de Seguridad con Pruebas Unitarias Automáticas suficientes para asegurar el mismo comportamiento |
No combinar con modificar/agregar comportamiento al mismo tiempo que refactorizas porque pierdes la Red de Seguridad |
|
|
|
|
|
|
Condición del Refactoring
La perfección se alcanza, no cuando no hay nada que añadir, sino cuando no queda nada que quitar
— Antoine de Saint Exupéry
El principito |
Reglas del diseño simple: pasa todas las pruebas, no contiene duplicados, expresa claramente la intención del programador y minimiza el número de clases y métodos para expresar dicha intención
— Kent Beck
XXX |
Smell Codes de Martin Fowler | Smell Codes de Robert Martin |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Cuerpo del Refactoring
|
Refactorizaciones correspondientes a smell codes | |
---|---|
|
|
|
Baby Steps de Extraer Clase | |
---|---|
|
|
|
Catálogo de Refactorizaciones
No se convierte en un artesano del software aprendiendo una lista de heurísticas. El profesionalismo y la artesanía provienen de valores que impulsan las disciplinas
Refactoring
|
|
|
|
|
|
|
|
|
|
|
|
|
Nombrado
Rename Method | |
---|---|
|
|
Replace Magic Number with Symbolic Constant | |
---|---|
|
|
Parámetros
Remove Assignments to Parameters | |
---|---|
|
|
Replace Parameter with Method | |
---|---|
|
|
Replace Parameter with Explicit Methods | |
---|---|
|
|
Variables Temporales
Split Temporary Variable | |
---|---|
|
|
Introduce Explaining Variable | |
---|---|
|
|
Inline Temp | |
---|---|
|
|
Replace Temp with Query | |
---|---|
|
|
Condicionales
Replace Nested Conditional with Guard Clauses | |
---|---|
|
|
Consolidate Conditional Expression | |
---|---|
|
|
Consolidate Duplicate Conditional Fragments | |
---|---|
|
|
Remove Control Flag | |
---|---|
|
|
Introduce Null Object | |
---|---|
|
|
Decompose Conditional | |
---|---|
|
|
Cabecera de Método
Remove Parameter | |
---|---|
|
|
Add Parameter | |
---|---|
|
|
Parameterize Method | |
---|---|
|
|
Cuerpo de Métodos
Substitute Algorithm | |
---|---|
|
|
Inline Method | |
---|---|
|
|
Extract Method | |
---|---|
|
|
Replace Method with Method Object | |
---|---|
|
|
Form Template Method | |
---|---|
|
|
Encapsulación
Encapsulate Field | |
---|---|
|
|
Self Encapsulate Field | |
---|---|
|
|
Hide Method | |
---|---|
|
|
Remove Setting Method | |
---|---|
|
|
Encapsulate Collection | |
---|---|
|
|
Encapsulate Downcast | |
---|---|
|
|
Gestión de Errores
Introduce Assertion | |
---|---|
|
|
Replace Error Code with Exception | |
---|---|
|
|
Separate Query from Modifier | |
---|---|
|
|
Replace Exception with Test | |
---|---|
|
|
Relación de Herencia
Extract Interface | |
---|---|
|
|
Extract Superclass | |
---|---|
|
|
Extract Subclass | |
---|---|
|
|
Collapse Hierarchy | |
---|---|
|
|
Replace Subclass with Fields | |
---|---|
|
|
Pull Up Field | |
---|---|
|
|
Push Down Field | |
---|---|
|
|
Pull Up Method | |
---|---|
|
|
Push Down Method | |
---|---|
|
|
Pull Up Constructor Body | |
---|---|
|
|
Polimorfismo
Replace Conditional with Polymorphism | |
---|---|
|
|
Replace Type Code with Subclasses | |
---|---|
|
|
Replace Type Code with State/Strategy | |
---|---|
|
|
Replace Constructor with Factory Method | |
---|---|
|
|
Colaboraciones
Preserve Whole Object | |
---|---|
|
|
Replace Delegation with Inheritance | |
---|---|
|
|
Replace Inheritance with Delegation | |
---|---|
|
|
Hide Delegate | |
---|---|
|
|
Remove Middle Man | |
---|---|
|
|
Change Unidirectional Association to Bidirectional | |
---|---|
|
|
Change Bidirectional Association to Unidirectional | |
---|---|
|
|
Reparto de Responsabilidades
Move Method | |
---|---|
|
|
Move Field | |
---|---|
|
|
Inline Class | |
---|---|
|
|
Extract Class | |
---|---|
|
|
Replace Type Code with Class | |
---|---|
|
|
Replace Array with Object | |
---|---|
|
|
Replace Record with Data Class | |
---|---|
|
|
Introduce Parameter Object | |
---|---|
|
|
Replace Data Value with Object | |
---|---|
|
|
Change Value to Reference | |
---|---|
|
|
Change Reference to Value | |
---|---|
|
|
Bibliotecas & GUI
Introduce Foreign Method | |
---|---|
|
|
Introduce Local Extension | |
---|---|
|
|
Duplicate Observed Data | |
---|---|
|
|
Granularidad del Refactoring
Característica | Refactoring de Catálogo | Refactoring en Grande |
---|---|---|
|
Alto, añadir un parámetro, … |
Baja, desenmarañar una jerarquía de herencia, … |
|
Minutos, … hora |
Meses…, años, todos los días un poquito!!! |
|
Visible |
Difuso |
|
Individual |
Equipo coordinado con un mismo objetivo de diseño, evitando pisar lo barrido!!! |
|
Satisfacción instantánea |
Vivir tranquilo, no grandes logros |
Ejemplo de refactoring en grande |
|
|
|
Ejemplo movies
Versión 1.
Clase “Customer” - Método “statement()” | |
---|---|
|
Versión 2.
Clase “Customer“ - Método “amountFor()“ | |
---|---|
|
Versión 3.
Clase “Customer“ - Método “amountFor()“ | |
---|---|
|
Versión 4.
Clase “Customer“ – Método “amountFor()“ | |
---|---|
|
Versión 5.
Clase “Customer“ – Método “statement()“ | |
---|---|
|
Versión 6.
Clase “Customer“ – Método “statement()“ | |
---|---|
|
Versión 7.
Clase “Customer“ – Método “statement()“ | |
---|---|
|
Versión 8.
Clase “Customer“ – Método “statement()“ | |
---|---|
|
Versión 9.
Clase “Rental“ – Método “getCharge()“ | |
---|---|
|
Versión 10.
Clase “Rental“ – Método “getFrequentRenterPoints()“ | |
---|---|
|
Versión 11.
Clase “Movie“ – Método “getCharge()“ | |
---|---|
*Reemplazar Código de Tipo con Estrategia/Estado (inyección de dependencias) ⇒ Auto-encapsular campo ⇒ “priceCode” |
Versión 12.
Clase “Movie“ – Método “getCharge()“ | |
---|---|
*Sentencia Alternativa Múltiple ⇒ el comportamiento depende de un tipo/código/…
|
Versión 13.
Clase “Movie” - Atributo “priceCode” | |
---|---|
|
Versión 14.
Clase “Movie” - método “getCharge()” | |
---|---|
|
Versión 15.
Clase “Price” - método “getCharge()” | |
---|---|
*Reemplazar Condicional con Polimorfismo ⇒ Redefinir método “getCharge()” en clases derivadas |
Versión 16.
Clase “Price” - método “getFrequentRenterPoints()” | |
---|---|
*Reemplazar Condicional con Polimorfismo ⇒ Redefinir métod“getFrequentRenterPoints()” en clases derivadas |
Versión 17.
Clase “CustomerTest” - métodos de prueba con Tipo/Código | |
---|---|
|
Versión 18.
Clase “CustomerTest” - métodos de prueba con Tipo/Código | |
---|---|
|
Versión 19.
Clase “Price” - método “getPriceCode()” | |
---|---|
|
Versión 20.
Jerarquía “Price” | |
---|---|
|
Versión 21.
Sintesis
Bibliografía
Obra, Autor y Editor | Portada | Obra, Autor y Editor | Portada |
---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ponente
|
|