Principios de Reestructuracin M C Juan Carlos Olivares

  • Slides: 132
Download presentation
Principios de Reestructuración M. C. Juan Carlos Olivares Rojas jcolivar@itmorelia. edu. mx http: //antares.

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

Competencias • Específica: conoce los términos básicos de la reestructuración de código e identifica

Competencias • 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 • Interpersonales: Capacidad crítica y autocrítica, Capacidad de trabajar en equipo interdisciplinario, Habilidad

Competencias • 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.

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

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

Evidencias • 30% Prácticas • 10% Otras actividades en el aula • 60% Actividad

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

Actividad • Descargar el código fuente de la página Web denominado Fecha. zip. Dicho

Actividad • Descargar el código fuente de la página Web denominado Fecha. zip. Dicho archivo comprimido consta de dos clases: Fecha y valida. Fecha. • 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.

Laboratorio 3 • Esta práctica de laboratorio cuenta para la unidad 1. • Refactoriza

Laboratorio 3 • 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 • En nuestro caso el paquete deberá comenzar con mx. edu. itmorelia

Laboratorio 3 • 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 • Una vez realizado el renombrado de modificadores se proseguirá con la

Laboratorio 3 • 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 • Nombre de mágicos la Refactorización: Números • Localización: Archivo. java líneas

Laboratorio 3 • Nombre de mágicos la Refactorización: Números • 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.

Condiciones reestructuración • El software evoluciona constantemente… Valor ($$) del Mantenimiento EL PROBLEMA Mantenimiento

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

Reestructuración y Diseño • La refactorización es el arte de mejorar de manera segura,

Reestructuración y Diseño • 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 desempeño • Los “smells” en el código son señales de alerta respecto

Reestructuración y desempeño • 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.

Origen de la Reestructuración • El origen de la reestructuración se da una vez

Origen de la Reestructuración • 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 • Se detecta una refactroización apropiada para el smell, se

Origen de la Reestructuración • 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”.

Encapsulate Field • El objetivo de esta reestructuración es hacer que los objetos no

Encapsulate Field • 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 • Localizar todas las referencias y reemplazar todos los accesos a los

Encapsulate Field • 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 • Las herramientas automatizadas de refactoring como la incluida en Net. Beans

Encapsulate Field • Las herramientas automatizadas de refactoring como la incluida en Net. Beans 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 Person person; person. name = “Juan Pérez”; assert. Equals(“Juan Pérez”, person. name);

