wuolah-free-TEMA-3-gulag-free.pdf
Document Details
Uploaded by WellPositionedTurkey
Tags
Full Transcript
TEMA 3. MANTENIBILIDAD Mantenibilidad del software ▪ ▪ ▪ ▪ Tipos de mantenimiento: o Correctivo: modificación de un software para corregir errores o problemas. o Adaptativo: modificación de un software para que continúe siendo usable en un entorno que ha cambiado o Perfectivo: modificación de...
TEMA 3. MANTENIBILIDAD Mantenibilidad del software ▪ ▪ ▪ ▪ Tipos de mantenimiento: o Correctivo: modificación de un software para corregir errores o problemas. o Adaptativo: modificación de un software para que continúe siendo usable en un entorno que ha cambiado o Perfectivo: modificación de un software para mejorar su rendimiento o mantenibilidad o Preventivo: modificación de un software para corregir defectos latentes en el software antes de que se hagan efectivos Mantenibilidad: cómo de fácil es modificar un software. “Software should be written in such a way so that it can evolve to meet the changing needs of customers.” Principios de mantenibilidad: conjunto de buenas prácticas sobre el tamaño, número de parámetros, puntos de decisión y otras propiedades del código fuente. o Mantenibilidad tiene impacto en el negocio o Período medio de mantenimiento del software de unos 10 años: peticiones continuas de mantenimiento correctivo como adaptativo. o Reducciónde costes y esfuerzos en las tareas de mantenimiento en sistemas "mantenibles" o Negocio sostenible requiere software sostenible La mantenibilidad como catalizador de otras características de la calidad del software. o Un SW mantenible permite mejorar otras áreas de calidad como rendimiento, eficiencia, seguridad, ... Mantenibilidad del software – Mitos ▪ ▪ ▪ ▪ Misunderstanding: Maintainability is the same as the absence of bugs “You said the system has above-average maintainability. However, it turns out it is full of bugs!”... Misunderstanding: Maintainability is a binary quantity: My team repeatedly has been able to fix bugs in this system. Therefore, it has been proven that it is maintainable.” Misunderstanding: Maintainability is language-dependent: “Our system uses a state-ofthe-art programming language. Therefore, it is at least as maintainable as any other system.” Misunderstanding: Maintainability is industry-dependent: “My team makes embedded software for the car industry. Maintainability is different there.” Refactorización ▪ ▪ ▪ La refactorización es el proceso de introducir mejoras en un programa para ralentizar la degradación por el cambio (Opdyke y Johnson, 1990). La refactorización es el proceso de cambiar un sistema de software de forma que no altere el comportamiento externo del código pero mejore su estructura interna. [Fowler02] Implica modificar un programa para mejorar su estructura, reducir su complejidad o hacerlo más fácil de entender. Cuando refactorizas no deberías añadir ni modificar funcionalidad. La refactorización posibilita y facilita el mantenimiento. Ejemplos: o borrar código duplicado (reorganización de una clase mediante herencia) o reemplazar código por la llamada a un método definido en un paquete/librería o o ▪ ▪ ▪ ▪ ordenar y renombrar atributos y métodos refactorizar la arquitectura – reemplazar código existente con nuevo código que implementa un nuevo patrón Fowler et al. (1999) sugieren que existen situaciones estereotipadas (él las llama "malos olores") en las que se puede mejorar el código de un programa. Bad smells en el código; el diseño y arquitectura; pruebas; rendimiento; bases de datos; usabilidad; etc. Los code smells: o Son un indicador o síntoma de un problema de diseño más profundo. o Suelen ser una solución pobre a un problema. o Contravienen mejores prácticas. o Tienen un impacto negativo sobre la calidad (dificultan la evaluación y el mantenimiento de un sistema) o Recurrencia: se pueden definir como errores recurrentes. La refactorización no se debe hacer de manera simultánea a otros cambios que afecten a la funcionalidad. Bad Smells 1. Código duplicado: En un programa puede incluirse código igual o muy similar en distintos lugares. Esto puede eliminarse e implementarse como un único método o función que se llame según sea necesario. 2. Métodos largos: Si un método es muy largo, debería diseñarse un número de métodos más cortos. 3. Sentencias de conmutación (case): A menudo implican duplicación, ya que la conmutación depende del tipo de algún valor. Las sentencias switch pueden estar dispersas por un programa. En los lenguajes orientados a objetos, a menudo se puede utilizar el polimorfismo para lograr lo mismo. 4. Agrupación de datos: La agrupación de datos se produce cuando el mismo grupo de elementos de datos (campos en clases, parámetros en métodos) se repite en varios lugares de un programa. A menudo pueden sustituirse por un objeto que encapsule todos los datos. 5. Generalidad especulativa: Se produce cuando los desarrolladores incluyen generalidades en un programa por si fueran necesarias en el futuro. A menudo puede eliminarse simplemente. (A veces se genera código "por si acaso" para soportar características que nunca se implementan) Análisis estático de código ▪ ▪ ▪ IDEs: IntelliJ, PMD Eclipse Plugin: análisis estático de código y detección de code smells: análisis de dependencias, código duplicado, código muerto (variables, métodos y parámetros no usados, bloques catch vacíos, creación de objetos inútiles)... SonarQube: es una plataforma de código abierto para la inspección continua de la calidad del código para realizar revisiones automáticas con análisis estático de código para detectar errores, olores de código y vulnerabilidades de seguridad en más de 20 lenguajes de programación. SonarQube ofrece informes sobre código duplicado, complejidad del código, comentarios, normas de codificación, pruebas unitarias, cobertura del código, errores y vulnerabilidades de seguridad. BetterCodeHub: comprueba la base de código de GitHub según 10 directrices de ingeniería de software. Principios de mantenibilidad del software ▪ ▪ ¿ Que implica un cambio? 1. Localizar un fragmento específico de código fuente 2. Analizarlo: comprender la lógica interna, su posición en el proceso de negocio y dependencias dentro del código 3. Realizar el cambio y probarlo 4. Integrarlo en el desarrollo. Principios de mantenibilidad: 1. La mantenibilidad se beneficia de prácticas y guías sencillas. 2. La mantenibilidad debe considerarse desde el principio del desarrollo del proyecto. 3. Algunos incumplimientos son peores que otros. 10 principios para hacer software mantenible 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. Escribir unidades de código cortas Escribir unidades de código simples Escribir código de una vez – evitar duplicados Mantener las interfaces pequeñas Separar “concerns” en modulos Componentes arquitectónicos débilmente acoplados Mantener los componentes arquitectónicos balanceados Mantener la base de código pequeña Automatizar las pruebas Escribir código limpio 1. Escribir unidades de código cortas ▪ ▪ Cuanto más largo es un procedimiento, más difícil es su comprensión. Las unidades pequeñas (métodos y constructores) son más faciales de analizar, probar y reutilizar. ▪ ▪ ▪ ▪ Heurística: crear un método nuevo cada vez que se sienta la necesidad de insertar un comentario. Unidades de no más de 15 líneas de código o Definición de LoC (=Lines of Code) ▪ Cualquier línea del código fuente que termine con Enter/Return y que no esté vacía ni contenga sólo un comentario. ▪ Una línea puede contener más de una sentencia y una sentencia puede extenderse en más de una línea ▪ Regla: una sentencia por línea Tener en cuenta este principio: o Al escribir nuevas unidades o Al ampliar las funcionalidades de una unidad Técnicas de refactorización: o EXTRACT METHOD: para crear unidades que presenten una única funcionalidad,cortas y fáciles de probar. o REPLACE METHOD WITH METHOD OBJECT: para solventar los problemas que plantean las variables locales al extraer el método del cuerpo Extract Method ▪ ▪ ▪ ▪ ▪ Fragmentos de código que cumplen una función: candidatos a ser extraviados en un nuevo método Método de extracción: extraer el código en un método aparte y darle un nombre corto y explicativo del propósito Heurística: la inserción de un comentario sugiere la codificación de un nuevo método Al realizar la extracción, hay que considerar las variables locales, el paso de parámetros y los valores retornados. Ejemplo: Replace method with method object (Sustituir método por objeto método) ▪ ▪ ▪ Cuándo aplica: cuando se quiere extraer un método que accede a variables locales Es posible pasar esas variables locales como parámetros para extraer el método Sin embargo, se puede dar el caso de largas listas de parámetros, lo cual es un problema Escribir unidades de código simples ▪ ▪ Branch points: o if, switch case, &&, || while, for, foreach catch Causas de la complejidad o Bloques de código pegados: Técnica Extract Method o Evitar el uso del switch mediante el uso de estructuras de datos o If-then-else anidados: ▪ REPLACE NESTED CONDITINAL WITH GUARD CLAUSES ▪ DESCOMPOSICIÓN DE CONDICIONALES o Evitar el uso del switch mediante el uso de estructuras de datos ▪ Solución: usar EEDD Map que asocie las banderas: Técnica de descomposición de condicionales ▪ ▪ Problema: una sentencia condicional compleja Solución: o 1. Extraer la condición en un método propio/nuevo o 2. Extraer la parte del then y la parte del else en sus propios métodos Replace Nested Conditional with Guard Clauses (Sustituir condicional anidado por cláusulas de guarda) ▪ ▪ Problema: If anidados - dificultan el seguimiento de la ejecución del método. Solución: Usar guard clauses (sentencias booleanas). Técnica de descomposición de condicionales 3. Escribir código una vez – evitar duplicados ▪ ▪ ▪ ▪ ▪ Número uno de los bad smell!! Código duplicado (clones): o Dos fragmentos de códigos ideáticos (textual o sintácticamente) de al menos 6 líneas de longitud. o Tipo 1 (textualmente): Dos o más fragmentos de códigos idénticos textualmente de al menos 6 líneas de largo. El código duplicado puede estar en el mismo método, en métodos diferentes de la misma clase o en clases diferentes. o Tipo 2 (sintácticamente): Fragmentos idénticos sintácticamente. Difieren en comentarios, nombres de identificadores y literales. Problemas que plantea: o Difícil de localizar. No saber dónde hay otra copia del código, cuántas copias existen y dónde se encuentran. o ¿Y si el código duplicado contiene un bug? En caso de cambios, implica arreglar los bugs en múltiples lugares. El problema de la duplicación es no saber dónde hay otra copia del código, cuaÃÅntas copias existen y dónde se encuentran Escribir código reutilizable, genérico y llamar a métodos ya existentes. Técnica de refactorización: EXTRACT METHOD 4. Mantener las interfaces pequeñas ▪ ▪ ▪ ▪ Listas largas de parámetros son difíciles de comprender y mantener: su uso se vuelve inconsistente y difíciles de usar Limitar el número de parámetros por unidad a 4. Las listas cortas de parámetros son más faciales de reutilizar y menos expuestas al error. Técnicas de Refactorización: o INTRODUCE PARAMETER OBJECT o PRESERVE WHOLE OBJECT o REPLACE PARAMETER WITH METHOD 5. Separación de asuntos (Separation of concerns) ▪ ▪ ▪ ▪ Principio que afecta al diseño y las relaciones entre CLASES Evitar módulos (clases) grandes para lograr un acoplamiento débil entre módulos Motivación: o Uno de los objetivos de un buen diseño de clases es facilitar la localización de los cambios o Las modificaciones en una clase deberían tener efectos mínimos sobre las otras clases o Los cambios en un código débilmente acoplado son más fáciles de supervisar y ejecutar que los cambios en un código muy acoplado. Asignar responsabilidades a módulos separados y esconder los detalles de implementación detrás de las interfaces: o o ▪ Evitar definir campos públicos Definir claramente la interfaz de uso de la clase como un conjunto de métodos públicos. Cada clase debe representar una sola entidad bien definida, con responsabilidades bien definidas o La clase que posee unos datos tiene que ser responsable de procesarlos o Separar la clase: si la clase tiene más de una responsabilidad, dividir la clase en varias. 6. Componentes arquitectónicos débilmente acoplados ▪ ▪ ▪ Tratar de obtener nivel de acoplamiento débil entre los componentes de alto nivel. ¿Como? Minimizar la cantidad de código relativo entre módulos que está expuesto a módulos de otros componentes (información compartida entre módulos y llamadas) Los componentes independientes facilitan el mantenimiento aislado. 7. Mantener los componentes arquitectónicos equilibrados ▪ ▪ Equilibrar el número y tamaño relativo de los componentes de alto nivel del coÃÅdigo. Organizar el código de manera que el número de componentes se encuentre entre 612 y sean de tamaños similares. 8. Mantener la base de código pequeña ▪ ▪ ▪ ▪ Mantener la base de código tan pequeña como sea posible o Evitar el crecimiento de la base del código fuente, reducción activa del tamaño del sistema. Efectos adversos del tamaño en sistemas software Medidas funcionales: o E vitar el síndrome del lavadero (arrastramiento del alcance, scope creep), las funcionalidades y requisitos deseables. o Estandarizar la funcionalidad: evitar implementaciones de una misma funcionalidad de varias maneras o diversos caminos de flujo de información. Médidas técnicas: o Evitar duplicidades en el código o Refactorizar o Usar librerías y frameworks de terceras partes. o Dividir un sistema grande en sistemas más pequeños: microservicios ▪ Microservicios: Arquitectura basada en microservicios es un enfoque de desarrollo de una aplicación como un conjunto de pequeños servicios, cada cual se ejecuta en su propio proceso y se comunica mediante mecanismos ligeros (p.e., APIs en HTTP). o Diseño modular: su propósito es dividir sistemas grandes en pequeñas partes. Presentan acoplamiento débil. o Los microservicios se pueden implementar de manera independiente así, como la gestión de sus cambios. o Los microservicios se pueden implementar en distintas tecnologías, lenguajes y plataformas. o Cada microservicio posee su propio almacenamiento de datos. o Los microservicios se comunican entre si a través de la red (REST). 9. Automatizar las pruebas ▪ Automatizar las pruebas del código ▪ Implementar pruebas automatizadas con un entorno de pruebas ▪ Java Junit 10. Escribir código limpio ▪ ▪ ▪ ▪ ▪ ▪ Evitar code smells Evitar ciertos comentarios: o Los comentarios denotan código ininteligible, apuntan a un concern aplicar Extract method), indican buenas intenciones... No dejar código inalcanzable (dead code) No usar identificadores largos Definir constantes de manera explícita Capturar las excepciones Refactorización ▪ Técnicas: ▪ Deuda técnica: o Es una metáfora para hacer el coste de la deficiencia de la calidad (interna) del software visible o La deuda técnica hace visible la diferencia entre: o o Si la deuda técnica no se reduce o elimina, es más difícil implementar cambios en el futuro (el software es menos mantenible y es más difícil de evolucionar) – incrementa la entropía del software Para cuantificar la deuda se utilizan dos conceptos: ▪ Principal: coste de eliminar o reducir el impacto de un elemento de deuda técnica en un sistema software en un momento dado ▪ Interés: coste recurrente de no eliminar un elemento de deuda técnica sobre un cierto período de tiempo ▪ Principal: ej. coste de refactorizar ▪ Interés: coste del mantenimiento en el futuro ▪ También se puede tener en cuenta el time-to-market, es decir, la necesidad de lanzar nuevas versiones