La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

Principios de Reestructuración M.C. Juan Carlos Olivares Rojas

Presentaciones similares


Presentación del tema: "Principios de Reestructuración M.C. Juan Carlos Olivares Rojas"— Transcripción de la presentación:

1 Principios de Reestructuración M.C. Juan Carlos Olivares Rojas jcolivar@itmorelia.edu.mx http://antares.itmorelia.edu.mx/~jcolivar/ juancarlosolivares@hotmail.com @jcolivares Febrero 2010

2 Específica: conoce los términos básicos de la reestructuración de código e identifica el problema de código mal desarrollado en el contexto de desarrollo de software. Genéricas Instrumentales: Capacidad de análisis y síntesis, Solución de problemas, Toma de decisiones. Competencias

3 Interpersonales: Capacidad crítica y autocrítica, Capacidad de trabajar en equipo interdisciplinario, Habilidad para trabajar en un ambiente laboral, Compromiso ético. Sistémicas: Capacidad de aprender, Capacidad de adaptarse a nuevas situaciones, Capacidad de generar nuevas ideas (creatividad), Habilidad para trabajar en forma autónoma, Preocupación por la calidad. Competencias

4 Condiciones de la reestructuración Reestructuración y Diseño Reestructuración y desempeño Origen de la Reestructuración Temario

5 30% Prácticas 10% Otras actividades en el aula 60% Actividad de Evaluación Integral (Teórico- Práctico) Evidencias

6 Descargar el código fuente de la página Web denominado Fecha.zip. Dicho archivo comprimido consta de dos clases: Fecha y validaFecha. Realizar un diagrama de clases de todo el sistema antes de modificar y uno después de haber cocnluído todas las reestructuraciones. Se enviará por correo todo el proyecto. Actividad

7 Esta práctica de laboratorio cuenta para la unidad 1. Refactoriza el nombre de todos los identificadores (paquetes, clases, atributos, métodos y variables) para que cumplan con el estándar de codificación “Camello Húngaro” visto en clase. En el caso de paquetes se sigue la convención de nombres de dominios al revés. Laboratorio 3

8 En nuestro caso el paquete deberá comenzar con mx.edu.itmorelia y el nombre actual del paquete. ¿Porqué se sigue esta convención en el nombre de paquetes? Para hacerlo realmente útil al momento de exportarlos a nivel de API. Si no existe la convección de notación se deberá indicar el prefijo utilizado. Laboratorio 3

9 Una vez realizado el renombrado de modificadores se proseguirá con la detección de “malos olores” en el código vistos y no vistos en clase. Se deberá documentar el por que hicieron los cambios y en donde se encontraban en forma de reporte indicando el antes y después así como el nombre de la refactorización utilizada. Laboratorio 3

10 Nombre de la Refactorización: Números mágicos Localización: Archivo.java líneas x-y Código fuente: listado de código Código reestructurado: cómo queda el código modificado. Pueden utilizar un procesador de textos o bien indicarlo en el código fuente. Laboratorio 3

11 El software evoluciona constantemente… Condiciones reestructuración EL PROBLEMA Ciclo de Desarrollo 20% Mantenimiento Depuración + Extender Funcionalidad 80% Valor ($$) del Mantenimiento Confiabilidad del Aplicativo Tiempo de Vida útil Nivel de Mantenibilidad Buenas Prácticas de Diseño y Codificación ¿Cómo detectarlas? ¿Cómo medirlas? Detección de Malas Prácticas de Diseño o Codificación

12 La refactorización es el arte de mejorar de manera segura, el diseño de código existente. Esto tiene algunas implicaciones: –La Refactorización no solo incluye hacer cambios en un sistema. –Refactorización no es reescribir todo desde cero. –Refactorización no es cualquier reestructuración pensada para mejorar código. Reestructuración y Diseño

13 Los “smells” en el código son señales de alerta respecto a problemas potenciales en el código. No todos los smells indican un problema, pero la mayoría son dignas de un vistazo y una decisión. Los “smells” usualmente describen problemas localizados en algún lugar. Es cómo la analogía de un refrigerador… si algo huele mal posiblemente esté mal. Reestructuración y desempeño

