• No se han encontrado resultados

JSpIRIT ­ Análisis de code smells y aglomeraciones

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  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       if­else 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       if­else 

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   

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 afectados       

de 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 este       

estudio.      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