Encapsulate Field Person person; person. name = “Juan Pérez”; assert. Equals(“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 get. Name() {return name; } public String set. Name(String New. Name){ name=New. Name; }

Encapsulate Field • Ahora se aplica el paso 2: Encontrar todos los clientes; reemplazar

Encapsulate Field • 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. set. Name(“Juan Pérez”); • Se compila y prueba. Ahora se sigue con la reestructuración de la siguiente referencia:

Encapsulate Field • Antes: assert. Equals( person. name); • Después: assert. Equals( person. get.

Encapsulate Field • Antes: assert. Equals( person. name); • Después: assert. Equals( person. get. Name()); “Juan Pérez”, • 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; ……}

Actividad • Realiza las siguientes reestructuraciones en el código anterior: • Empaqueta los códigos

Actividad • 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 • Realiza un constructor sin parámetros para inicializar los atributos del paso anterior

Actividad • 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 • No se recomienda construir un objeto apartir de construir un objeto directamente

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

Actividad • Demasiada indirección es mala. Modificar el método valida() de la clase valida.

Actividad • Demasiada indirección es mala. Modificar el método valida() de la clase valida. Fecha 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 • En las condicionales del método valida() realizar el refactoring de introducir variables

Actividad • 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 parse. Int. No utilizar la clase genérica Exception.

Remover Asignación Parámetros • Problema: el código de un método tiene una asignación a

Remover Asignación Parámetros • 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

Remover Asignación Parámetros

Reemplazar Mét. por Obj. Mét. • Problema: hay un método largo que usa variables

Reemplazar Mét. por Obj. Mét. • 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.

Reemplazar Mét. por Obj. Mét.

Substitución de Algoritmo • Problema: se quiere cambiar un algoritmo por otro que es

Substitución de Algoritmo • 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

Substitución de Algoritmo

Refactoring Ágil • Las metodologías ágiles que basan el desarrollo en primero entregar soluciones

Refactoring Ágil • 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.

Actividad • Realizar una aplicación agenda de directorios en donde se pueden tener Amigos,

Actividad • 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.

Práctica 3 • Refactoring aplicables: • En la clase Autobuses se puede aplicar el

Práctica 3 • 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 • La clase boletos no tiene razón de ser. • Están mezclado

Práctica 3 • 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 j. Button 15 Action. Performed()?

Práctica 3 • En algunas condicionales se puede aplicar el refactoring de introducir variable

Práctica 3 • 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.

Mover Funcionalidad / Objetos • Una de las decisiones fundamentales en el diseño orientado

Mover Funcionalidad / Objetos • 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 Método • El método de la clase original de preferencia debe desaparecer o

Mover Método • 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

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

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

Ejemplo de Mover Método • El método amount. For utiliza muchas referencias a métodos

Ejemplo de Mover Método • El método amount. For 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 • ¿Qué le hace falta?

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

Ejemplo de Mover Método • Actualizar la referencia • Nótese que el método no

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

Actividad • Del programa Agenda realizado en la clase anterior determine si todas las

Actividad • 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

Walkthrough • Las pruebas de recorrido es una forma básica de las revisiones técnicas

Walkthrough • 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

Move Field • Un atributo es más utilizado por otra clase que por la

Move Field • 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.

Extract Class • Hay un clase que está haciendo el trabajo de dos. Se

Extract Class • 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.

Inline Class • Una clase no está haciendo nada. Se soluciona fusionando en una

Inline Class • 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.

Hide Delegate • Un cliente está llamando a la clase delegado de un objeto.

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

Remove Middleman • Lo contrario de lo anterior. Una clase está haciendo demasiada delegación.

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

Práctica 4 • Dado el programa de la agenda que se realizó previamente se

Práctica 4 • 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.

Ofuscación • La ofuscación es una técnica avanzada de refactorización que permite a un

Ofuscación • 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 • La ofuscación se realiza en muchas casos para hacer un código ilegible,

Ofuscación • 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 • En mucho tipos de aplicaciones como las aplicaciones móviles se ofusca el

Ofuscación • 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 • En algunos casos la ofuscación se logra simplemente refactorizando el nombre de

Ofuscación • 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 • En algunos casos resulta que ofuscar el código puede ser que el

Ofuscación • 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

Ofuscación

Actividad • Realizar la ofuscación del código de las clases del laboratorio 1 (ejemplo

Actividad • 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 • Comparar su proyecto ofuscado con el original a través de diff y

Actividad • 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

Tarea • De la página principal del sitio Web de su profesor: http: //antares.

Tarea • De la página principal del sitio Web de su profesor: 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 10 KB y se reduce en 8 KB 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.

Refac. de Organización de Datos • Reemplazar valores de datos con objetos: • En

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

Reemp. Val. datos con objetos • En la práctica pasada se utilizó la clase

Reemp. Val. datos con objetos • 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.

Encapsular Colección • Cuando se devuelvan colecciones (estructuras de datos) se debe de proteger

Encapsular Colección • 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 • ¿Cómo implementarla? • Sino se tiene alguna interfaz para no modificar

Encapsular Colección • ¿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.

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

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

Reemp. Cod. Tipos por subclase • Cuando se tiene atributos de código que afectan

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

Reemp. Cod. Tipo por subclase • Un síntoma frecuente de este malo olor es

Reemp. Cod. Tipo por subclase • 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 encapsule esta complejidad. polimorfismo

Reemp. Cod. Tipo por Estrategia • En algunas ocasiones no se puede realizar generalización

Reemp. Cod. Tipo por Estrategia • 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. Subclases con campos • Problema: se tienen subclases que sólo varían en los

Reemp. Subclases con campos • 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

Reemp. Subclases con campos

Práctica 5 • Se dará un código el cual deberá reestructurarse en las cadenas

Práctica 5 • 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 Net. Beans) 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 • Se deberá realizar un diseño e implementación de la base de

Práctica 5 • 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.

Simp. Expresiones Condicionales • Las expresiones condicionales son unas de las estructuras preferidas para

Simp. Expresiones Condicionales • 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.

Descomposición Condicionales

Descomposición Condicionales

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

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

Consolidar Frag. Cond. Duplicado • Problema: Se repite el mismo fragmento de código en

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

Remover Bandera de Control • Problema: una variable está actuando como un indicador de

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

Remover Bandera de Control • El primer enfoque es utilizar break-continue que es la

Remover Bandera de Control • 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

Remover Bandera de Control

Remover Bandera de Control • En el código anterior found sirve de variable de

Remover Bandera de Control • 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 check. Security(String[ ] people) { String found = found. Miscreant(people); some. Later. Code(found); }

Remover Bandera de Control

Remover Bandera de Control

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

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

Reemp cond. Anidadas con guard • Problema: un método tiene un comportamiento condicional que

Reemp cond. Anidadas con guard • 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

Reemp cond. Anidadas con guard

Introducir Objeto Null • Malor olor: cuando se tienen muchas comprobaciones de si un

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

Introducir Aserción • Malor olor: un código hace un asunción sobre el estado del

Introducir Aserción • 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 • ¿Hay aserciones en java?

Introducir Aserción • ¿Hay aserciones en java?

Introducir Aserción • Si. El código anterior es en C# • Cuando una aserción

Introducir Aserción • 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.

Aserciones en Java • Las aserciones sólo están disponibles a partir de JDK 1.

Aserciones en Java • Las aserciones sólo están disponibles a partir de JDK 1. 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 • En su lugar se puede manejar: • assert estamos_como_queremos; •

Aserciones en Java • 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: assert. Equals() por ejemplo.

Aserciones en Java • IMPORTANTE: las validaciones de datos no son aserciones!!! • Las

Aserciones en Java • 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 • IMPORTANTE: el contenido colocado en assert no debe de ser

Aserciones en Java • 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 calcular. Salario(int comisiones){ assert comisiones >=0; return 1000+(comisiones*20); }

Aserciones en Java • Y el siguiente método para probarlo: public static void main(String

Aserciones en Java • Y el siguiente método para probarlo: public static void main(String args[]){ int comisiones = 5; int sueldo = calcular. Salario(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 • Se ocupa activar las directivas del manejo de aserciones: •

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

Actividad • Realizar el programa (modificar si ya lo tienen) de la obtención de

Actividad • 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?

Manejo de Errore con try-catch • Cuando se está en fase de producción es

Manejo de Errore con try-catch • 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 • Cuando se está en fase de producción es

Manejo de Errore con try-catch • 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 • Otra mala práctica de programación es atrapar Excepciones

Manejo de Errore con try-catch • 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 • Parte de las malas prácticas del uso de

Manejo de Errore con try-catch • Parte de las malas prácticas del uso de trycatch 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 • Por cada excepción que se lance debe de

Manejo de Errore con try-catch • 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.

Actividades • Modificar el programa anterior (raíces de una ecuación cuadrática) para que maneje

Actividades • 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 JOption. Pane. • Las entradas se validarán para que al encontrarse un error se marque una excepción creada por nosotros.

Actividades • Para posteriormente procesarlas en la interfaz. • Al introducir un valor incorrecto

Actividades • 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: No. Polinomio. Cuadrado cuando a=0 y Raiz. Imaginaria cuando el discriminante es <0.

Ref. mejorar Simplicidad Método • Rename Method: cambiar el nombre de un método por

Ref. mejorar Simplicidad Método • 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.

Add Parameter • Problema: El método necesita que se le pase más información. •

Add Parameter • 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 • En la medida de lo posible hay que evitar el tener

Add Parameter • 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.

Separate query from Modifier • Malor olor: un método devuelve un valor pero también

Separate query from Modifier • 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.

Parametizer Method • Malor olor: varios métodos hacen lo mismo pero con diferentes parámetros.

Parametizer Method • 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.

Repl. Param. with Explicit Meth. • Malor olor: un método ejecuta distinto código dependiendo

Repl. Param. with Explicit Meth. • 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. turn. On() que switch. set. On(true)

Repl. Param. with Explicit Meth.

Repl. Param. with Explicit Meth.

Patrón MVC • En la década de 1980’s los Sistemas de Información se desarrollaban

Patrón MVC • 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 • En la década de 2010 se caracterizará probablemente por el desarrollo

Patrón MVC • 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

Patrón MVC

Patrón MVC • Modelo: lógica de datos. Si es java se trata de que

Patrón MVC • 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.

Práctica 6. • Dado un código fuente, refactorizarlo para que pueda ser convertido a

Práctica 6. • 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 • Se manejarán dos vistas: una en modo texto y otra en

Práctica 6 • 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 7 • Aplicación de Refactoring simples • Del proyecto número uno (ejemplo de

Práctica 7 • 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 amount. For para que recibe como argumento un objeto de la clase rental.

Práctica 7 • Cambiar las referencias Customer. statement(). necesarias en • Cambiar el tipo

Práctica 7 • Cambiar las referencias Customer. statement(). necesarias en • Cambiar el tipo de datos de amount. For a double (para un mejor desemepeño) actualizando las referencias. • Dentro del código de amount. For renombrar las variables each por a. Rental, this. Amount por result.

Práctica 7 • Aplicar el refactoring Move Method amount. For de la clase Customer

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

Práctica 7 • El nuevo método se llamará get. Frequent. Renter. Points() y se

Práctica 7 • El nuevo método se llamará get. Frequent. Renter. Points() 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 total. Amount y frecuent. Rental. Points del método Custromer. statement(). • Primeramente todas las referencias a

Práctica 7 • get. Total. Charge() contenido dentro de la clase Customer. Actualizar la

Práctica 7 • get. Total. Charge() contenido dentro de la clase Customer. Actualizar la referencia en la cadena result. • Ahora realizar lo mismo con frequent. Renter. Points con el método get. Total. Frequent. Renter. Points(). • 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

Práctica 7 • Agregar una nueva funcionalidad a la clase Customer denominada html. Statement()

Práctica 7 • Agregar una nueva funcionalidad a la clase Customer denominada html. Statement() 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 • Agregar una nueva funcionalidad a la clase Customer denominada html. Statement()

Práctica 7 • Agregar una nueva funcionalidad a la clase Customer denominada html. Statement() 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

Práctica 7 • Una problemática del código en Rental. get. Charge() es el manejo

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

Práctica 7 • Se deberá aplicar tambien mover método al método Rental. get. Frequent.

Práctica 7 • Se deberá aplicar tambien mover método al método Rental. get. Frequent. Renter. Points() a la clase Movie actualizando las referencias. • Ahora sí, podemos aplicar herencia. Definiendo tres subclases Regular. Movie, Childrens. Movie y New. Release. Movie todas ellas sobrecargando el método get. Charge() de la clase padre (el demás funcionamiento no se modifica).

Práctica 7 • Esto parece una mejor opción. Al menos funciona para reemplazar la

Práctica 7 • 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 • Para aplicar el patrón estado simplemente nuestra clase padre Movie delega

Práctica 7 • 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 Regular. Price, Childrens. Price y New. Release. Price. • El primer cambio a aplicar es dentro del constructor de Movie el acceso al atributo _price. Code no puede realizarse de manera drecta (se está aplicando Replace Type. Code with State/Strategy).

Práctica 7 • Por lo que se deberá definir un método set. Price. Code()

Práctica 7 • Por lo que se deberá definir un método set. Price. Code() y get. Price. Code(). • La clase Price debe definir como abstracta al igual que el método get. Price. Code(). • El método set. Price. Code de la clase Movie debe definir en base a su argumento una estructura switch construyendo un objeto concreto de Price (Regular. Price, Children. Price, New. Release. Price).

Práctica 7 • Ahora se moverá la funcionalidad del método Movie. get. Charge() a

Práctica 7 • Ahora se moverá la funcionalidad del método Movie. get. Charge() a Price. get. Charge() actualizando referencias respectivas. • Ahora que se tiene el método Price. get. Charge() 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. get. Charge() pude ser manejada como abstracta.

Práctica 7 • Ahora se pude aplicar el refactoring anterior a Movie. get. Frequent.

Práctica 7 • Ahora se pude aplicar el refactoring anterior a Movie. get. Frequent. Renter. Points(). • Por lo que se deberá mover a Price y actualizar las referencias. Para despues pasar dicha funcionalidad a la clase New. Release. Price. 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 • Definir para cada paso de refactoring aplicado las nuevas pruebas unitarias

Práctica 7 • 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.

Referenicas • Fowler, M. (1999), Refactoring, Adison-Wesley. • Sanchez, M. , (2009), Material del

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

Dudas

Dudas