14 El origen de la reestructuración se da una vez construido código, no se puede aplicar refactoring si previamente no hay código. Se pueden aplicar buenas prácticas de codificación desde el inicio, pero siendo puritanos realmente esto no es refactoring. Una vez detectado “malos olores”, se deben de priorizar y comenzar por aquel olor que es el más fuerte. Origen de la Reestructuración

15 Se detecta una refactroización apropiada para el smell, se aplica y se observa que los cambios realizados sigan cumpliendo con las restricciones del software. Se sugiere que se realicen transformaciones seguras. A continuación se verá el proceso de aplicar una reestructuración ya conocida por nostros: “Encpasulate Field”. Origen de la Reestructuración

16 El objetivo de esta reestructuración es hacer que los objetos no puedan acceder a los atributos de una clase de manera directa sino a través de métodos para acceder a los campos. Los pasos a seguir son: Crear los méodos get y set para cada atributo que se desea acceder. Encapsulate Field

17 Localizar todas las referencias y reemplazar todos los accesos a los campos con los métodos get y todas las asignaciones con set. Compilar y cambiar después de cada referencia. Declarar el campo como privado. Compilar y probar. Encapsulate Field

18 Las herramientas automatizadas de refactoring como la incluida en NetBeans realizan estos pasos de manera segura. Inicialmente se tiene el código: public class Persona { public String name } En el caso de prueba unitaria se tiene: Encapsulate Field

