Table Of ContentAplicación de un Proceso de Refactoring
guiado por Escenarios de Modificabilidad y
Code Smells
Trabajo final entregado para el grado de
Ingeniería en Sistemas
en la Facultad de Ciencias Exactas
Por
Manuel Alonso
Facundo H. Klaver
Bajo la supervisión de
Dr. Andrés Díaz-Pace
Dr. Santiago Vidal
Universidad Nacional del Centro de
la Provincia de Buenos Aires
Tandil, Argentina
Noviembre 2015
A mis padres, Claudia y Daniel.
A mi hijo Fermín y su mamá.
MA
A mis padres, Susana y Daniel.
A mi madrina Alicia.
A mi compañera de la vida Eliana.
FHK
También queremos agradecer a nuestros directores, Andrés y Santiago,
que nos ayudaron en todo lo posible para sacar adelante este trabajo.
Y en especial, a todos nuestros cumpas,
al Estado Nacional y la Universidad Pública,
por el apoyo y todo el aprendizaje de estos años.
Indice de Contenidos
1.Introducción.......................................................................................................7
1.1.Modificabilidad como objetivo de calidad.....................................................................7
1.2.Proceso de refactoring...................................................................................................8
1.3.Caso de estudio...............................................................................................................9
1.4.Esquema general...........................................................................................................10
2.Marco teórico...................................................................................................11
2.1.Evolución de los sistemas de software.......................................................................11
2.2.Refactoring....................................................................................................................12
2.2.1.Beneficios de refactorizar........................................................................................13
2.2.1.1.Mejora el Diseño de Software...................................................................................13
2.2.1.2.Hace al software fácil de entender...........................................................................13
2.2.1.3.Ayuda a encontrar errores........................................................................................13
2.2.2.Momentos para refactorizar.....................................................................................14
2.2.2.1.Al agregar una funcionalidad....................................................................................14
2.2.2.2.Cuando se necesita corregir un error.......................................................................14
2.2.2.3.Al revisar el código....................................................................................................15
2.2.3.Refactoring y diseño................................................................................................15
2.2.3.1.Refactoring como una alternativa de diseño............................................................15
2.2.3.2.Cambio de énfasis....................................................................................................15
2.2.3.3.Flexible......................................................................................................................16
2.3.Calidad en el desarrollo de software...........................................................................16
2.3.1.Atributos de calidad.................................................................................................16
2.3.2.Funcionalidad y arquitectura....................................................................................17
2.3.3.Modificabilidad.........................................................................................................18
2.3.3.1.Artefacto a modificar.................................................................................................18
2.3.3.2.Ambiente en que se realiza la modificación.............................................................18
2.3.4.Escenarios de Modificabilidad..................................................................................19
2.3.5.Tácticas de modificabilidad......................................................................................21
2.3.5.1.Localización de modificaciones................................................................................22
2.3.5.2.Prevención de efecto dominó...................................................................................22
2.3.5.3.Retraso de tiempo de Binding..................................................................................22
2.3.6.Deuda Técnica.........................................................................................................22
2.3.6.1.Retrospectiva de deuda técnica...............................................................................23
2.4.Métricas y code smells.................................................................................................24
2.4.1.Code Smells............................................................................................................25
2.4.1.1.Desarmonías de identidad........................................................................................26
2.4.1.2.Desarmonías de Colaboración.................................................................................28
2.4.1.3.Desarmonías de Clasificación..................................................................................29
2
2.5.Testing............................................................................................................................29
2.6.Resumen........................................................................................................................30
3.Trabajos Relacionados...................................................................................32
3.1.Aspectos generales del refactoring de software........................................................32
3.1.1.Formalización de los procesos de refactoring..........................................................32
3.1.2.Desafíos y beneficios de refactorizar.......................................................................32
3.1.3.Dos tácticas de refactoring.......................................................................................34
3.1.4.Herramientas para cada táctica de refactoring.........................................................34
3.1.5.Refactoring guiado por métricas..............................................................................34
3.2.Enfoques de refactoring...............................................................................................35
3.2.1.Identificación de oportunidades de refactoring.........................................................35
3.2.2.Refactoring basado en herramientas de visualización.............................................35
3.2.3.Refactoring orientado por features...........................................................................36
3.2.4.Modelo matemático para refactoring........................................................................37
3.3.Impacto de refactorings en la calidad del software....................................................37
3.3.1.Efectos del refactoring en la calidad del software....................................................37
3.3.2.Acoplamiento y cohesión como indicadores de buena calidad................................38
3.3.3.Relación entre calidad y refactoring en casos de estudio........................................38
3.3.4.Modificabilidad de arquitecturas de software...........................................................38
3.3.5.Impacto de técnicas de refactoring en las métricas de calidad................................39
3.4.Refactorings guiados por code smells........................................................................39
3.4.1.Evaluación de sistemas a partir del análisis objetivo y el análisis subjetivo.............40
3.4.2.Detección automatizada de code smells..................................................................40
3.4.3.Identificación de Architectural Smells.......................................................................40
3.4.4.Detección de code smells relevantes para la arquitectura.......................................41
3.4.5.Orden apropiado de resolución de code smells.......................................................41
3.4.6.Una experiencia con code smells en Extreme Programming (XP)...........................42
3.5.Resumen........................................................................................................................43
4.Proceso de Refactorización...........................................................................44
4.1.Definición del Proceso..................................................................................................44
4.1.1.Refactoring iterativo por etapas...............................................................................45
4.1.1.1.Etapa 1: Análisis e identificación del problema ¿Qué refactorizar?.........................47
4.1.1.2.Etapa 2: Planteo de solución y definición de escenarios.........................................49
4.1.1.3.Etapa 3: Priorización de backlog. ¿Por dónde conviene empezar?.........................50
4.1.1.4.Etapa 4: Implementación de escenario. ¡Refactorizar!.............................................51
4.1.1.5.Etapa 5: Medición de resultados. ¿Es válida la refactorización?.............................53
4.1.1.6.Etapa 6: Evaluación. ¿Seguir refactorizando?.........................................................54
5.Caso de Estudio..............................................................................................55
5.1.SocialGraph, una herramienta para analizar redes sociales.....................................55
5.1.1.Sobre el Análisis de Redes Sociales........................................................................55
3
5.2.Definición del sistema...................................................................................................56
5.2.1.Versiones de SocialGraph.......................................................................................56
5.2.2.Arquitectura actual de SocialGraph.........................................................................56
5.2.3.Funcionalidades de SocialGraph.............................................................................60
5.2.4.Requerimientos de SocialGraph..............................................................................60
5.3.Aplicación del proceso de refactorización a SocialGraph.........................................61
5.4.Iteración 0: Preliminar...................................................................................................61
5.4.1.Análisis general del problema..................................................................................61
5.4.1.1.Anomalía 1: Estructura del código del proyecto.......................................................62
5.4.1.2.Anomalia 2: Acoplamiento entre capas....................................................................62
5.4.1.3.Anomalía 3: Diseño ligado a correos electrónicos...................................................62
5.4.2.Priorización de las anomalías..................................................................................62
5.4.3.Cobertura de test de la aplicación............................................................................64
5.4.4.Observaciones de la Iteración 0...............................................................................65
5.5.Iteración 1: Re-estructuración del Proyecto...............................................................65
5.5.1.Etapa 1: Análisis e identificación del problema........................................................65
5.5.1.1.Documentación del proyecto....................................................................................65
5.5.1.2.Detección de code smells.........................................................................................65
5.5.1.3.Identificación de los problemas en el diseño............................................................66
5.5.2.Etapa 2: Planteo de solución y definición de escenarios..........................................67
5.5.2.1.Definir refactorings a realizar....................................................................................67
5.5.2.2.Especificar Escenarios de Modificabilidad................................................................67
5.5.2.2.1.Escenario 1.1. Mavenizar Proyecto.........................................................................................67
5.5.2.2.2.Escenario 1.2. Reestructurar dependencia con aplicación WordCram...................................68
5.5.2.2.3.Escenario 1.3. Reestructurar dependencia con aplicación GATE...........................................69
5.5.2.3.Agregar al backlog....................................................................................................69
5.5.3.Etapa 3: Priorización de backlog..............................................................................69
5.5.3.1.Nivel de Impacto.......................................................................................................70
5.5.3.2.Nivel de Esfuerzo......................................................................................................70
5.5.3.3.Ubicación en cuadrantes..........................................................................................70
5.5.4.Etapa 4: Implementar Escenarios............................................................................71
5.5.4.1.Escenario 1.1: Mavenizar proyecto..........................................................................71
5.5.4.1.1.Verificar cobertura de test........................................................................................................71
5.5.4.1.2.Implementar Escenario............................................................................................................71
5.5.4.1.3.Ejecutar casos de test..............................................................................................................75
5.5.4.2.Escenario 1.2: Reestructurar dependencia con aplicación WordCram Proyecto.....76
5.5.4.2.1.Verificar cobertura de test........................................................................................................76
5.5.4.2.2.Implementar Escenario............................................................................................................76
5.5.4.2.3.Ejecutar casos de test..............................................................................................................76
5.5.4.3.Escenario 1.3. Reestructurar dependencia con aplicación GATE............................76
5.5.4.3.1.Verificar cobertura de test........................................................................................................76
5.5.4.3.2.Implementar Escenario............................................................................................................77
5.5.4.3.3.Ejecutar casos de test..............................................................................................................78
4
5.5.4.3.4.Notas sobre la implementación de los escenarios...................................................................78
5.5.5.Etapa 5: Medición de Resultados............................................................................79
5.5.5.1.Análisis basado en métricas y documentación.........................................................79
5.5.5.2.Análisis subjetivo y valoración del grupo de desarrollo............................................79
5.5.5.3.Validación de escenarios..........................................................................................80
5.5.6.Etapa 6: Etapa 6: Evaluación...................................................................................80
5.6.Iteración 2: Diseño ligado a correos electrónicos......................................................80
5.6.1.Etapa 1: Análisis e identificación del problema........................................................80
5.6.1.1.Documentación del proyecto....................................................................................80
5.6.1.2.Detección de code smells.........................................................................................82
5.6.1.3.Identificación de los problemas en el diseño............................................................83
5.6.2.Etapa 2: Planteo de solución y definición de escenarios..........................................83
5.6.2.1.Definir refactorings a realizar....................................................................................83
5.6.2.2.Especificar Escenarios de Modificabilidad................................................................83
5.6.2.2.1.Escenario 3.1: Abstraer el modelo para la construcción del grafo...........................................83
5.6.2.2.2.Escenario 3.1.1: Aplicar patrón Strategy a la clase GraphBuilder...........................................84
5.6.2.2.3.Escenario 3.1.2: Abstraer la clase CommunicationEdge de la clase Mail en el modelo..........85
5.6.2.2.4.Escenario 3.1.3: Abstraer la clase PersonVertex de la clase Mail en el modelo.....................85
5.6.2.2.5.Escenario 3.1.4: Abstraer la clase FileVertex y AttachmentEdge de la clase Mail en el modelo.
................................................................................................................................................................86
5.6.2.2.6.Escenario 3.1.5: Abstraer la clase TagFinder de la clase Mail en el modelo...........................87
5.6.2.2.7.Escenario 3.1.6: Refactorizar God Class en GraphPersistenceHelper...................................88
5.6.2.2.8.Escenario 3.2: Abstraer la clase Mail en la interfaz gráfica de la herramienta........................88
5.6.2.2.9.Escenario 3.3: Refactorizar sección de código de “importación de datos”..............................89
5.6.2.3.Agregar al backlog....................................................................................................90
5.6.3.Etapa 3: Priorización de backlog..............................................................................90
5.6.3.1.Nivel de Impacto.......................................................................................................90
5.6.3.2.Nivel de Esfuerzo......................................................................................................91
5.6.3.3.Ubicación en cuadrantes..........................................................................................91
5.6.4.Etapa 4: Implementación de escenarios..................................................................92
5.6.4.1.Escenario 3.1.1: Aplicar patrón Strategy a la clase GraphBuilder............................92
5.6.4.1.1.Verificar cobertura de test........................................................................................................92
5.6.4.1.2.Implementar Escenario............................................................................................................92
5.6.4.1.3.Ejecutar casos de test..............................................................................................................94
5.6.4.2.Escenario 3.1.2: Abstraer la clase CommunicationEdge de la clase Mail en el
modelo..................................................................................................................................94
5.6.4.2.1.Verificar cobertura de test........................................................................................................94
5.6.4.2.2.Implementar Escenario............................................................................................................94
5.6.4.2.3.Ejecutar casos de test..............................................................................................................96
5.6.4.3.Escenarios 3.1.3, 3.1.4 y 3.1.5.................................................................................96
5.6.4.4.Escenario 3.1.6: Refactorizar God Class en GraphPersistenceHelper (GPH).........96
5.6.4.4.1.Verificar cobertura de test........................................................................................................96
5.6.4.4.2.Implementar Escenario............................................................................................................96
5.6.4.4.3.Ejecutar casos de test..............................................................................................................97
5
5.6.4.5.Escenario 3.2: Abstraer la clase Mail en la interfaz gráfica de la herramienta.........98
5.6.4.5.1.Verificar cobertura de test........................................................................................................98
5.6.4.5.2.Implementar Escenario............................................................................................................98
5.6.4.5.3.Ejecutar casos de test..............................................................................................................99
5.6.4.6.Escenario 3.3: Refactorizar sección de código de “importación de datos”..............99
5.6.4.6.1.Verificar cobertura de test........................................................................................................99
5.6.4.6.2.Implementar Escenario............................................................................................................99
5.6.4.6.3.Ejecutar casos de test............................................................................................................103
5.6.5.Etapa 5: Medición de resultados............................................................................103
5.6.5.1.Análisis basado en métricas y documentación.......................................................103
5.6.5.2.Análisis subjetivo y valoración del grupo de desarrollo..........................................104
5.6.5.3.Validación de escenarios........................................................................................105
5.6.6.Etapa 6: Evaluación...............................................................................................105
6.Conclusiones.................................................................................................106
6.1.Evaluación de la solución...........................................................................................106
6.2.Aportes y beneficios...................................................................................................107
6.3.Limitaciones................................................................................................................108
6.4.Trabajos futuros..........................................................................................................109
7.Referencias....................................................................................................110
6
1. Introducción
Una característica intrínseca de los sistemas de software es su necesidad de evolucionar. A
medida que el software se ha mejorado, modificado y adaptado a las nuevas exigencias, el
código se vuelve más complejo y se aleja de su diseño original, lo que reduce la calidad del
software [Mens2004]. El objetivo de este trabajo es brindar un enfoque de refactorización que
garantice una mejora en la modificabilidad del software.
1.1. Modificabilidad como objetivo de calidad
Los sistemas de software son construcciones complejas de ingeniería [Lanza2007]. Un
sistema de software moderno es desarrollado por muchas personas al mismo tiempo, y esto
puede dar lugar a problemas de comunicación y problemas de complejidad. Los proyectos de
desarrollo de software evolucionan en el tiempo y necesitan mantenimiento constante. Un
cambio en una parte del sistema puede afectar otras partes del mismo. Por eso, establecer el
diseño adecuado de un sistema es la clave para que sea más entendible y soporte fácilmente
cambios en el futuro. Para mantener un equilibrio en el sistema es necesario una mejora
continua de la calidad del diseño de dicho sistema.
Los atributos de calidad son características que permiten verificar y medir el grado de
satisfacción de los usuarios y/o diseñadores con respecto al sistema de software [ISO9126].
Consideraciones de la lógica de negocio determinan qué cualidades deben ser tenidas en
cuenta en la arquitectura del sistema. Estas cualidades están por encima de la funcionalidad,
que es la declaración básica de las capacidades, los servicios y el comportamiento del sistema
[Bass2003].
El desarrollo y mantenimiento de un sistema de software, sobre todo el caso de proyectos
grandes, requieren de un proceso ordenado, guiado por atributos de calidad, definidos y
priorizados de manera que garanticen tanto la satisfacción de los stakeholders como la
sustentabilidad del proyecto. Si el proceso de desarrollo es guiado solamente por
requerimientos funcionales, a fin de cumplir con los features solicitados por el cliente, no
siempre se garantiza un nivel de calidad que permita la escalabilidad del proyecto en términos
de performance, trazabilidad, seguridad, modificabilidad, etc. Esta problemática es común en
muchos sistemas de software.
Con la evolución del sistema y la introducción de nuevos features, se suelen tomar
decisiones de diseño que no van en concordancia con la idea original. Asi, se incurre en un
desvío en la arquitectura que puede traducirse en un deterioro de la modificabilidad del
sistema.
La modificabilidad tiene que ver con el costo del cambio [Bass2003]. Cada vez que se desea
introducir un cambio en el sistema se debe tener en cuenta el impacto del mismo y el esfuerzo
que se requiere para realizarlo exitosamente. Estos cambios en el sistema deben poder ser
testeados y desplegados sin afectar el comportamiento observable del sistema. Para
representar posibles cambios en la arquitectura del sistema, se utilizan escenarios de
7
modificabilidad. De esta manera, un arquitecto puede especificar en un lenguaje común a todos
los desarrolladores, las tareas a realizar y los resultados a obtener.
Los resultados de la implementación de estos escenarios deben ser validados, y
preferentemente, la mejora de calidad del sistema debe poder medirse. Durante el ciclo de
desarrollo del sistema es importante contar con métricas que brinden una noción de la
evolución de la calidad a través del tiempo. Las métricas miden elementos estructurales y,
como tales, pueden revelar problemas ocultos. En este trabajo se utilizó una serie de code
smells que permiten detectar, a nivel de implementación y diseño, síntomas de baja
modificabilidad. Sin embargo, siempre habrá una brecha entre los síntomas detectados y la
evaluación profunda que un experto en diseño puede hacer en base a esos síntomas
[Fowler1999]. Por lo tanto, es importante combinar y complementar estos indicadores con el
análisis subjetivo y cualitativo que aportan los desarrolladores del proyecto y responsables del
refactoring.
1.2. Proceso de refactoring
Refactoring es el proceso de cambiar un sistema de software de manera tal que se no altere
su comportamiento externo, pero se mejore su estructura interna [Fowler1999]. Bajo esta
definición, cualquier cambio, por pequeño sea, si representa una mejora y no afecta la
funcionalidad del sistema, podría considerarse una “refactorización”.
El objetivo en este trabajo es ir más allá de esas pequeñas mejoras que a diario realizan los
programadores para pensar en la refactorización como un proceso enmarcado en el desarrollo
de software que permita mejorar la calidad del sistema a partir de un incremento de su
modificabilidad. Esto significa que las refactorizaciones son realizadas con un enfoque
ordenado, guiado por objetivos concretos, que lleva a modificaciones definidas y validadas, con
el testeo de las áreas de código afectadas y el análisis de los resultados.
En este contexto, se utilizó un proceso de refactorización en el cual se pueden identificar un
conjunto de etapas iterables de manera incremental, que conforman un proceso guiado por
escenarios de modificabilidad y code smells. Las etapas se pueden clasificar de la siguiente
manera:
• Etapas de Análisis: al comienzo del proceso es necesario el análisis del código del
sistema para detectar errores y síntomas de problemas asociados al desarrollo y las
malas prácticas de diseño.
• Etapas de Implementación: con el diagnóstico del sistema, se pasa a la proposición y
realización de modificaciones con el objetivo de solucionar esos problemas detectados.
• Etapas de Validación: finalmente se realiza una evaluación de los cambios
desarrollados y su impacto en la calidad del sistema. Una vez realizada la evaluación se
decide si conviene llevar adelante una nueva iteración sobre el proceso para refinar la
refactorización.
8
En la Figura 1.1 se puede ver un resumen del proceso definido en este trabajo.
Figura 1.1. Proceso de refactorización resumido.
1.3. Caso de estudio
Este proceso se validó sobre un caso de estudio: el sistema SocialGraph. La instanciación
del proceso en esta sistema de software resultó en una mejora de calidad significativa.
SocialGraph es una herramienta que permite estudiar el comportamiento de grupos de trabajo
tomando como fuente de información los correos electrónicos y aplicando técnicas de Análisis
de Redes Sociales (SNA por sus siglas en inglés). Se puede decir que SocialGraph ha
evolucionado con distintas versiones a fin de agregar nuevos features. Dicha evolución ha sido
"no planeada" conduciendo a un deterioro de la calidad del software. La utilidad de esta
herramienta ha llevado a los stakeholders a requerir nuevas funcionalidades, cuyo desarrollo se
9
Description:Aplicación de un Proceso de Refactoring guiado por Escenarios de Modificabilidad y. Code Smells. Trabajo final entregado para el grado de.