Optimización: Performance
Proyecto Smells Aglomeraciones Tiempo
8.1 JSpIRIT Análisis de code smells y aglomeraciones
Caso de estudio #3: Visualización
Aplicación: Mobile Media
El mismo experimento realizado en el capítulo anterior se llevó a cabo en este caso en Mobile Media, un software académico para manipulación de fotos, videos y música en dispositivos móviles. La aplicación contiene 51 clases y JSpIRIT arrojó un total de 45 smells y 68 aglomeraciones en el análisis.
8.1 JSpIRIT Análisis de code smells y aglomeraciones
A continuación se realiza un análisis de los smells y aglomeraciones detectados por JSpIRIT tomando el rol de un desarrollador en la interpretación de los resultados obtenidos. Para llevar a cabo el análisis se utilizaran las vistas desarrolladas en este trabajo.
8.1.1 Vista de Heat Map
La visualización (Figura 8.1) muestra como más afectado al paquete
ubc.midp.mobilephoto.core.ui.controller. En este caso se utilizó la fórmula que calcula el nivel de afectación en base a la razón de la cantidad de smells por paquete sobre la cantidad de clases del mismo. El paquete contiene 12 clases y los smells detectados según la visualización fueron 22 (Tabla 8.1).
Si bien los smells que afectan al paquete son variados, se puede reconocer un método handleCommand presente en 11 clases y al que se le atribuyen más del 50% de los smells encontrados en el paquete. Al explorar el código se puede reconocer la relación entre los métodos de igual nombre que aparecen en 7 clases diferentes. Estas clases extienden a la clase AbstractController, que a su vez implementa una interfaz ControllerInterface que contiene la signatura del método. Según la documentación provista en el código de la interfaz, el patrón
de diseño que se pretende modelar se denomina “Chain of Resposibility” [67]. La implementación se basa en dos métodos: postCommand(Command command) y handleCommand(Command command) . El principio de funcionamiento de las instancias es el siguiente: el método postCommand de una instancia llama al método handleCommand de la misma, si este es capaz de resolver la operación “Command” que se le asigna la resuelve y la cadena termina, de lo contrario se la delega a otro controlador. Este último realiza el mismo procedimiento y esto se repite hasta que algún controlador resuelva la operación en cuestión.
Figura 8.1: Vista Heat Map de Mobile Media.
Code Smell Ranking Shotgun [email protected] 16 Shotgun [email protected] 17 Shotgun [email protected] 18 Shotgun [email protected] 19 Brain [email protected] 41 Dispersed [email protected] 22 Brain [email protected] 42 Dispersed [email protected] 24 God Class@MediaController 1 Refused Parent Bequest@MediaController 37 Brain [email protected] 43 Dispersed [email protected] 25 Dispersed [email protected] 26 Dispersed [email protected] 27 Brain [email protected] 44 Dispersed [email protected] 28 Dispersed [email protected] 29 Brain [email protected] 45 Dispersed [email protected] 32 Dispersed [email protected] 33 Refused Parent Bequest@SelectMediaController 38 Dispersed [email protected] 36
Tabla 8.1: Smells del paquete ubc.midp.mobilephoto.core.ui.controller.
Los smells del tipo Brain Method que afectan al método handleCommand
de varias clases señalan un posible exceso de responsabilidades delegadas al método. En efecto, cuando se explora el código de los métodos se observan en la mayoría de ellos bloques condicionales ifelse que resuelven varios tipos de posibles operaciones del tipo Command que pueden recibir los métodos (Figura 8.2). El problema de esto es que este comportamiento es precisamente el que se intenta evitar utilizando el patrón de diseño “Chain of Responsibility”. Se supone que cada instancia de un controlador debería ser responsable de procesar un solo tipo de orden, y al verse en la incapacidad de resolverla, delegarla a la siguiente instancia en la cadena. Por otro lado los smells del tipo Dispersed Coupling sobre los métodos favorecen este razonamiento indicando que los métodos están acoplados a diversas operaciones que tienen lugar en diversas instancias de otras clases del sistema. Y finalmente, la gran cantidad de dependencias del sistema que utiliza el paquete
ubc.midp.mobilephoto.core.ui.controller (Figura 8.3) es otro indicador del alto nivel de acoplamiento que posee con diversos componentes del sistema.
Figura 8.2: Método PhotoViewController.handleCommand.
Figura 8.3: Dependencias del paquete ubc.midp.mobilephoto.core.ui.controller.
Una de las clases que se muestra más afectada (Tabla 8.1) es
MediaController, incluso fue catalogada como God Class . Explorando el código de la clase se puede ver un método handleCommand(Command command) que abarca 240 de las 540 líneas que posee la clase. Sin dudas se trata de un método extenso, y el hecho de que contenga múltiples estructuras de condición ifelse
aplica pensamiento procedural en programación orientada a objetos. En este caso se acude a un gran número de condiciones para resolver todas las facetas de un problema que se pueden presentar, sin embargo, la solución debería aprovechar el polimorfismo para lograr el cometido. Otro indicador de este problema se observa en la Figura 8.4, donde se extrajo algunas de las condiciones evaluadas dentro del método en cuestión. Las condiciones sugieren una diversidad en las responsabilidades o concerns que maneja el método, violando el “principio de responsabilidad única” [80]. Figura 8.4: Fragmento extraído del método MediaController.handleCommand().
A su vez, MediaController termina realizando el manejo de excepciones de todas las clases que utiliza (para la gran variedad de concerns de la que es responsable) que se propagan a través de los componentes, lo que genera una violación de la arquitectura original en algunos casos (Figura 8.5). Por ejemplo, la clase MediaController invoca diferentes métodos de la clase AlbumData, que
es parte de la capa que se corresponde con el Modelo . MediaController entonces termina manejando excepciones (ej: PersistentException) señalizadas por AlbumData, incluyendo aquellas que deberían ser tratadas internamente por la capa del Modelo. Lo que significa que existe un acoplamiento adicional entre los elementos que implementan las capas del Modelo y el Controlador (como bien se pudo apreciar en la Figura 8.3), que es el origen de las violaciones en la arquitectura. Figura 8.5: Violaciones en la arquitectura de Mobile Media.
Por último, los smells de tipo Shotgun Surgery sobre los métodos de la clase AbstractController (Figura 8.6), indican una gran utilización de los mismos en las clases concretas de los controladores. Esto puede representar un problema a la hora de modificar los métodos en cuestión, generando repercusiones en las clases que lo utilizan. Explorando el código se puede ver que estos métodos son innecesarios, ya que en su interior acceden a métodos estáticos de una clase Display perteneciente a una biblioteca externa al sistema.
Sencillamente se podría acceder estáticamente a estos métodos desde las clases concretas y evitar los smells en cuestión justificando que los llamados a dependencias externas tienen una muy baja probabilidad de ser modificados con respecto a una clase perteneciente al sistema. Figura 8.6: Métodos afectados por Shotgun Surgery.
8.1.2 Vistas desarrolladas para aglomeraciones
En la vistas desarrolladas para las aglomeraciones (Figuras 8.7 y 8.8) se puede absorber una gran cantidad de información de un solo vistazo, además de poder ubicar esa información en un contexto estructural del sistema. Por otro lado es posible visualizar los sectores más afectados sin necesidad de analizar el código del sistema. Tanto en la vista IntraComponent (Figura 8.7) como en la
IntraClass (Figura 8.8) se observa al paquete
ubc.midp.mobilephoto.core.ui.controller como el más afectado por aglomeraciones. Las dos aglomeraciones más grandes del tipo IntraComponent y cuyos smells de color anaranjado y morado, son del tipo Dispersed Coupling
y Brain Method respectivamente (Figura 8.7) señalan los problemas detectados anteriormente en los métodos handleCommand, mientras que en la Figura 8.8 se pueden ver las clases con mayor concentración de smells del paquete, entre ellas
AbstractController, afectada por 3 smells del tipo Shotgun Surgery , que representan a los métodos en la Figura 8.6. Figura 8.7: Vista de aglomeraciones IntraComponent.
Figura 8.8: Vista de aglomeraciones IntraClass.
Observando las aglomeraciones del tipo Hierarchical (Figura 8.9) se puede ver que el problema detectado en la vista de Heat Map en las implementaciones del método handleCommand que afectan al paquete
ubc.midp.mobilephoto.core.ui.controller se extienden también a clases del paquete ubc.midp.mobilephoto.sms, este tipo de problemas se puede manifestar en varios paquetes, razón por la cual no pudo ser dilucidado en la vista de Heat Map.
Figura 8.9: Problema que se extiende a más de un paquete.
En el paquete ubicado a la derecha del más afectado se observa una aglomeración de 7 smells del tipo Feature Envy (Figura 8.10). Esta aglomeración se trata de la segunda más grande que contiene el sistema, sin embargo fue posicionada en el lugar #8 del ranking, anteúltima de su tipo.
Figura 8.10: Aglomeración de smells Feature Envy en el paquete ubc.midp.mobilephoto.core.ui.datamodel.
Algunos de los smells de esta aglomeración fueron abordados en el análisis
tradicional de smells (Figuras 8.1, 8.3 y 8.4) otros fueron pasados por alto
debido a sus elevados puestos en el ranking (menor relevancia). Sin embargo, la
aglomeración marca una relación entre estos smells que se creían problemas
independientes levantando sospechas acerca de la implementación. En la Figura
8.11 se observa una aglomeración del tipo Hierarchical que forman 3 de los smells. Esta aglomeración corresponde a las clases ImageAlbumData, VideoAlbumData y MusicAlbumData que extienden a la clase AlbumData.
Todas estas subclases de AlbumData implementan un único método
getFromRecordStore, cuyo comportamiento es el mismo en todas ellas, dejando
sin sentido la jerarquía. Figura 8.11: Aglomeración jerárquica sobre subclases de AlbumData.
8.2 Resultados
La vista de Heat Map sirvió a su propósito mostrando los sectores más afectadosde la estructura del sistema y proveyendo información sobre los smells
afectantes independientemente de su relevancia en el ranking. La vista de
aglomeraciones presentó una perspectiva diferente en la que se pudo apreciar
claramente los tipos y cantidad de smells afectando a los paquetes y la relación
existente entre ellos que en ocasiones puede ser clave para el descubrimiento de
problemas que afectan a toda una jerarquía de clases o la detección de defectos
en la implementación de patrones de diseño. Como es de esperar la mayoría de los problemas marcados en estas vistas
coinciden con los observados en los resultados tradicionales, de hecho sería
exhaustivo del código del sistema sin necesidad de acudir a ellas. En este
sentido está claro que la vistas no agregan información que no esté presente en
el sistema de una forma u otra. Las vistas agregan una perspectiva nueva, es
decir, otra manera de abordar el análisis aprovechando la capacidad de síntesis
de las intuitivas visualizaciones gráficas, dándole mayor velocidad y dinámica
al mismo, y eventualmente marcando ciertas características que el desarrollador
puede haber pasado por alto en otras oportunidades.
8.3 Riesgos de la validez de los resultados
A continuación se analizan los riesgos de los cuatro tipos de validación para esteestudio. Validación de conclusión: Este riesgo tiene que ver con el análisis estadístico
de los resultados. En este caso, la principal preocupación es que el estudio fue
realizado sobre una sola aplicación con un desarrollador. Esto podría reducir la
habilidad de presentar resultados concretos. Por esta razón, se cree que son
necesarios más experimentos con diferentes sujetos y aplicaciones para poder
generalizar los resultados. Validación de construcción: Este riesgo tiene que ver con el diseño del
experimento. ● El estudio fue realizado por los autores de este trabajo que tomaron el rol
de un desarrollador en búsqueda de problemas en el código de un sistema.
En la realidad se espera que el desarrollador conozca de antemano el
sistema o que incluso haya formado parte en su producción, lo que le
permitiría tener un criterio más reforzado a la hora de decidir si un smell o aglomeración realmente representa un problema real en el sistema.
● En el estudio se apeló a que el desarrollador utilice el ranking de JSpIRIT
para el análisis tradicional, e incluso se definió una relevancia para los
smells y aglomeraciones para el caso. Estos parámetros pueden diferir
dependiendo del criterio del desarrollador, quien podría variar su elección
de parámetros basándose en sus conocimientos sobre el sistema o sus
prioridades. Validación externa: Este riesgo tiene que ver con que tan representativos son
los elementos tomados para el experimento. El estudio representa la efectividad
de las visualizaciones en el contexto de un sistema y sus particularidades. Para
generalizar los resultados es necesario conducir más estudios con más sistemas,
preferentemente que difieran en su arquitectura. Validación interna: Este riesgo tiene que ver con las causas que pueden afectar
las variables independientes del experimento sin el conocimiento del
investigador. La principal variable del experimento en este aspecto es el juicio
del desarrollador, es incierto si otros desarrolladores hubiesen tomado diferentes
caminos en el proceso de deducción que los que se tomaron en este
experimento. Sin embargo, se cree que de una forma u otra se arribaría a
conclusiones similares y eventualmente saldrían a la luz los mismos problemas
detectados en este experimento (quizás incluso más). Razón por la cual esto no se considera un punto crítico en la validación interna.
Capítulo 9
Conclusión
En este trabajo se introdujeron mejoras de usabilidad y performance sobre la
herramienta de detección de smells JSpIRIT. Estas mejoras consisten en la
aceleración de los tiempos de respuesta de los análisis que ejecuta la
herramienta y la adición de vistas gráficas como medio de representación de los
resultados de dichos análisis. Gracias a estas nuevas funcionalidades, se mejora
la experiencia del usuario en el uso de la herramienta en varios aspectos: ● Tiempos de espera menores alientan al desarrollador a utilizar la
herramienta como parte del proceso de refactoring. ● Las representaciones gráficas ayudan al desarrollador a relacionar
los resultados de manera más sencilla. ● Las vistas resaltan la información relevante. ● Las vistas agregan la noción de estructura del sistema a los
resultados, esto facilita la identificación de los componentes más
afectados. ● Se mejora la asistencia en el proceso análitico que lleva a cabo el
desarrollador en base a los resultados arrojados por la herramienta. ● Integración de las vistas en la IDE Eclipse, lo que facilita su
utilización. Las mejoras también introdujeron un cierto aspecto negativo, que en este
caso formó parte de la planificación. La aceleración de los tiempos en las
algunos casos) en la primer ejecución de JSpIRIT sobre un sistema. El resto de
las ejecuciones son alcanzadas por la optimización, siendo sus tiempos de
respuesta notablemente disminuidos como demuestran los resultados.
6.1 Resultados
Como se mencionó, una de las mejoras implementadas ataca el problema
de los tiempos de respuesta lentos de JSpIRIT en las ejecuciones. Luego de
hacer un análisis empírico (Capítulo 6) se probó que la mejora efectivamente
representaba una disminución en los tiempos de respuesta de las ejecuciones, a
costa de cierto overhead en la primer ejecución. No obstante, hay que tener en
cuenta además, que si bien los tiempos de respuesta son cuantificables, en este
caso la percepción de una disminución de los mismos por parte del usuario es
un factor determinante [82]. Si el usuario no percibe la mejora en el uso de la
aplicación quiere decir que la mejora existe pero que no es lo suficientemente
significativa como para hacer una diferencia en el uso real, lo que pone en tela
de juicio los beneficios obtenidos. Mucho peor aún es que el usuario no perciba
una mejora, pero si detecte el overhead introducido para su implementación. En
este caso, a riesgo de parecer subjetiva la apreciación, se puede decir que se
percibió una disminución notable en los tiempos de respuesta en alrededor de 20
ejecuciones que fueron necesarias para la realización de los casos de estudio
(Capítulos 6, 7 y 8). Otra de las mejoras introducidas en JSpIRIT tiene que ver con la
visualización de los resultados. La salida de los análisis de JSpIRIT son los code
smells y las aglomeraciones. Si bien ambos tipos de anomalías se muestran
fielmente en las tablas de resultados, éstas carecen de contexto. El contexto
estructural del sistema que se ve afectado por los smells y aglomeraciones es de
suma importancia para las decisiones de refactoring que tomará el desarrollador.
De aquí surge la necesidad de una forma de visualización gráfica que represente
el estado de afectación del sistema y permita al desarrollador concentrarse en
los sectores más afectados si así lo desea. Bajo estos términos se desarrolló en
este trabajo una vista denominada HeatMap [71] que refleja los paquetes más
mucha utilidad en el proceso de descubrimiento de problemas llevado a cabo en
los casos de estudio. Sobre todo si se tiene en cuenta que los casos fueron
abordados sin un entendimiento previo de la arquitectura pretendida y/o del
código implementado. Esta vista probó su utilidad al señalar con efectividad los
sectores más afectados de un sistema y en ocasiones ayudó a detectar problemas
en la arquitectura de los mismos a través de un análisis de las dependencias de
los componentes. En paralelo se desarrollaron vistas que permiten representar a los
diferentes tipos de aglomeraciones, teniendo en cuenta a su vez el contexto
estructural del sistema en las que se hayan. Estas vistas sirvieron para establecer
una relación entre los smells encontrados, y ubicar las clases/métodos afectados
y sus concerns, lo que facilitó el descubrimiento de defectos en patrones de
diseño implementados en el código. Las aglomeraciones no son más que
relaciones entre un conjunto de smells del mismo tipo [30]. La relaciones
pueden ser estructurales (los smells afectan al mismo paquete/clase/método) o
pueden provenir de una jerarquía de clases afectadas por smells. Al establecer
estas relaciones es posible ver que en ocasiones los problemas se extienden a un
scope más amplio que el de una clase o método. Las vistas implementadas en
este trabajo para las aglomeraciones permiten al desarrollador apreciar mejor
estas relaciones para detectar hasta donde se extienden estos problemas. En
cualquier caso, las vistas agregan una perspectiva nueva, otra manera de abordar
el análisis aprovechando la capacidad de síntesis de las intuitivas
visualizaciones gráficas, dándole mayor velocidad y dinámica al mismo, y
eventualmente marcando ciertas características que el desarrollador puede haber
pasado por alto en otras oportunidades.
6.2 Limitaciones
A continuación se describen algunas limitaciones del enfoque implementado: ● Si bien JSpIRIT está implementado en Java, un lenguaje multiplataforma
cuyas rutinas son ejecutadas por la JVM (Java Virtual Machine), las
vistas fueron implementadas utilizando código HTML/JavaScript cuyas
que su funcionamiento está sujeto a la compatibilidad de dichos browsers
ante el código implementado. Si bien no se encontraron incompatibilidades en los navegadores nativos de los sistemas operativos
testeados (Internet Explorer 9 / Windows 7, Mozilla Firefox 44.0 / Linux
Ubuntu 14.04 LTS) no se puede garantizar que no sea el caso para otras
versiones y/o sistemas. ● Falta soporte para navegar los elementos de código afectados por una
aglomeración. Si bien las aglomeraciones están señaladas en el código, no
se establece una relación entre los elementos de código afectados para
navegar fácilmente de uno a otro (como si se hace en el caso de smells
individuales). ● No se brinda soporte al desarrollador en términos de cuál es el mejor