19 Person person; person.name = “Juan Pérez”; assertEquals(“Juan Pérez”, person.name); Después se aplica el paso 1 (crear métodos get y set): public class Person { public String name; public String getName() {return name;} public String setName(String NewName){ name=NewName;} Encapsulate Field

20 Ahora se aplica el paso 2: Encontrar todos los clientes; reemplazar referencias con llamadas. Se modifica la primera referencia. Antes: person.name = “Juan Pérez”; Después: person.setName(“Juan Pérez”); Se compila y prueba. Ahora se sigue con la reestructuración de la siguiente referencia: Encapsulate Field

21 Antes: assertEquals( “Juan Pérez”, person.name); Después: assertEquals( “Juan Pérez”, person.getName()); Se compila y vuelve a probar. Una vez que se ha probado que funciona se sigue el paso 4 de hacer privado el campo: public class Person{ private String name; ……} Encapsulate Field

22 Realiza las siguientes reestructuraciones en el código anterior: Empaqueta los códigos fuentes en el espacio de nombres llamado reestructuración. Sube todas las variables usadas en el método main() de la clase Fecha como atributos de las clase, las cuales serán privados y no deberán ser estáticos. Actividad

23 Realiza un constructor sin parámetros para inicializar los atributos del paso anterior (recuerda que para que se ejecute el constructor se debe crear el objeto). No se recomienda que el método main() lance excepciones por lo que habrá que modificar el método para que caché la excepción. Actividad

24 No se recomienda construir un objeto apartir de construir un objeto directamente como es el caso del objeto derivado de BufferedReader por lo que se recomienda separarlo en dos objetos diferentes. Sólo utilizar un objeto validaFecha en el método main(). Actividad

25 Demasiada indirección es mala. Modificar el método valida() de la clase validaFecha para que su funcionalidad se encuentre en el constructor de la clase. Nótese que esta refactroización implica el cambio en la clase Fecha. Cambie todas los números mágicos de la clase valida Fecha por constantes. Actividad

26 En las condicionales del método valida() realizar el refactoring de introducir variables de explicación. En el método imprime, atrapar la posible excepción que puede ocasionar los métodos de conversión parseInt. No utilizar la clase genérica Exception. Actividad

27 Problema: el código de un método tiene una asignación a un parámetro. Solución: usar una variable temporal. Motivo: no tiene nada de malo, el problema es que causa mucha confusión para entender si un parámetro se pasa por valor o por referencia. Java utiliza solamente paso por valor. Remover Asignación Parámetros

28

29 Problema: hay un método largo que usa variables locales de tal forma que no es posible aplicar “Extraer Método”. Solución: convertir el método en un objeto, de modo que todas las variables locales sean a tributos de dicho objeto. A continuación se puede descomponer el método en varios métodos del mismo objeto. Reemplazar Mét. por Obj. Mét.

30

31 Problema: se quiere cambiar un algoritmo por otro que es más claro y/o eficiente. Solución: cambiar el cuerpo del método por el nuevo algoritmo. Substitución de Algoritmo

32

33 Las metodologías ágiles que basan el desarrollo en primero entregar soluciones que documentación recomiendan realizar reestructuración de códigos en todo momento. En estas metodologías primero se programa y se verifica que se cumpla con las pruebas unitarias. Una vez pasadas las pruebas se debe de refactorizar el código generado. Refactoring Ágil

34 Realizar una aplicación agenda de directorios en donde se pueden tener Amigos, Familia y Servicios. Cada categoría puede tener un arreglo de objetos donde cada objeto tiene un nombre y un teléfono. Esta clase tiene los métodos de capturar() para pedir datos a los usuarios y buscar() para encontrar los datos de los objetos. Su entregable no debe de tener malos olores. Actividad

35 Refactoring aplicables: En la clase Autobuses se puede aplicar el refactoring de extraer el método hay mucho código repetido (del switch no nos salvamos). Se tiene muchas depencias en cuestión de las líneas que son estáticas (4) y que quizás en un futuro pudieran ser variables (Aplicar Refactoring para mejora). Práctica 3

36 La clase boletos no tiene razón de ser. Están mezclado la lógica de aplicación y la presentación en cada una de las clases (Aplicar Modelo-Vista-Controlador). El refactoring de nombre de variables (que aplicaron) en las GUIs es de suma importancia. También se recomienda cambiar el nombre de los manejadores de eventos: ¿qué hace de la clase línea jButton15ActionPerformed()? Práctica 3

37 En algunas condicionales se puede aplicar el refactoring de introducir variable de explicación. No se tiene un sangrado adecuado de las líneas de código. Práctica 3

38 Una de las decisiones fundamentales en el diseño orientado a objetos es dónde poner las responsabilidades. Puesto que es casi imposible hacerlo bien a la primera, las siguientes refactorizaciones nos ayudarán a lidiar con este problema. La refactorización más básica es mover el método de una clase a otra. Esto se debe de hacer sólo cuando el método utiliza más funcionalidad de otra clase diferente a la que lo contiene Mover Funcionalidad / Objetos

39 El método de la clase original de preferencia debe desaparecer o bien hacer referencia al de la nueva clase. Una clase es responsable de una cosa Mover Método

40 ¿Qué tiene de malo este código? Lab 1: Ejercicio de Fowler Ejemplo de Mover Método

41 El método amountFor utiliza muchas referencias a métodos de la clase Rental. Haciendo un análisis a mayor profundidad se puede determinar quela clase cliente no debe de tener la responsabilidad de calcular el costo de una renta, que realmentele corresponde a la clase Renta. ¿Cómo debe de quedar la refactorización? Ejemplo de Mover Método

42 ¿Qué le hace falta? Ejemplo de Mover Método

43 Actualizar la referencia Nótese que el método no se eleminó de la clase original. Se escogió una mejor forma de llamarlo. Ejemplo de Mover Método

44 Del programa Agenda realizado en la clase anterior determine si todas las clases tienen asignadas de forma correcta su responsabilidad. Determine si se puede aplicar o no la refactorización de mover métodos. En caso de no poderse realizar deberá de argumentar de forma extensa su respuesta. ¿Qué es un walkthrough? Se pasará a hacer una prueba de recorrido. Actividad

45 Las pruebas de recorrido es una forma básica de las revisiones técnicas formales especializadas en la inspección del código. Un grupo de personas empiezan a detallar y explicar que hace cada línea del código del programa (aquellas que no quedan claro). En la programación por pares se realiza de forma casi automática Walkthrough

46 Un atributo es más utilizado por otra clase que por la clase que lo contiene. Se soluciona creando una nueva clase, colocando el atributo en esta nueva clase y cambiando todas las referencias hacia los clientes. Move Field

47 Hay un clase que está haciendo el trabajo de dos. Se soluciona creando una nueva clase colocando los métodos y atributos pertinentes en la nueva clase. Extract Class

48 Una clase no está haciendo nada. Se soluciona fusionando en una nueva clase los métodos y atributos de las dos clases anteriores. Cuando se tengan comportamientos diferentes, se deberán manejar clases aparte. Inline Class

49 Un cliente está llamando a la clase delegado de un objeto. Se soluciona creando métodos en la clase servidora que oculten dicha dependencia. Hide Delegate

50 Lo contrario de lo anterior. Una clase está haciendo demasiada delegación. Se soluciona dejando que el cliente se comunique directamente con el delegado. Remove Middleman

51 Dado el programa de la agenda que se realizó previamente se realizarán algunas mejoras propuestas. Se deberá aplicar técnicas de historia local y diferenciación de archivos. Práctica 4

52 La ofuscación es una técnica avanzada de refactorización que permite a un código mantenerle obscuro (es decir no muy legible) con diversos propósitos de optimización. ¿Para que se hace ofuscación? ¿No viola esto el principio de claridad en la implantación? Ofuscación

53 La ofuscación se realiza en muchas casos para hacer un código ilegible, también en muchos casos se puede reducir el tamaño del código fuente y del código binario realizado. Al realizar cualquier tipo de programa se puede aplicar técnicas de reingeniería como la ingeniería inversa para de un código binario tratar de obtener su código fuente. Ofuscación

54 En mucho tipos de aplicaciones como las aplicaciones móviles se ofusca el código objeto generado para obtener un código más pequeño. Un programa puede ser fácilmente decompilable, por este motivo se ofusca con la premisa de que si esto llegará ocurrir, el que lo hiciera le costaría mucho trabajo entender el programa y modificarlo. Ofuscación

55 En algunos casos la ofuscación se logra simplemente refactorizando el nombre de las variables pero en muchos casos esto no sirve. Para lograr la ofuscación se deberá modificar el flujo del programa de tal forma que menos instrucciones o en algunos casos más instrucciones deben de realizar el mismo programa. Ofuscación

56 En algunos casos resulta que ofuscar el código puede ser que el tamaño del código fuente y del programa aumente, debido a que es común que las variables tengan nombres muy grandes o bien se incluyan instrucciones extras, se descompongan ciclos, se cambien y mapeen estructuras, etc. Existen concursos de ofuscación de código Ofuscación

57

58 Realizar la ofuscación del código de las clases del laboratorio 1 (ejemplo de Fowler) con las siguientes características: Refactoring de identificadores (métodos, clases, atributos) con nombres muy grandes y poco descriptivos. Agregando comentarios javadoc sin coherencia. Agregando funcionalidades no utilizadas así como código no útil. Actividad

59 Comparar su proyecto ofuscado con el original a través de diff y patch Determina el grado de legibilidad de la aplicación calculado a través de la siguiente fórmula: Líneas negras / líneas blancas * 100 NÓTESE: LA OFUSCACIÓN NO HACE REUSABLE EL CÓDIGO PERO SI SEGURO Actividad

60 De la página principal del sitio Web de su profesor: http://antares.itmorelia.edu.mx/~jcolivar/ http://antares.itmorelia.edu.mx/~jcolivar/ Realizar ofuscación de códigos para obtener el archivo más pequeño posible. Por ejemplo si la página es de 10KB y se reduce en 8KB es buena la ofuscación. Trate de eliminar líneas en blanco. La página NO debe de cambiar. Se premiará al que logre el menor tamaño posible con 1 PUNTO EXTRA. En caso de empate se anula. Tarea

61 Reemplazar valores de datos con objetos: En algunas ocasiones se ocupa mejor la semántica de los datos. Refac. de Organización de Datos

62 En la práctica pasada se utilizó la clase Teléfono dado que es más fácil de ser extensible. ¿Qué hubiera sucedido si el teléfono fuera cadena y se necesitarán rutinas para formatear, extraer el prefijo, etc.? Problablemente estaríamos duplicando código y/o haciéndolo menos legible. Refactoring de números mágicos entra dentro de esta categoría. Reemp. Val. datos con objetos

63 Cuando se devuelvan colecciones (estructuras de datos) se debe de proteger la obtención de las mismas a través de un objeto no cambiante. Esto con la finalidad que a partir de un método get no se pueda modificar la colección. Encapsular Colección

64 ¿Cómo implementarla? Sino se tiene alguna interfaz para no modificar estructura de datos se deberá construir un objeto nuevo. Reemplazar códigos de tipo por clases Se da cuando una clase tiene atributos numéricos repetitivos que no afectan su comportamiento. Encapsular Colección

65 La solución es reemplazar los números por una clase. Reemp. Cod. Tipos por clase

66 Cuando se tiene atributos de código que afectan al comportamiento de la clase se deberá reemplazar por sublcases: Reemp. Cod. Tipos por subclase

67 Un síntoma frecuente de este malo olor es cuando se tienen varias condicionales anidadas (switches, ifs, etc.). De hecho las estructuras anidadas o con complejidades ciclomáticas muy altas son carácterísticas fundamentales de cualquier mal olor. Es recomendable que el polimorfismo encapsule esta complejidad. Reemp. Cod. Tipo por subclase

68 En algunas ocasiones no se puede realizar generalización al momento de reemplazar el atributo repetitivo por lo que se recomienda utilizar el patrón Strategy o un objeto Estado: Reemp. Cod. Tipo por Estrategia

69 Problema: se tienen subclases que sólo varían en los datos que devuelven los métodos que se consideran constantes. Aunque son muy útiles, no exhiben un comportamiento distinto, por lo que habrá que eliminar la generalización. Solución: subir tanto el atributo como el método a la clase padre y eliminar las subclases. Reemp. Subclases con campos

70

71 Se dará un código el cual deberá reestructurarse en las cadenas de texto que forman parte de la interfaz, de tal forma que permita la internacionalización (se utilizará el asistente de internacionalización de NetBeans) de la aplicación. Se realizará reestructuración de datos de una aplicación legada que utiliza archivos para manejar base de datos relacionales. Práctica 5

72 Se deberá realizar un diseño e implementación de la base de datos así como la migración de los datos existentes. Se tendrá que instalar un manejador de base de datos y realizar conexiones a la misma. Se harán las modificaciones pertinentes para que la aplicación funcione con la base de datos y sea más extensible y segura. Práctica 5

73 Las expresiones condicionales son unas de las estructuras preferidas para vivir de los malos olores. A continuación se muestran algunos ejemplos de reestructuraciones. Descompose conditional: se tiene una condicional compleja. Se soluciona extrayendo métodos para la condición y para las acciones de falso y verdadero. Simp. Expresiones Condicionales

74 Descomposición Condicionales

75 Existe una serie de condicionales que se pueden unificar. Consolidar Expresiones Cond.

76 Problema: Se repite el mismo fragmento de código en todas las ramas. Solución: Sacarlo de la expresión Consolidar Frag. Cond. Duplicado

77 Problema: una variable está actuando como un indicador de control para una serie de expresiones lógicas. Solución: sustituir por breaks o returns Remover Bandera de Control ¿Cómo debe de quedar este código reestructurad o?

78 El primer enfoque es utilizar break-continue que es la manera predeterminada de lenguajes como C y Java. Es más elegante el uso de returns. Aunque sólo aplica cuando son métodos. A continuación se detalla un ejemplo de reestructuración a través de return. Remover Bandera de Control

79

80 En el código anterior found sirve de variable de control y además guarda el resultado. Se puede simplicar este método realizando la extracción de otro método: void checkSecurity(String[ ] people) { String found = foundMiscreant(people); someLaterCode(found); } Remover Bandera de Control

81

82 Continuar con la práctica pasada. Revisión de algunos detalles Actividad

83 Problema: un método tiene un comportamiento condicional que obscurece el flujo del programa. Solución: implementar “clausulas guardianas” para los casos especiales. Las clausulas guardianas permiten el manejo de datos de forma más segura. Pueden ser elementos de control como break, return o bien alguna clase dada. Reemp cond. Anidadas con guard

84

85 Malor olor: cuando se tienen muchas comprobaciones de si un objeto es nulo. Desodorante: sustituir el valor null por un objeto null Introducir Objeto Null

86 Malor olor: un código hace un asunción sobre el estado del programa. Desodorante: hacer explícita la asunción a través de un aserción. Por ejemplo en cierto tipo de validaciones como la raíz cuadrada asumimos que el dato introducido es positivo. Introducir Aserción

87 ¿Hay aserciones en java? Introducir Aserción

88 Si. El código anterior es en C# Cuando una aserción falla se produce una excepción “unchecked” Indican errores de programación (que deben ser corregidos, no capturados). De hecho, normalmente las aserciones se desactivan en el código de producción. Introducir Aserción

89 Las aserciones sólo están disponibles a partir de JDK1.4, si se desea hacer una aserción se deberá de lanzar una excepción: if (! (estamos_como_queremos) ) throw new Error("fallo en tal zona del programa"); Pero este esquema maneja banderas lo cual se acaba de ver que no es nada bueno. Aserciones en Java

90 En su lugar se puede manejar: assert estamos_como_queremos; El cual evaluará la expresión indicada para obtener un valor de verdad. Las aserciones han caído en desuso con la extensa proliferación de frameworks para pruebas unitarias donde se hacen aserciones: assertEquals() por ejemplo. Aserciones en Java

91 IMPORTANTE: las validaciones de datos no son aserciones!!! Las validaciones de datos se deben de hacer. Una aserción en teoría es para indicar una porción de código que no debiera de ejecutarse. Para indicar la versión de java al momento de compilar se deberá habilitar la opción –source seguido del numero de versión. Aserciones en Java

92 IMPORTANTE: el contenido colocado en assert no debe de ser vital para la ejecución del código. Suponga el siguiente código: public int calcularSalario(int comisiones){ assert comisiones >=0; return 1000+(comisiones*20); } Aserciones en Java

93 Y el siguiente método para probarlo: public static void main(String args[]){ int comisiones = 5; int sueldo = calcularSalario(comisiones); System.out.println(“Sueldo=”+ sueldo); } Si se corre tanto para valores de 5 y -5 para comisiones no sucede nada. ¿Por qué? Aserciones en Java

94 Se ocupa activar las directivas del manejo de aserciones: -ea: activa aserciones -da: desactiva aserciones CONSEJO: en caso de duda siempre meter aserciones. Aserciones en Java

95 Realizar el programa (modificar si ya lo tienen) de la obtención de ecuaciones de segundo grado por fórmula general, para que maneje aserciones. Se deberá contar con un método main() y con interface de usuario ¿cuántas aserciones manejaste? Actividad

96 Cuando se está en fase de producción es muy común sustituir las aserciones y pruebas unitarias con bloques try-catch imprimiendo la traza del error en pantalla o un archivo. Realizar está acción de esta forma no es buena práctica de programación. El atrapar excepciones es para darles solución aunque en algunos casos como abrir o crear un archivo sean excepciones mortales. Manejo de Errore con try-catch

97 Cuando se está en fase de producción es muy común sustituir las aserciones y pruebas unitarias con bloques try-catch imprimiendo la traza del error en pantalla o un archivo. Realizar está acción de esta forma no es buena práctica de programación. El atrapar excepciones es para darles solución aunque en algunos casos como abrir o crear un archivo sean excepciones mortales. Manejo de Errore con try-catch

98 Otra mala práctica de programación es atrapar Excepciones genéricas (objeto de la clase Exception) si bien es cierto que nos permiten ahorrar en muchas ocasiones tiempo hacen que el software no sea predecible. Se pueden utilizar considerando las demás excepciones. Siempre hay que saber que tipos de errores se pueden presentar y darles un tratamiento. Manejo de Errore con try-catch

99 Parte de las malas prácticas del uso de try- catch en lenguajes con marcado de errores implícito como Java es el hecho que al forzarnos a atrapar el error solamente lo hacemos para que corra el programa y no en si por manejar el error. En algunas ocasiones no siempre es obligatorio. Se recomienda lanzar errores en métodos que implementen el modelo, mientras que en la interfaz se deben atrapar. Manejo de Errore con try-catch

100 Por cada excepción que se lance debe de haber una parte donde se atrape. Por tal motivo es una mala práctica de programación poner una excepción en el método main(). Se recomienda crear nuestros propios manejadores de errores extendiendo de la clase Exception y colocando aquellos métodos y atributos para procesar el error. Manejo de Errore con try-catch

101 Modificar el programa anterior (raíces de una ecuación cuadrática) para que maneje excepciones y haga las validaciones respectivas. Se contará con una interfaz con JOptionPane. Las entradas se validarán para que al encontrarse un error se marque una excepción creada por nosotros. Actividades

102 Para posteriormente procesarlas en la interfaz. Al introducir un valor incorrecto se deberá quedar en donde está el error para volver a introducir la entrada. Las clases Excepciones a Generar son: NoPolinomioCuadrado cuando a=0 y RaizImaginaria cuando el discriminante es <0. Actividades

103 Rename Method: cambiar el nombre de un método por otro más indiciativo. En muchas ocasiones no se puede a la primera vez pero no hay que caer en la tentación de dejarlo tal cual. Ref. mejorar Simplicidad Método

104 Problema: El método necesita que se le pase más información. Solución: agregar un parámetro. Si se necesita el método anterior se necesitará realizar polimorfismo. Add Parameter

105 En la medida de lo posible hay que evitar el tener una lista de parámetros muy grande. Siempre hay que ver si la información se puede obtener a través de otros objetos. Cuando se quede una lista muy grande de parámetros se recomienda enmascarar la lista de argumentos en un objeto estructura. Add Parameter

106 Malor olor: un método devuelve un valor pero también cambia el estado de un objeto. Desodorante: crear dos métodos uno para la consulta y otro para el modificador. Separate query from Modifier

107 Malor olor: varios métodos hacen lo mismo pero con diferentes parámetros. Desodorante: crear un método que use un parámetro para los diferentes valores. Parametizer Method

108 Malor olor: un método ejecuta distinto código dependiendo de un valor enumerado. Desodorante: crear un método separado para cada valor del parámetro. Es más claro tener el método switch.turnOn() que switch.setOn(true) Repl. Param. with Explicit Meth.

109

110 En la década de 1980’s los Sistemas de Información se desarrollaban con UI basadas en Texto. En la década de 1990’s los desarrollos fueron “visuales”. La década de 2000 se caracterizó por el desarrollo Web. Patrón MVC

111 En la década de 2010 se caracterizará probablemente por el desarrollo móvil y ubicuo. Si estas aplicaciones no se desarrollan de forma especial, se tendría que realizar la aplicación desde el inicio. Para solucionar este problema existe el patrón de diseño Modelo-Vista-Controlador. Patrón MVC

112

113 Modelo: lógica de datos. Si es java se trata de que sean beans. Vista: interfaz de usuario Controlador: liga tanto a la vista como al el controlador. Responde generalmente al manejo de eventos. Es mala recomendación dejar embebido en la interfaz código de lógica de programa. Patrón MVC

114 Dado un código fuente, refactorizarlo para que pueda ser convertido a una biblioteca dentro del paquete mx.edu.itmorelia.refactoring. Se deberá importarlo en otro proyecto donde se aplicará el patrón de diseño MVC. Donde el modelo está representado por nuestra biblioteca, el controlador contiene el método main() y construye tanto las vistas como el modelo. Práctica 6.

115 Se manejarán dos vistas: una en modo texto y otra en una GUI utilizando para ambas métodos de validación para la entrada de datos. El controlador encapsula la llamada a los métodos tanto del modelo como de la vista para que puedan trabajar de manera conjunta sin mucho acoplamiento. Práctica 6

116 Aplicación de Refactoring simples Del proyecto número uno (ejemplo de Fowler). Realizar las siguientes reestructuraciones: Extraer método dentro del método statement() de la clase customer en la parte del switch. Llamarlo amountFor para que recibe como argumento un objeto de la clase rental. Práctica 7

117 Cambiar las referencias necesarias en Customer.statement(). Cambiar el tipo de datos de amountFor a double (para un mejor desemepeño) actualizando las referencias. Dentro del código de amountFor renombrar las variables each por aRental, thisAmount por result. Práctica 7

118 Aplicar el refactoring Move Method amountFor de la clase Customer a Rental. Renombrar el método amountFor de la clase Rental a getCharge. Ajustar los cambios al método amountFor de la clase customer. Del método statement se Extraerá el método Frecuent Renter Points (porción del código que incrementa variable frequentRenterPoints). Práctica 7

119 El nuevo método se llamará getFrequentRenterPoints() y se implementará dentro de la clase Rental. Ahora se remplazarán todas las variables temporales. Se aplicará el refactoring Replace Temp with query a las variables totalAmount y frecuentRentalPoints del método Custromer.statement(). Primeramente todas las referencias a totalAmount se encapsularán en el método Práctica 7

120 getTotalCharge() contenido dentro de la clase Customer. Actualizar la referencia en la cadena result. Ahora realizar lo mismo con frequentRenterPoints con el método getTotalFrequentRenterPoints(). Nótese que en ambos casos se deberá repetir la estructura cíclica que los contenía (esto aumenta el código pero mejora la legibilidad del mismo). Práctica 7

121 Agregar una nueva funcionalidad a la clase Customer denominada htmlStatement() que haga exactamente lo mismo que statement() agregando etiquetas de HTML a la cadea de resultado. Aquí puede observarse cómo se aplican los refactoring de sustituir temps que parecían imprácticos. Práctica 7

122 Agregar una nueva funcionalidad a la clase Customer denominada htmlStatement() que haga exactamente lo mismo que statement() agregando etiquetas de HTML a la cadea de resultado. Aquí puede observarse cómo se aplican los refactoring de sustituir temps que parecían imprácticos. Los refactorings de ahora serán más interesantes. Práctica 7

123 Una problemática del código en Rental.getCharge() es el manejo de switch en getPrice() esto puede mejorarse si se aplica el refactoring de reemplazar la lógica condicional de PriceCode con polimorfismo. Esto implica en primera instancia que el método getCharge() deba de ser movido a la clase Movie actualizando su referencia en Rental.getCharge(). Práctica 7

124 Se deberá aplicar tambien mover método al método Rental.getFrequentRenterPoints() a la clase Movie actualizando las referencias. Ahora sí, podemos aplicar herencia. Definiendo tres subclases RegularMovie, ChildrensMovie y NewReleaseMovie todas ellas sobrecargando el método getCharge() de la clase padre (el demás funcionamiento no se modifica). Práctica 7

125 Esto parece una mejor opción. Al menos funciona para reemplazar la condicional con polimorfismo. Desafortunadamente esta implementación no es eficiente si una película cambia su clasificación durante el transcurso de su vida (no siempre será estreno por ejemplo, o podrá pasar de moda y aplicar algún descuento). Para hacer más extensible esto. Será necesario utilizar el patrón de diseño State (estado). Práctica 7

126 Para aplicar el patrón estado simplemente nuestra clase padre Movie delega funcionalidad a una nueva clase denomina Price que maneja la herencia de las clases RegularPrice, ChildrensPrice y NewReleasePrice. El primer cambio a aplicar es dentro del constructor de Movie el acceso al atributo _priceCode no puede realizarse de manera drecta (se está aplicando Replace TypeCode with State/Strategy). Práctica 7

127 Por lo que se deberá definir un método setPriceCode() y getPriceCode(). La clase Price debe definir como abstracta al igual que el método getPriceCode(). El método setPriceCode de la clase Movie debe definir en base a su argumento una estructura switch construyendo un objeto concreto de Price (RegularPrice, ChildrenPrice, NewReleasePrice). Práctica 7

128 Ahora se moverá la funcionalidad del método Movie.getCharge() a Price.getCharge() actualizando referencias respectivas. Ahora que se tiene el método Price.getCharge() se puede nuevamente reemplazar la condicional por polimorfismo, en este caso implementando la funcionalidad de cada switch dentro de las clases Price concretas. De esta forma Price.getCharge() pude ser manejada como abstracta. Práctica 7

129 Ahora se pude aplicar el refactoring anterior a Movie.getFrequentRenterPoints(). Por lo que se deberá mover a Price y actualizar las referencias. Para despues pasar dicha funcionalidad a la clase NewReleasePrice. En la clase Price el método siempre devuelve uno de valor (1). De esta forma se tiene la siguiente estructura final del proyecto. Práctica 7

130 Definir para cada paso de refactoring aplicado las nuevas pruebas unitarias que ayuden a validar que el software es correcto. Nótese como un proceso aparentemente simple (código de la práctica 1) puede volverse complejo si el refactoring no se realiza paso por paso. Práctica 7

131 Fowler, M. (1999), Refactoring, Adison-Wesley. Sanchez, M., (2009), Material del Curso de Reestructuración de Códigos, Instituto Tecnológico de Morelia. Referenicas

132 Dudas


Descargar ppt "Principios de Reestructuración M.C. Juan Carlos Olivares Rojas"

Presentaciones similares


Anuncios Google