Comparativa de arquitecturas MV*
Texto completo
(2)
(3) Agradecimientos A mi tutor, por su tiempo, esfuerzo y dedicación. Gracias por lo mucho que me has enseñado. A mis padres, por haberme dado esta oportunidad y por su apoyo incondicional..
(4)
(5) Resumen Este proyecto consiste en un estudio de la calidad software de diferentes diseños basados en los estilos arquitectónicos MV* para una misma aplicación. El estudio se realiza a través del análisis de diferentes factores de calidad: facilidad de mantenimiento, adaptación al cambio, legibilidad, reusabilidad, etc. Para ello se toma como referencia el desarrollo del juego Klondike (también conocido como Solitario) que sufre varios cambios de requisitos (nuevas funcionalidades, despliegue distribuido, etc). Dicho juego es implementado como una aplicación de escritorio bajo la tecnologı́a Java. La solución inicial utiliza el modelo del dominio como estrategia de análisis. Las soluciones restantes resultan de la adaptación de nuevos requisitos o de la aplicación de diferentes estilos arquitectónicos, patrones o técnicas a la versión anterior para obtener un mejor diseño. En el apartado teórico se introducen algunos términos previos como arquitectura software, diseño software y estilo arquitectónico. En el segundo apartado se explican los requisitos de la aplicación y los diferentes cambios, que formando cuatro series de requisitos. Posteriormente se exponen las soluciones resultantes, el enfoque que se ha tomado en cada una de ellas, los cambios en el diseño y los problemas que presenta. Por último se presenta una comparativa de las soluciones según métricas de referencia de acoplamiento, cohesión, coherencia, etc.. Palabras clave Arquitecturas, diseño, principios, patrones, calidad del software ....
(6)
(7) Abstract This project intends to conduct a study of the software quality of various software designs based in the MV* architectural styles for the same application. The study is carried out by analyzing different software quality factors: maintainability, adaptability to change, legibility, reusability, etc. To this end, the development of the game Klondike (also knows as Solitaire) is used as reference, which experiments requirements changes throughout the course of the project (new features, distributed deployment, etc). The game is implemented as a desktop application under the Java technology. The initial solution uses the domain model as the analysis strategy. The remaining solutions are the result of adjusting to the requirement changes or applying different architectural styles, patterns or techniques to the previous version in order to improve the design. The first section introduces prior terms such as software architecture, software design and architectural design. In the second section the initial requirements and its changes are explained, leading to four requiriment series. Subsequently, the resulting solutions are presented, along with the approach of each one of them, the changes in the design and the existent problems. Lastly, a comparison of the solutions is made using various metrics that measure coupling, cohesion, coherence, etc.. Keywords Architecture, design, principles, pattern, software quality...
(8)
(9) Índice Resumen. 4. Abstract. 6. Índice. 8. Índice de figuras. 10. Índice de cuadros. 14. Objetivos. 16. I. . . . .. 18 18 20 21 22 26 27 29 31 33. Estado del arte 1 Arquitectura de software 2 Patrones de arquitectura 3 Patrones interaccion . . 4 Estilos arquitectónicos .. . . . .. II Requisitos 1 Requisitos iniciales . . . . 2 Segunda serie de requisitos 3 Tercera serie de requisitos 4 Cuarta serie de requisitos . III Soluciones 1 Solución 2 Solución 3 Solución 4 Solución 5 Solución 6 Solución 7 Solución 8 Solución 9 Solución 10 Solución 11 Solución 12 Solución 13 Solución. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . . . . . .. . . . .. basada en el Modelo del Dominio . . . . aplicando patrón comando . . . . . . . . con vista separada . . . . . . . . . . . . MVP-PM . . . . . . . . . . . . . . . . . MVP-PM aplicando patrón fachada . . . MVP-PM con vista achicada . . . . . . . MVP-PM con doble despacho . . . . . . MVP-PM con funcionalidad undo/redo . MVP-PM con reusabilidad por herencia MVP-PM client-server . . . . . . . . . . MVP-PM aplicando patrón proxy . . . . MVP-PM con persistencia . . . . . . . . MVP-PM aplicando patrón proxy . . . .. . . . . . . . . . . . . .. . . . . . . . . . . . . .. . . . . . . . . . . . . .. . . . . . . . . . . . . .. . . . . . . . . . . . . .. . . . . . . . . . . . . .. . . . . . . . . . . . . .. . . . . . . . . . . . . .. . . . . . . . . . . . . .. . . . . . . . . . . . . .. . . . . . . . . . . . . .. 36 . 37 . 41 . 45 . 52 . 59 . 64 . 72 . 79 . 87 . 94 . 104 . 114 . 123. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. . . . .. IV Comparativa 1 Tamaño . . . 2 Cohesion . . . 3 Acoplamiento 4 Complejidad .. . . . .. . . . .. . . . .. . . . .. 134 134 136 137 139. V Conclusiones. 142. Referencias. 144. 8.
(10)
(11) Índice de figuras 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44. Estructura MVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . Evolución MVC a MVP . . . . . . . . . . . . . . . . . . . . . . . . Estructura MVP . . . . . . . . . . . . . . . . . . . . . . . . . . . . Estructura MVP-VP . . . . . . . . . . . . . . . . . . . . . . . . . . Estructura MVP-CS . . . . . . . . . . . . . . . . . . . . . . . . . . Estructura MVP-PM . . . . . . . . . . . . . . . . . . . . . . . . . . Estructura MVVM . . . . . . . . . . . . . . . . . . . . . . . . . . . Estructura del juego klondike (posición incial) . . . . . . . . . . . . Diagrama de casos de uso (serie de requisitos 1) . . . . . . . . . . . Diagrama de contexto de casos de uso (serie de requisitos 1) . . . . Prototipado de la interfaz consola (serie de requisitos 1) . . . . . . . Diagrama de casos de uso (serie de requisitos 2) . . . . . . . . . . . Diagrama de contexto de casos de uso (serie de requisitos 2) . . . . Prototipado de la interfaz consola (serie de requisitos 2) . . . . . . . Diagrama de casos de uso (serie de requisitos 3) . . . . . . . . . . . Diagrama de contexto de casos de uso (serie de requisitos 3) . . . . Prototipado de la interfaz consola (serie de requisitos 3) . . . . . . . Diagrama de casos de uso (serie de requisitos 4) . . . . . . . . . . . Diagrama de contexto de casos de uso (serie de requisitos 4) . . . . Menu de inicio (serie de requisitos 4) . . . . . . . . . . . . . . . . . Vista en juego (serie de requisitos 4) . . . . . . . . . . . . . . . . . Vista de guardado (serie de requisitos 4) . . . . . . . . . . . . . . . Menú abrir partida (serie de requisitos 4) . . . . . . . . . . . . . . . Tabla resumen soluciones . . . . . . . . . . . . . . . . . . . . . . . . Diagrama de despliegue(domainModel) . . . . . . . . . . . . . . . . Diagrama de implementación(domainModel) . . . . . . . . . . . . . Diagrama de paquetes (domainModel) . . . . . . . . . . . . . . . . Diagrama de clases de klondike (domainModel) . . . . . . . . . . . Diagrama de clases de klondike.utils (domainModel) . . . . . . . . . Diagrama de implementación(domainModel+command) . . . . . . . Diagrama de paquetes (domainModel+command) . . . . . . . . . . Diagrama de clases de klondike (domainModel+command) . . . . . Diagrama de clases de klondike.menu (domainModel+command) . . Diagrama de clases de klondike.utils (domainModel+command) . . Diagrama de implementación(documentView) . . . . . . . . . . . . Diagrama de paquetes (documentView) . . . . . . . . . . . . . . . . Diagrama de clases de klondike (documentView) . . . . . . . . . . . Diagrama de clases de klondike.views.console (documentView) . . . Diagrama de clases de klondike.views (documentView) . . . . . . . Diagrama de clases de klondike.views.console.menu (documentView) Diagrama de clases de klondike.models (documentView) . . . . . . Diagrama de clases de klondike.utils (documentView) . . . . . . . . Diagrama de implementación(mvp.pm) . . . . . . . . . . . . . . . . Diagrama de paquetes (mvp.pm) . . . . . . . . . . . . . . . . . . . 10. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 22 23 23 24 24 25 25 26 27 28 28 29 30 30 31 32 32 33 34 34 35 35 35 36 37 37 37 38 39 41 41 42 43 44 45 46 46 47 47 48 49 50 52 53.
(12) Comparativa de arquitecturas MV* 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86. Diagrama de clases de klondike (mvp.pm) . . . . . . . . . . . . . . . . Diagrama de clases de klondike.views.console (mvp.pm) . . . . . . . . . Diagrama de clases de klondike.views (mvp.pm) . . . . . . . . . . . . . Diagrama de clases de klondike.views.console.menu (mvp.pm) . . . . . Diagrama de clases de klondike.controllers (mvp.pm) . . . . . . . . . . Diagrama de clases de klondike.utils (mvp.pm) . . . . . . . . . . . . . . Diagrama de clases de klondike.models (mvp.pm) . . . . . . . . . . . . Diagrama de paquetes (mvp.pm+facade) . . . . . . . . . . . . . . . . . Diagrama de clases de klondike (mvp.pm+facade) . . . . . . . . . . . . Diagrama de clases de klondike.views.console (mvp.pm+facade) . . . . Diagrama de clases de klondike.views (mvp.pm+facade) . . . . . . . . . Diagrama de clases de klondike.views.console.menu (mvp.pm+facade) . Diagrama de clases de klondike.controllers (mvp.pm+facade) . . . . . . Diagrama de clases de klondike.utils (mvp.pm+facade) . . . . . . . . . Diagrama de clases de klondike.models (mvp.pm+facade) . . . . . . . . Diagrama de paquetes (mvp.pm-doubleDispatching) . . . . . . . . . . . Diagrama de clases de klondike (mvp.pm-doubleDispatching) . . . . . . Diagrama de clases de klondike.views.console (mvp.pmdoubleDispatching) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Diagrama de clases de klondike.views (mvp.pm-doubleDispatching) . . Diagrama de clases de klondike.views.console.menu (mvp.pmdoubleDispatching) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Diagrama de clases de klondike.controllers (mvp.pm-doubleDispatching) Diagrama de clases de klondike.models (mvp.pm-doubleDispatching) . . Diagrama de clases de klondike.utils (mvp.pm-doubleDispatching) . . . Diagrama de paquetes (mvp.pm+doubleDispatching) . . . . . . . . . . Diagrama de clases de klondike (mvp.pm+doubleDispatching) . . . . . Diagrama de clases de klondike.views.console (mvp.pm+doubleDispatching) . . . . . . . . . . . . . . . . . . . . . . . Diagrama de clases de klondike.views (mvp.pm+doubleDispatching) . . Diagrama de clases de klondike.views.console.menu (mvp.pm+doubleDispatching) . . . . . . . . . . . . . . . . . . . . . . . Diagrama de clases de klondike.controllers (mvp.pm+doubleDispatching) Diagrama de clases de klondike.models (mvp.pm+doubleDispatching) . Diagrama de clases de klondike.utils (mvp.pm+doubleDispatching) . . Diagrama de paquetes (mvp.pm+composite) . . . . . . . . . . . . . . . Diagrama de clases de klondike (mvp.pm+composite) . . . . . . . . . . Diagrama de clases de klondike.views.console (mvp.pm+composite) . . Diagrama de clases de klondike.views (mvp.pm+composite) . . . . . . . Diagrama de clases de klondike.views.console.menu (mvp.pm+composite) Diagrama de clases de klondike.controllers (mvp.pm+composite) . . . . Diagrama de clases de klondike.utils (mvp.pm+composite) . . . . . . . Diagrama de clases de klondike.models (mvp.pm+composite) . . . . . . Diagrama de paquetes (mvp.pm+reusability) . . . . . . . . . . . . . . . Diagrama de clases de klondike (mvp.pm+reusability) . . . . . . . . . . Diagrama de clases de klondike.views.console (mvp.pm+reusability) . .. Irati Casi Satrústegui. 53 54 54 55 55 56 57 59 60 60 61 61 62 62 63 64 65 66 67 67 68 69 70 73 73 74 75 75 76 77 78 80 80 81 82 82 83 84 85 87 88 89. Página 11.
(13) Comparativa de arquitecturas MV*. 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131. Diagrama de clases de klondike.views (mvp.pm+reusability) . . . . . . 90 Diagrama de clases de klondike.views.console.menu (mvp.pm+reusability) 90 Diagrama de clases de klondike.controllers (mvp.pm+reusability) . . . . 91 Diagrama de clases de klondike.models (mvp.pm+reusability) . . . . . 92 Diagrama de clases de klondike.utils (mvp.pm+reusability) . . . . . . . 93 Diagrama de despliegue(mvp.pm-proxy) . . . . . . . . . . . . . . . . . 94 Diagrama de implementación(mvp.pm-proxy) . . . . . . . . . . . . . . 95 Diagrama de paquetes (mvp.pm-proxy) . . . . . . . . . . . . . . . . . . 95 Diagrama de clases de klondike.distributed (mvp.pm-proxy) . . . . . . 96 Diagrama de clases de klondike (mvp.pm-proxy) . . . . . . . . . . . . . 96 Diagrama de clases de klondike.views.console (mvp.pm-proxy) . . . . . 97 Diagrama de clases de klondike.views (mvp.pm-proxy) . . . . . . . . . 98 Diagrama de clases de klondike.views.console.menu (mvp.pm-proxy) . . 98 Diagrama de clases de klondike.distributed.dispatchers (mvp.pm-proxy) 99 Diagrama de clases de klondike.controllers (mvp.pm-proxy) . . . . . . . 100 Diagrama de clases de klondike.models (mvp.pm-proxy) . . . . . . . . . 101 Diagrama de clases de klondike.utils (mvp.pm-proxy) . . . . . . . . . . 102 Diagrama de implementación(mvp.pm+proxy) . . . . . . . . . . . . . . 104 Diagrama de paquetes (mvp.pm+proxy) . . . . . . . . . . . . . . . . . 105 Diagrama de clases de klondike.distributed (mvp.pm+proxy) . . . . . . 106 Diagrama de clases de klondike (mvp.pm+proxy) . . . . . . . . . . . . 106 Diagrama de clases de klondike.views.console (mvp.pm+proxy) . . . . . 107 Diagrama de clases de klondike.views (mvp.pm+proxy) . . . . . . . . . 108 Diagrama de clases de klondike.views.console.menu (mvp.pm+proxy) . 108 Diagrama de clases de klondike.distributed.dispatchers (mvp.pm+proxy) 109 Diagrama de clases de klondike.controllers.implementation (mvp.pm+proxy) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 Diagrama de clases de klondike.controllers (mvp.pm+proxy) . . . . . . 111 Diagrama de clases de klondike.models (mvp.pm+proxy) . . . . . . . . 112 Diagrama de clases de klondike.utils (mvp.pm+proxy) . . . . . . . . . . 113 Diagrama de paquetes (mvp.pm-dao) . . . . . . . . . . . . . . . . . . . 114 Diagrama de clases de klondike.distributed (mvp.pm-dao) . . . . . . . . 115 Diagrama de clases de klondike (mvp.pm-dao) . . . . . . . . . . . . . . 115 Diagrama de clases de klondike.views.console (mvp.pm-dao) . . . . . . 116 Diagrama de clases de klondike.views (mvp.pm-dao) . . . . . . . . . . . 117 Diagrama de clases de klondike.views.console.menu (mvp.pm-dao) . . . 117 Diagrama de clases de klondike.distributed.dispatchers (mvp.pm-dao) . 118 Diagrama de clases de klondike.controllers.implementation (mvp.pm-dao)119 Diagrama de clases de klondike.controllers (mvp.pm-dao) . . . . . . . . 120 Diagrama de clases de klondike.models (mvp.pm-dao) . . . . . . . . . . 121 Diagrama de clases de klondike.utils (mvp.pm-dao) . . . . . . . . . . . 122 Diagrama de implementación(mvp.pm+dao) . . . . . . . . . . . . . . . 123 Diagrama de paquetes (mvp.pm+dao) . . . . . . . . . . . . . . . . . . 124 Diagrama de clases de klondike.distributed (mvp.pm+dao) . . . . . . . 125 Diagrama de clases de klondike (mvp.pm+dao) . . . . . . . . . . . . . 125 Diagrama de clases de klondike.views.console (mvp.pm+dao) . . . . . . 126. Irati Casi Satrústegui. Página 12.
(14) Comparativa de arquitecturas MV*. 132 133 134 135 136 137 138 139 140 141 142 143 144. Diagrama de clases de klondike.views (mvp.pm+dao) . . . . . . . . . . 127 Diagrama de clases de klondike.views.console.menu (mvp.pm+dao) . . 127 Diagrama de clases de klondike.distributed.dispatchers (mvp.pm+dao) 128 Diagrama de clases de klondike.controllers.implementation (mvp.pm+dao)129 Diagrama de clases de klondike.controllers (mvp.pm+dao) . . . . . . . 130 Diagrama de clases de klondike.models.DAO (mvp.pm+dao) . . . . . . 131 Diagrama de clases de klondike.models (mvp.pm+dao) . . . . . . . . . 132 Diagrama de clases de klondike.utils (mvp.pm+dao) . . . . . . . . . . . 133 Gráfica del tamaño medio de las clases . . . . . . . . . . . . . . . . . . 135 Gráfica falta de cohesión . . . . . . . . . . . . . . . . . . . . . . . . . . 137 Gráfica factor de acoplamiento . . . . . . . . . . . . . . . . . . . . . . . 138 Gráfica complejidad ciclomática . . . . . . . . . . . . . . . . . . . . . . 140 Gráfica complejidad ciclomática . . . . . . . . . . . . . . . . . . . . . . 141. Irati Casi Satrústegui. Página 13.
(15) Índice de cuadros 1 2 3 4 5. Tamaño soluciones . . . Media de lineas por clase LCOM . . . . . . . . . . Factor de acoplamiento . Complejidad ciclomática. . y . . .. . . . . . método . . . . . . . . . . . . . . .. 14. . . . . .. . . . . .. . . . . .. . . . . .. . . . . .. . . . . .. . . . . .. . . . . .. . . . . .. . . . . .. . . . . .. . . . . .. . . . . .. . . . . .. . . . . .. . . . . .. . . . . .. . . . . .. . . . . .. . . . . .. 134 135 136 138 140.
(16)
(17) Comparativa de arquitecturas MV*. Objetivos El objetivo principal de la realización de este proyecto es afianzar los conocimientos adquiridos sobre la utilización de diferentes arquitecturas, principios y patrones del software y comprender su repercusión en la calidad del software a través de un proyecto común. También se pretende aprender a realizar un análisis de la calidad de un diseño software y a interpretar diferentes métricas de referencia.. Irati Casi Satrústegui. Página 16.
(18)
(19) Comparativa de arquitecturas MV*. I.. Estado del arte. 1.. Arquitectura de software. En el ámbito del desarrollo software cada vez es más común escuchar el término “arquitectura de software”. Aún ası́, este concepto tiende a ser malentendido y utilizado para referirse a varios aspectos. Existen muchas definiciones dadas por diferentes autores. “ La arquitectura de software es la estructura de estructuras del sistema, compuesta por elementos del software, las propiedades visibles de forma externa de esos elementos y las relaciones entre ellos. ” (Carnigie-Mellon University) “ La arquitectura de software es un conjunto de elementos arquitecturales que tienen una particular forma. Distinguimos tres clases de elementos arquitecturales: elementos de procesamiento, elementos de datos y conexiones entre elementos. Los elementos de procesamiento son componentes que suministran la transformación de los elementos de datos; los elementos de datos son los que contienen la información usada y transformada; los elementos de conexión (los cuales pueden ser tanto de procesamiento, de datos o de ambos) son el pegamento que une juntas las diferentes piezas de la arquitectura. ” (Perry y Wolf) “ Una arquitectura es el conjunto de decisiones significativas sobre la organización del un sistema software, la selección de los elementos estructurales y sus interfaces por los que el sistema está compuesto junto con su comportamiento como se especifica en sus colaboraciones entre estos elementos, la composición de estos elementos estructurales y de comportamiento en subsistemas progresivamente más grandes y el estilo de arquitectura que guı́an la organización – estos elementos, sus interfaces, sus colaboraciones y su composición. ” (Booch, Rumbaugh, and Jacobson) Teniendo en cuenta estas definiciones, se puede concluir que la arquitectura de software es, de manera abstracta, el conjunto de componentes del software, sus interfaces y la comunicación entre ellos. Una vez definido este concepto, hay que diferenciarlo de los términos “arquitectura de sistema” y “diseño de software”. Arquitectura de sistema “ La arquitectura del sistema es la organización fundamental de un sistema incorporado en sus componentes, sus relaciones con otros y su entorno y las principales guı́as de su diseño y evolución. ” (IEEE). Irati Casi Satrústegui. Página 18.
(20) Comparativa de arquitecturas MV*. Entonces, al nivel más alto, un sistema comprende hardware, software, firmware, etc. La arquitectura de sistema incluye todos estos componentes, mientras que la arquitectura de software baja un nivel de abstracción para centrarse únicamente en el software. Es a este nivel donde se tiene en cuenta el funcionamiento general del software, las interfaces de usuario, las arquitecturas de bases de datos, etc. Diseño de software “ El diseño de software es el proceso de definición de la arquitectura, componentes, interfaces y otras caracterı́sticas de un sistema o componente que resulta de este proceso. ” (IEEE) Por tanto, el diseño de software se centra en la implementación de las funcionalidades del sistema en términos de clases, sus relaciones, los datos que manejan, casos de uso, etc. Mientras que la arquitectura de software se centra en los paquetes sin entrar en su implementación.. Irati Casi Satrústegui. Página 19.
(21) Comparativa de arquitecturas MV*. 2.. Patrones de arquitectura “ Un patrón de arquitectura define el esquema de organización estructural fundamental de los sistemas software. Proporciona una serie de subsistemas predefinidos, especificando sus responsabilidades e incluyendo unas pautas para organizar las relaciones entre ellos. ” (Willey— Pattern Oriented Software Architecture). Un patrón de arquitectura es una especialización de elementos y relaciones, junto con un conjunto de restricciones de cómo pueden usarse. Son patrones a nivel de sistema, mientras que los patrones de diseño se enfocan en el diseño de los componentes, a nivel de subsistema. Ambos grupos de patrones son independientes del lenguaje de programación. Dentro de los patrones de arquitectura se pueden diferenciar distintas categorı́as: Patrones para la capa de negocio: Patrón modelo del dominio (análisis y diseño orientado a objetos), etc. Patrones para la Capa de Datos: Patrón pasarela por fila de datos, patrón pasarela por tabla de datos (DAO), patrón correspondencia de datos (ORM), patrón registro activo, etc. Patrones para la capa de presentación: Patrones MV* Este trabajo se centra en la aplicación de los patrones MV*, pero antes se deben definir los patrones de interacción en los que se basan.. Irati Casi Satrústegui. Página 20.
(22) Comparativa de arquitecturas MV*. 3.. Patrones interaccion. Patrón de Presentación separada “ Asegura que cualquier código que manipula la presentación solo manipula la presentación desplazando toda la lógica del dominio y de datos en áreas separadas del programa. ” (Martin Fowler) El resultado de su aplicación serán vistas que se responsabilizan de gestionar: Sus controles de interfaz. Su estado (datos mostrados en la interfaz) Su lógica (para manipular los controles de la interfaz) Su sincronización (coordinar su estado con el de los objetos de datos y de negocio en memoria/bbdd) Patrón de Vista Achicada Este patrón consiste en minimizar la responsabilidad de objetos vista difı́ciles de probar. Las vistas resultantes se encargarán de gestionar: Sus controles de interfaz. De forma mı́nima o nula: su estado, su lógica y su sincronización. Mientras que las clases controladoras gestionan en gran parte o en su totalidad. el estado, la lógica y la śincronización de la presentación.. Irati Casi Satrústegui. Página 21.
(23) Comparativa de arquitecturas MV*. 4.. Estilos arquitectónicos. Los Patrones MV* son el resultado de la aplicación combinada de los patrones anteriores en distintas formas por diversas motivaciones. A estos patrones también se les denomina “estilos arquitectónicos”. MVC Desarrollado por Trygve Reenskaug de Xerox PRAC Smalltalk-80 en 1978 – 1979, tiene como objetivo separar el dominio de la aplicación, la presentación y la entrada del usuario para proporcionar una interfaz de usuario con múltiples vistas. Para ello define tres componentes principales y sus responsabilidades: El modelo: Maneja los datos y la funcionalidad del negocio. Un presentador del modelo: Maneja el modelo con el que desea interactuar el usuario. La vista: Presenta el modelo y posibles acciones y redirige las interacciones al controlador. El controlador: Actua como puente entre las interacciones del usuario en la vista y el resto de la aplicación. Modifica oportunamente el modelo a través del presentador del modelo. Figura 1: Estructura MVC. Irati Casi Satrústegui. Página 22.
(24) Comparativa de arquitecturas MV*. MVP Definido por Mike Potel de Taligent Inc. en 1991. Su objetivo es separar el dominio de la aplicación, la interacción y la lógica de la presentación para posibilitar las pruebas unitarias. Para ello define tres componentes principales y sus responsabilidades: El modelo: Maneja los datos y la funcionalidad del negocio. La vista: Maneja los controles de interfaz. El presentador. La responsabilidad de manejar el estado, la lógica y la sincronización de la presentación se reparte en menor o mayor medida entre la vista y el presentador. Dependiendo de este reparto estaremos en un caso especifico de MVP o en otro.. Figura 2: Evolución MVC a MVP. Figura 3: Estructura MVP. Irati Casi Satrústegui. Página 23.
(25) Comparativa de arquitecturas MV*. MVP-VP MVP con Vista Pasiva reduce la vista a los controles de la interfaz para minimizar el riesgo de no realizar pruebas de la vista. El presentador se encarga en totalidad de manejar el estado, la lógica y la sincronización de la presentación.. Figura 4: Estructura MVP-VP MVP-CS MVP con Controlador Supervisor reparte las responsabilidades entre la vista y el presentador para reducir la carga del presentador: La vista: Tareas sencillas (del estado, la lógica y la sincronización de la presentación) El presentador: Tareas complejas (del estado, la lógica y la sincronización de la presentación). Figura 5: Estructura MVP-CS. Irati Casi Satrústegui. Página 24.
(26) Comparativa de arquitecturas MV*. MVP-PM MVP con Presentador del Modelo pretende desacoplar al presentador de la vista. El reparto de responsabilidades es el siguiente: La vista: Sincronización de la presentación. El presentador: El estado y la lógica de la presentación). Figura 6: Estructura MVP-PM MVVM El patrón Modelo/Vista/Vista-Modelo incorpora el enlace de datos automático (data binding) para reducir la codificación de la sincronización. El presentador se encarga del estado y la lógica de la presentación.. Figura 7: Estructura MVVM. Irati Casi Satrústegui. Página 25.
(27) Comparativa de arquitecturas MV*. II.. Requisitos. El problema a abordar es el desarrollo del juego Klondike (también denominado Solitario), un conocido juego de cartas de un solo jugador. La figura 8 refleja el estado inicial del juego, donde se puede observar los distintos montones de cartas existentes y movimientos posibles.. Figura 8: Estructura del juego klondike (posición incial). Irati Casi Satrústegui. Página 26.
(28) Comparativa de arquitecturas MV*. 1.. Requisitos iniciales. Inicialmente, la aplicación contará con la funcionalidad básica del juego, es decir, con sus 7 movimientos posibles y la posiblidad de comenzar una nueva partida cuando se haya ganado la actual. Estas funcionalidades quedan reflejadas en el diagrama de casos de uso de la figura 9 y en el diagrama de contexto de la figura 10. Se tratará de una aplicación standalone con interfaz de consola. Casos de uso. Figura 9: Diagrama de casos de uso (serie de requisitos 1). Irati Casi Satrústegui. Página 27.
(29) Comparativa de arquitecturas MV*. Figura 10: Diagrama de contexto de casos de uso (serie de requisitos 1) Prototipado de la interfaz. Figura 11: Prototipado de la interfaz consola (serie de requisitos 1) Irati Casi Satrústegui. Página 28.
(30) Comparativa de arquitecturas MV*. 2.. Segunda serie de requisitos. En esta nueva serie de requisitos, se incluye las funcionalidades de deshacer y rehacer movimientos. Estas opciones solo se mostrarán en el caso de que sean posibles de realizar. Casos de uso. Figura 12: Diagrama de casos de uso (serie de requisitos 2). Irati Casi Satrústegui. Página 29.
(31) Comparativa de arquitecturas MV*. Figura 13: Diagrama de contexto de casos de uso (serie de requisitos 2) Prototipado de la interfaz. Figura 14: Prototipado de la interfaz consola (serie de requisitos 2) Irati Casi Satrústegui. Página 30.
(32) Comparativa de arquitecturas MV*. 3.. Tercera serie de requisitos. Para esta serie de requisitos, la aplicación deberá tener una nueva versión con despliegue cliente-servidor (en adición a su versión standalone), manteniendo las funcionalidades de la serie anterior. Casos de uso. Figura 15: Diagrama de casos de uso (serie de requisitos 3). Irati Casi Satrústegui. Página 31.
(33) Comparativa de arquitecturas MV*. Figura 16: Diagrama de contexto de casos de uso (serie de requisitos 3) Prototipado de la interfaz. Figura 17: Prototipado de la interfaz consola (serie de requisitos 3) Irati Casi Satrústegui. Página 32.
(34) Comparativa de arquitecturas MV*. 4.. Cuarta serie de requisitos. En esta serie de requisitos se añade persistencia, se podrá guardar una partida, cargar una partida guardada previamente y salir de una partida en juego. Casos de uso. Figura 18: Diagrama de casos de uso (serie de requisitos 4). Irati Casi Satrústegui. Página 33.
(35) Comparativa de arquitecturas MV*. Figura 19: Diagrama de contexto de casos de uso (serie de requisitos 4) Prototipado de la interfaz. Figura 20: Menu de inicio (serie de requisitos 4). Irati Casi Satrústegui. Página 34.
(36) Comparativa de arquitecturas MV*. Figura 21: Vista en juego (serie de requisitos 4). Figura 22: Vista de guardado (serie de requisitos 4). Figura 23: Menú abrir partida (serie de requisitos 4). Irati Casi Satrústegui. Página 35.
(37) Comparativa de arquitecturas MV*. III.. Soluciones. Figura 24: Tabla resumen soluciones. Irati Casi Satrústegui. Página 36.
(38) Comparativa de arquitecturas MV*. 1.. Solución basada en el Modelo del Dominio. (Implementada en la rama domainModel, serie de requisitos 1) Enfoque Esta primera solución utiliza el modelo del dominio como estrategia de análisis. El diseño se crea identificando los conceptos más importantes del contexto y asignando la responsabilidad al experto en la información (clase que tiene la información necesaria para cumplir con la responsabilidad). De esta manera las clases resultantes son fáciles de entender, ya que tienen una analogı́a con el mundo real y se mantiene la encapsulación de la información, ya que los objetos utilizan su propia información para cumplir con las tareas. Diseño Como se puede observar en la figura 27, esta versión cuenta con dos paquetes: el paquete klondike donde están todos las clases del modelo del dominio y el paquete klondike.utils que contiene clases auxiliares para escribir por consola. En la figura 28 se percibe fácilmente el alto acoplamiento de las clases.. Figura 25: Diagrama de despliegue(domainModel). Figura 26: Diagrama de implementación(domainModel). Figura 27: Diagrama de paquetes (domainModel). Irati Casi Satrústegui. Página 37.
(39) Comparativa de arquitecturas MV*. Figura 28: Diagrama de clases de klondike (domainModel). Irati Casi Satrústegui. Página 38.
(40) Comparativa de arquitecturas MV*. Figura 29: Diagrama de clases de klondike.utils (domainModel). Irati Casi Satrústegui. Página 39.
(41) Comparativa de arquitecturas MV*. Problemas Switch para el menú en Klondike: La clase Klondike se encarga de ofrecer el menú de posibles acciones (por el momento, los 7 movimientos existentes) y de llevarlas a cabo. Para ello muestra las opciones una a una: IO . writeln ( " 1 . Move from Stock to Waste " ) ; IO . writeln ( " 2 . Move from Waste to Stock " ) ; ... Y mediante un switch organiza las acciones a ejecutar: switch ( chosenMove ) { case 1 : return this . game . mo v eF ro m St oc k To Wa s te () ; case 2 : return this . game . mo v eF ro m Wa st e To St o ck () ; case 3 : .... De esta manera, se lleva por separado la opción del menú de su acción a ejecutar y se relacionan a través de un literal, lo cual no solo dificulta la comprensión del código si no que también dificulta su modificación y su extensión con nuevas acciones. Acoplamiento modelos-vistas: Las mismas clases del modelo del dominio son las que manejan las tecnologı́as de la interfaz, dando lugar a modelos poco cohesivos y muy acoplados. Se incumple el principio abierto/cerrado (las entidades del software deben estar abiertas a la extension pero cerradas a la modificación). La inclusión de nuevas interfaces (gráficos, web...) supondrı́a un aumento de los modelos en lineas , en métodos y atributos. Acoplamiento modelos-funcionalidades: Con este diseño, al incluir nuevas funcionalidades (undo/redo, demo, estadı́sticas, etc), habrı́a que modificar los modelos y su tamaño aumentarı́a, incumpliendo de nuevo el principio abierto/cerrado.. Irati Casi Satrústegui. Página 40.
(42) Comparativa de arquitecturas MV*. 2.. Solución aplicando patrón comando. (Implementada en la rama domainModel+command, serie de requisitos 1) Enfoque El objetivo de esta versión es solucionar el problema del switch para el menú en Klondike aplicando el patrón comando. Diseño Las clases ya existentes se mantienen inalteradas, excepto la clase klondike.Klondike, que delega la responsabilidad del menú a klondike.menu.PlayMenu. [Figura 32] Al paquete klondike.utils se le añaden las clases Menu y Command que representan la aplicación del patrón comando a la consola. [Figura 34] En klondike.menu se encuentran las clases PlayMenu y Command que heredan de las mencionadas anteriormente y una clase por cada movimiento que a su vez extiende a este último Command y que PlayMenu añade a su lista de comandos. [Figura 33]. Figura 30: Diagrama de implementación(domainModel+command). Figura 31: Diagrama de paquetes (domainModel+command). Irati Casi Satrústegui. Página 41.
(43) Comparativa de arquitecturas MV*. Figura 32: Diagrama de clases de klondike (domainModel+command). Irati Casi Satrústegui. Página 42.
(44) Comparativa de arquitecturas MV*. Figura 33: Diagrama de clases de klondike.menu (domainModel+command). Irati Casi Satrústegui. Página 43.
(45) Comparativa de arquitecturas MV*. Figura 34: Diagrama de clases de klondike.utils (domainModel+command) Problemas Switch para el menú Resuelto con el patrón command. Acoplamiento modelos-vistas Esta versión mantiene este problema. Acoplamiento modelos-funcionalidades También se mantiene este acoplamiento. Ciclo entre klondike y klondike.menu El principio de dependencias acicilicas declara que “la estructura de dependencias entre los paquetes debe ser un grafo dirigido acı́clico. Es decir, no debe haber ciclos en la estructura de dependencias.” Los ciclos hacen que sea muy difı́cil aislar módulos y por tanto que las pruebas de unidad y las entregas sean muy difı́ciles y propensas a error. En este caso, se produce un ciclo entre klondike y klondike.menu. Este ciclo se debe a que klondike.Klondike depende de klondike.menu.PlayMenu y el menu depende de los modelos.. Irati Casi Satrústegui. Página 44.
(46) Comparativa de arquitecturas MV*. 3.. Solución con vista separada. (Implementada en la rama documentView, serie de requisitos 1) Enfoque En esta nueva versión, vamos a desacoplar los modelos de las vistas aplicando el patrón de presentación separada. Diseño Todas las clases del modelo se encapsulan en el paquete klondike.models [Figura 41], extrayendo las partes encargadas de la presentación. El paquete klondike.views [Figura 39] contiene una clase abstracta View preparada para ser extendidas por la diferentes interfaces. En klondike.views.console [Figura 38] se sitúa toda la codificación de la interfaz consola, donde ConsoleView extiende de klondike.views.View. De está manera la clase klondike.Klondike [Figura 37] solo hace uso de klondike.models.Game y klondike.views.View (instancia de klondike.views. console.ConsoleView). Figura 35: Diagrama de implementación(documentView). Irati Casi Satrústegui. Página 45.
(47) Comparativa de arquitecturas MV*. Figura 36: Diagrama de paquetes (documentView). Figura 37: Diagrama de clases de klondike (documentView). Irati Casi Satrústegui. Página 46.
(48) Comparativa de arquitecturas MV*. Figura 38: Diagrama de clases de klondike.views.console (documentView). Figura 39: Diagrama de clases de klondike.views (documentView). Irati Casi Satrústegui. Página 47.
(49) Comparativa de arquitecturas MV*. Figura 40: Diagrama de clases de klondike.views.console.menu (documentView). Irati Casi Satrústegui. Página 48.
(50) Comparativa de arquitecturas MV*. Figura 41: Diagrama de clases de klondike.models (documentView). Irati Casi Satrústegui. Página 49.
(51) Comparativa de arquitecturas MV*. Figura 42: Diagrama de clases de klondike.utils (documentView). Irati Casi Satrústegui. Página 50.
(52) Comparativa de arquitecturas MV*. Problemas Acoplamiento modelos-vistas Este problema se ha visto resuelto con la separación de vistas. Acoplamiento modelos-funcionalidades Se mantiene este acoplamiento. Ciclo entre klondike y klondike.menu El ciclo se producı́a debido a que klondike.Klondike dependı́a de klondike. menu.PlayMenu y el menú dependı́a de los modelos. Este problema se resuelve con la separación de vistas, que hace de paquete compartido y elimina la dependencia de klondike con klondike.menu.PlayMenu. La vista lleva el control de flujo del juego La clase klondike.views.View es la responsable del control de flujo de la aplicación: public void interact () { boolean resume ; do { this . start () ; boolean finished ; do { this . move () ; finished = this . game . isFinished () ; } while (! finished ) ; resume = this . resume () ; if ( resume ) { this . game . clear () ; } } while ( resume ) ; }. Como las vistas son difı́ciles de probar, esto dificulta la realización de pruebas de la lógica del juego. Además supone la repetición de código en las diferentes interfaces (incumplimiento principio DRY).. Irati Casi Satrústegui. Página 51.
(53) Comparativa de arquitecturas MV*. 4.. Solución MVP-PM. (Implementada en la rama mvp.pm, serie de requisitos 1) Enfoque La idea para esta solución es aplicar el estilo arquitectónico MVP-PM para poder desacoplar las funcionalidades de los modelos. Diseño Respecto a la versión anterior, se añade un nuevo paquete klondike.controllers [Figura 49] que interactúa con la vista, de tal manera que la vista no conoce a klondike.models.Game. El paquete contiene los controladores StartController, MoveController y ResumeController que heredan de la clase padre Controller. Con este diseño se separan responsabilidades, se reduce el acoplamiento respecto a la versión anterior y se obtienen paquetes más cohesivos y pequeños .. Figura 43: Diagrama de implementación(mvp.pm). Irati Casi Satrústegui. Página 52.
(54) Comparativa de arquitecturas MV*. Figura 44: Diagrama de paquetes (mvp.pm). Figura 45: Diagrama de clases de klondike (mvp.pm). Irati Casi Satrústegui. Página 53.
(55) Comparativa de arquitecturas MV*. Figura 46: Diagrama de clases de klondike.views.console (mvp.pm). Figura 47: Diagrama de clases de klondike.views (mvp.pm). Irati Casi Satrústegui. Página 54.
(56) Comparativa de arquitecturas MV*. Figura 48: Diagrama de clases de klondike.views.console.menu (mvp.pm). Figura 49: Diagrama de clases de klondike.controllers (mvp.pm) Irati Casi Satrústegui. Página 55.
(57) Comparativa de arquitecturas MV*. Figura 50: Diagrama de clases de klondike.utils (mvp.pm). Irati Casi Satrústegui. Página 56.
(58) Comparativa de arquitecturas MV*. Figura 51: Diagrama de clases de klondike.models (mvp.pm). Irati Casi Satrústegui. Página 57.
(59) Comparativa de arquitecturas MV*. Problemas Acoplamiento modelos-funcionalidades Resuelto con la separación de los controladores. La vista lleva el control de flujo del juego Esta solución mantiene este problema. Las vistas conocen a todos los controladores La vista acepta todos los controladores existentes: View ( startController : StartConrtoller , moveController : MoveController , resumeController : ResumeController ). Esto supone modificar las vistas al añadir nuevos controladores, aumentando su tamaño e incumpliendo el principio abierto/cerrado.. Irati Casi Satrústegui. Página 58.
(60) Comparativa de arquitecturas MV*. 5.. Solución MVP-PM aplicando patrón fachada. (Implementada en la rama mvp.pm+facade, serie de requisitos 1) Enfoque El objetivo de esta nueva versión es aplicar el patrón fachada en los controladores para que las vistas no tengan que aceptar a todos los controladores. Diseño El patrón fachada se aplica a través de la nueva clase klondike.controller.Logic [Figura 57] que encapsula los controladores para ofrecer una interfaz única a la vista. Con este cambio, la vista no tendrá que añadir un nuevo parámetro cada vez que se quiera añadir un nuevo controlador y todos quedarán encapsulados en la lógica, creando un código más limpio. View ( logic Logic ). Figura 52: Diagrama de paquetes (mvp.pm+facade). Irati Casi Satrústegui. Página 59.
(61) Comparativa de arquitecturas MV*. Figura 53: Diagrama de clases de klondike (mvp.pm+facade). Figura 54: Diagrama de clases de klondike.views.console (mvp.pm+facade). Irati Casi Satrústegui. Página 60.
(62) Comparativa de arquitecturas MV*. Figura 55: Diagrama de clases de klondike.views (mvp.pm+facade). Figura 56: Diagrama de clases de klondike.views.console.menu (mvp.pm+facade). Irati Casi Satrústegui. Página 61.
(63) Comparativa de arquitecturas MV*. Figura 57: Diagrama de clases de klondike.controllers (mvp.pm+facade). Figura 58: Diagrama de clases de klondike.utils (mvp.pm+facade). Irati Casi Satrústegui. Página 62.
(64) Comparativa de arquitecturas MV*. Figura 59: Diagrama de clases de klondike.models (mvp.pm+facade) Problemas La vista lleva el control de flujo del juego El control de flujo sigue siendo responsabilidad de la vista. Las vistas conocen a todos los controladores Al encapsular los controladores en la fachada, este problema desaparece.. Irati Casi Satrústegui. Página 63.
(65) Comparativa de arquitecturas MV*. 6.. Solución MVP-PM con vista achicada. (Implementada en la rama mvp.pm-doubleDispathing, serie de requisitos 1) Enfoque Esta versión pretende achicar la vista ya que es difı́cil de probar, quitándole la responsabilidad del control de flujo. Diseño El control de flujo pasa a ser responsabilidad de klondike.controllers.Logic [Figura 65], que lleva el estado del juego a través de los nuevos modelos State y StateValue [Figura 66]. Logic es la encargada de entregarle a la vista el controlador oportuno en cada momento. La vista [Figura 63] tan solo debe interactuar con el controlador que recibe.. Figura 60: Diagrama de paquetes (mvp.pm-doubleDispatching). Irati Casi Satrústegui. Página 64.
(66) Comparativa de arquitecturas MV*. Figura 61: Diagrama de clases de klondike (mvp.pm-doubleDispatching). Irati Casi Satrústegui. Página 65.
(67) Comparativa de arquitecturas MV*. Figura 62: Diagrama de clases de klondike.views.console (mvp.pm-doubleDispatching). Irati Casi Satrústegui. Página 66.
(68) Comparativa de arquitecturas MV*. Figura 63: Diagrama de clases de klondike.views (mvp.pm-doubleDispatching). Figura 64: Diagrama doubleDispatching). Irati Casi Satrústegui. de. clases. de. klondike.views.console.menu. (mvp.pm-. Página 67.
(69) Comparativa de arquitecturas MV*. Figura 65: Diagrama de clases de klondike.controllers (mvp.pm-doubleDispatching). Irati Casi Satrústegui. Página 68.
(70) Comparativa de arquitecturas MV*. Figura 66: Diagrama de clases de klondike.models (mvp.pm-doubleDispatching). Irati Casi Satrústegui. Página 69.
(71) Comparativa de arquitecturas MV*. Figura 67: Diagrama de clases de klondike.utils (mvp.pm-doubleDispatching). Irati Casi Satrústegui. Página 70.
(72) Comparativa de arquitecturas MV*. Problemas La vista lleva el control de flujo del juego El control de flujo es ahora responsabilidad de los controladores. instanceOf en ConsoleView En klondike.views.console.ConsoleView se necesita dar un tratamiento especı́fico según la clase derivada concreta del objeto polimórfico Controller. Para ello se realiza una comprobación con instanceOf: if ( controller instanceof StartController ) { this . start (( StartController ) controller ) ; } else { if ( controller instanceof MoveController ) { this . move (( MoveController ) controller ) ; } else { this . resume (( ResumeController ) controller ) ; } }. De esta manera, cuando se añada una nueva clase derivada de Controller, habrá que añadir una nueva condición en cada sitio que se realice esta comprobación. Buscar manualmente estas comprobaciones no solo es costoso, sino que también fomenta olvidos y equivocaciones.. Irati Casi Satrústegui. Página 71.
(73) Comparativa de arquitecturas MV*. 7.. Solución MVP-PM con doble despacho. (Implementada en la rama mvp.pm+doubleDispathing, serie de requisitos 1) Enfoque En esta solución se pretende eliminar las comprobaciones instanceOf aplicando la técnica de doble despacho. Diseño Para aplicar esta técnica añadimos una nueva interfaz ControllerVisitor en los controladores [Figura 73] que deberá implementar toda clase que quiera realizar un tratamiento especifico de Controller según su clase derivada. Sustituimos la comprobación de instanceOf por el envı́o de un mensaje accept al objeto polimórfico Controller auto-pasándose como parámetro this: controller . accept ( this ) ;. El método accept es abstracto en la clase Controller y es implementado por sus clases derivadas de la siguiente manera: public void accept ( Co ntrollerVisi tor co ntroll erVisi tor ) { cont roller Visito r . visit ( this ) ; }. Y por último la clase ConsoleView [Figura 70] implementa la interfaz ControllerVisitor con el tratamiento especifico de cada clase derivada con el método visit: public void visit ( Contr olle rDer ivad o con trol lerD eriv ad o ) { /* tratamiento especifico */ }. Con este nuevo diseño, al añadir una nueva clase derivada de Controller, habrá que añadir el nuevo método visit a la interfaz y tendremos la obligación de implementarlo en cada clase que implemente este interfaz, sin dar lugar a olvidos.. Irati Casi Satrústegui. Página 72.
(74) Comparativa de arquitecturas MV*. Figura 68: Diagrama de paquetes (mvp.pm+doubleDispatching). Figura 69: Diagrama de clases de klondike (mvp.pm+doubleDispatching). Irati Casi Satrústegui. Página 73.
(75) Comparativa de arquitecturas MV*. Figura 70: Diagrama de clases de klondike.views.console (mvp.pm+doubleDispatching). Irati Casi Satrústegui. Página 74.
(76) Comparativa de arquitecturas MV*. Figura 71: Diagrama de clases de klondike.views (mvp.pm+doubleDispatching). Figura 72: Diagrama (mvp.pm+doubleDispatching). Irati Casi Satrústegui. de. clases. de. klondike.views.console.menu. Página 75.
(77) Comparativa de arquitecturas MV*. Figura 73: Diagrama de clases de klondike.controllers (mvp.pm+doubleDispatching). Irati Casi Satrústegui. Página 76.
(78) Comparativa de arquitecturas MV*. Figura 74: Diagrama de clases de klondike.models (mvp.pm+doubleDispatching). Irati Casi Satrústegui. Página 77.
(79) Comparativa de arquitecturas MV*. Figura 75: Diagrama de clases de klondike.utils (mvp.pm+doubleDispatching) Problemas instanceOf en ConsoleView Resuelto con la aplicación de la técnica de oble despacho.. Irati Casi Satrústegui. Página 78.
(80) Comparativa de arquitecturas MV*. 8.. Solución MVP-PM con funcionalidad undo/redo. (Implementada en la rama mvp.pm+composite, serie de requisitos 2) Enfoque Esta versión es la primera solución para la segunda serie de requisitos, en la que se incorpora la funcionalidad de deshacer y rehacer movimientos. Diseño Para añadir esta nueva funcionalidad se han realizado los siguientes cambios: Se ha aplicado el patrón memento en klondike.models [Figura 83] que consiste en un Registry que maneja una lista de objetos de la clase Memento generados por Game. En klondike.controllers [Figura 81], debe existir un controlador que permita realizar un movimiento, rehacerlo o deshacerlo a elección del usuario. Con este fin, se aplica el patrón composite: la clase PlayController se compone en MoveController, UndoController y RedoController. Como estos tres últimos controladores no tienen que implementar el método accept, se hace una diferenciación entre la clase Controller que ya no tiene este método, y una clase derivada AcceptController que lo incluye. Por último en klondike.views.console.menu [Figura 80] se añaden al menú los comandos UndoCommand y MoveCommand y se incorpora el método isActive a la clase padre Command, que las clases hijas deben implementar. De esta forma, las funcionalidades de deshacer y rehacer solo se mostrarán en el menú en el caso de que sean posibles de realizar.. Irati Casi Satrústegui. Página 79.
(81) Comparativa de arquitecturas MV*. Figura 76: Diagrama de paquetes (mvp.pm+composite). Figura 77: Diagrama de clases de klondike (mvp.pm+composite). Irati Casi Satrústegui. Página 80.
(82) Comparativa de arquitecturas MV*. Figura 78: Diagrama de clases de klondike.views.console (mvp.pm+composite). Irati Casi Satrústegui. Página 81.
(83) Comparativa de arquitecturas MV*. Figura 79: Diagrama de clases de klondike.views (mvp.pm+composite). Figura 80: Diagrama de clases de klondike.views.console.menu (mvp.pm+composite). Irati Casi Satrústegui. Página 82.
(84) Comparativa de arquitecturas MV*. Figura 81: Diagrama de clases de klondike.controllers (mvp.pm+composite). Irati Casi Satrústegui. Página 83.
(85) Comparativa de arquitecturas MV*. Figura 82: Diagrama de clases de klondike.utils (mvp.pm+composite). Irati Casi Satrústegui. Página 84.
(86) Comparativa de arquitecturas MV*. Figura 83: Diagrama de clases de klondike.models (mvp.pm+composite). Irati Casi Satrústegui. Página 85.
(87) Comparativa de arquitecturas MV*. Problemas Aplicación del patrón memento dependiente del modelo del dominio: La clase Registry que lleva el registro de mementos es especifica para este dominio, sin poder ser reutilizada en otro contexto. Si necesitarı́amos aplicar este patrón en otro proyecto, tendrı́amos que volver a implementarlo de cero.. Irati Casi Satrústegui. Página 86.
(88) Comparativa de arquitecturas MV*. 9.. Solución MVP-PM con reusabilidad por herencia. (Implementada en la rama mvp.pm+reusability, serie de requisitos 2) Enfoque Para esta versión se pretende refactorizar el código de tal manera que Registry pueda reutilizarse en otros proyectos. Diseño Obtenemos esta reusabilidad a través de la generalización por uso de herencia e interfaces. El esquema del patrón memento se mueve a la clase klondike.utils [Figura 91] desacoplandolo del modelo, dando lugar a las clases Registry y Memento y al interfaz Originator. En klondike.models [Figura 90], la clase GameMemento extiende a Memento y la clase Game implementa Originator para adaptarse a este dominio concreto. Reutilizando código se aprovecha el trabajo anterior, se economiza el tiempo, y se reduce la redundancia.. Figura 84: Diagrama de paquetes (mvp.pm+reusability). Irati Casi Satrústegui. Página 87.
(89) Comparativa de arquitecturas MV*. Figura 85: Diagrama de clases de klondike (mvp.pm+reusability). Irati Casi Satrústegui. Página 88.
(90) Comparativa de arquitecturas MV*. Figura 86: Diagrama de clases de klondike.views.console (mvp.pm+reusability). Irati Casi Satrústegui. Página 89.
(91) Comparativa de arquitecturas MV*. Figura 87: Diagrama de clases de klondike.views (mvp.pm+reusability). Figura 88: Diagrama de clases de klondike.views.console.menu (mvp.pm+reusability). Irati Casi Satrústegui. Página 90.
(92) Comparativa de arquitecturas MV*. Figura 89: Diagrama de clases de klondike.controllers (mvp.pm+reusability). Irati Casi Satrústegui. Página 91.
(93) Comparativa de arquitecturas MV*. Figura 90: Diagrama de clases de klondike.models (mvp.pm+reusability). Irati Casi Satrústegui. Página 92.
(94) Comparativa de arquitecturas MV*. Figura 91: Diagrama de clases de klondike.utils (mvp.pm+reusability) Problemas Aplicacion del patron memento dependiente del modelo dominio La implementación del patrón comando es ahora independiente del problema.. Irati Casi Satrústegui. Página 93.
(95) Comparativa de arquitecturas MV*. 10.. Solución MVP-PM client-server. (Implementada en la rama mvp.pm-proxy, serie de requisitos 3) Enfoque Esta versión incorpora los cambios de requisitos de la tercera serie, es decir, una nueva versión cliente-servidor de la aplicación. Diseño Con está finalidad, la clase klondike.Klondike [Figura 96] se vuelve abstracta para ser extendida por klondike.KlondikeStandalone que conserva la versión standalone anterior y por klondike.distributed.KlondikeClient que incorpora el cliente de la versión distribuida. La única diferencia entre estas dos clases es el método isStandalone() que es utilizado por la clase padre para instanciar klondike. controllers.Logic. Los controladores [Figura 101] y la sesion [Figura 102] son los encargados de mandar la petición directamente al modelo o de mandarla a través de TCPIP según si nos encontramos en modo standalone o distribuido. Por otra parte klondike.distributed.KlondikeServer [Figura 95] representa el servidor que maneja las peticiones del cliente. Cuenta con un objeto LogicServer que extiende a la lógica y otro DispatcherPrototype que mapea el tipo de petición (FrameType) con su tratamiento (Dispatcher).. Figura 92: Diagrama de despliegue(mvp.pm-proxy). Irati Casi Satrústegui. Página 94.
(96) Comparativa de arquitecturas MV*. Figura 93: Diagrama de implementación(mvp.pm-proxy). Figura 94: Diagrama de paquetes (mvp.pm-proxy). Irati Casi Satrústegui. Página 95.
(97) Comparativa de arquitecturas MV*. Figura 95: Diagrama de clases de klondike.distributed (mvp.pm-proxy). Figura 96: Diagrama de clases de klondike (mvp.pm-proxy). Irati Casi Satrústegui. Página 96.
(98) Comparativa de arquitecturas MV*. Figura 97: Diagrama de clases de klondike.views.console (mvp.pm-proxy). Irati Casi Satrústegui. Página 97.
(99) Comparativa de arquitecturas MV*. Figura 98: Diagrama de clases de klondike.views (mvp.pm-proxy). Figura 99: Diagrama de clases de klondike.views.console.menu (mvp.pm-proxy). Irati Casi Satrústegui. Página 98.
(100) Comparativa de arquitecturas MV*. Figura 100: Diagrama de clases de klondike.distributed.dispatchers (mvp.pm-proxy). Irati Casi Satrústegui. Página 99.
(101) Comparativa de arquitecturas MV*. Figura 101: Diagrama de clases de klondike.controllers (mvp.pm-proxy). Irati Casi Satrústegui. Página 100.
(102) Comparativa de arquitecturas MV*. Figura 102: Diagrama de clases de klondike.models (mvp.pm-proxy). Irati Casi Satrústegui. Página 101.
(103) Comparativa de arquitecturas MV*. Figura 103: Diagrama de clases de klondike.utils (mvp.pm-proxy). Irati Casi Satrústegui. Página 102.
(104) Comparativa de arquitecturas MV*. Problemas Incumplimiento del Principio de Dependencias Acı́clicas (ADP): El principio de dependencias acicilicas declara que “la estructura de dependencias entre los paquetes debe ser un grafo dirigido acı́clico. Es decir, no debe haber ciclos en la estructura de dependencias.” Los ciclos hacen que sea muy difı́cil aislar módulos y por tanto que las pruebas de unidad y las entregas sean muy difı́ciles y propensas a error. En este caso, se producen varios ciclos debido a las dependencias de klondike. controllers y klondike.models con klondike.distributed.dispatchers (marcadas en rojo en la figura 94). Dependencia en controladores y modelos de las tecnologı́as de comunicación: Tanto en los controladores como en el modelo, existe código encargado de la comunicación entre cliente y servidor. Lo cual, además de crear los ciclos mencionados anteriormente, hace perder la cohesión de los módulos y rompe el principio abierto/cerrado. La incorporación de nuevas tecnologı́as de comunicación supondrı́a la modificación de los controladores y el modelo y un aumento en tamaño de las clases de ambos paquetes.. Irati Casi Satrústegui. Página 103.
(105) Comparativa de arquitecturas MV*. 11.. Solución MVP-PM aplicando patrón proxy. (Implementada en la rama mvp.pm+proxy, serie de requisitos 3) Enfoque El propósito de esta versión es solucionar los problemas de la anterior aplicando el patrón proxy. Diseño El paquete klondike.controllers [Figura 113] se desacopla de las tecnologı́as de comunicación, la clase Logic y las clases descendientes de AcceptorController se vuelven abstractas. Su especialización standalone se sitúa en un nuevo paquete klondike. controllers.implementation [Figura 112]. El paquete klondike.models[Figura\ ref{fig:prox_models}] también se desacopla de la comunicación, convirtiendo la clase Session en una interfaz y moviendo la implementación standalone a la clase SessionImplementation. Las especializaciones distribuidas se encuentra en klondike.distributed [Figura 106]: LogicProxy, StartControllerProxy, ResumeControllerProxy, StartControllerProxy y SessionControllerProxy. En la figura 128 se puede observar que al eliminar la dependencia de los modelos y controladores con klondike.distributed.dispatchers rompemos los ciclos de la versión anterior.. Figura 104: Diagrama de implementación(mvp.pm+proxy). Irati Casi Satrústegui. Página 104.
(106) Comparativa de arquitecturas MV*. Figura 105: Diagrama de paquetes (mvp.pm+proxy). Irati Casi Satrústegui. Página 105.
(107) Comparativa de arquitecturas MV*. Figura 106: Diagrama de clases de klondike.distributed (mvp.pm+proxy). Figura 107: Diagrama de clases de klondike (mvp.pm+proxy). Irati Casi Satrústegui. Página 106.
(108) Comparativa de arquitecturas MV*. Figura 108: Diagrama de clases de klondike.views.console (mvp.pm+proxy). Irati Casi Satrústegui. Página 107.
(109) Comparativa de arquitecturas MV*. Figura 109: Diagrama de clases de klondike.views (mvp.pm+proxy). Figura 110: Diagrama de clases de klondike.views.console.menu (mvp.pm+proxy). Irati Casi Satrústegui. Página 108.
(110) Comparativa de arquitecturas MV*. Figura 111: Diagrama de clases de klondike.distributed.dispatchers (mvp.pm+proxy). Irati Casi Satrústegui. Página 109.
(111) Comparativa de arquitecturas MV*. Figura 112: Diagrama (mvp.pm+proxy). Irati Casi Satrústegui. de. clases. de. klondike.controllers.implementation. Página 110.
(112) Comparativa de arquitecturas MV*. Figura 113: Diagrama de clases de klondike.controllers (mvp.pm+proxy). Irati Casi Satrústegui. Página 111.
(113) Comparativa de arquitecturas MV*. Figura 114: Diagrama de clases de klondike.models (mvp.pm+proxy). Irati Casi Satrústegui. Página 112.
(114) Comparativa de arquitecturas MV*. Figura 115: Diagrama de clases de klondike.utils (mvp.pm+proxy) Problemas Incumplimiento del Principio de Dependencias Aciclicas (ADP) Se rompe la dependencia de los controladores y los modelos con klondike. distributed.dispatchers. Dependencia en controladores y modelos de las tecnologias de comunicacion Los controladores y modelos están ahora desacoplados de las tecnologı́as de comunicación.. Irati Casi Satrústegui. Página 113.
(115) Comparativa de arquitecturas MV*. 12.. Solución MVP-PM con persistencia. (Implementada en la rama mvp.pm-dao, serie de requisitos 4) Enfoque Esta es la primera solución para la cuarta serie de requisitos, la cual añade persistencia de partidas. Se incluye la posibilidad de guardar una partida, de cargar una partida guardada y de salir de la partida actual. Diseño La primera idea para incluir la persistencia es utilizar ficheros. La responsabilidad de guardar y cargar el juego desde fichero es asignada directamente a los modelos. Se incluyen los métodos save(FileWriterfileWriter) y load(BufferedReaderbufferedReader) a varias clases del modelo [Figura 125] y algunos métodos adicionales a SessionImplementation. Por otro lado se añaden dos nuevos controladores [Figura 124]: SaveController y ExitController y dos nuevos menús [Figura 121] en la vista: StartMenu y GameSelectMenu con sus respectivos comandos.. Figura 116: Diagrama de paquetes (mvp.pm-dao). Irati Casi Satrústegui. Página 114.
(116) Comparativa de arquitecturas MV*. Figura 117: Diagrama de clases de klondike.distributed (mvp.pm-dao). Figura 118: Diagrama de clases de klondike (mvp.pm-dao) Irati Casi Satrústegui. Página 115.
(117) Comparativa de arquitecturas MV*. Figura 119: Diagrama de clases de klondike.views.console (mvp.pm-dao). Irati Casi Satrústegui. Página 116.
(118) Comparativa de arquitecturas MV*. Figura 120: Diagrama de clases de klondike.views (mvp.pm-dao). Figura 121: Diagrama de clases de klondike.views.console.menu (mvp.pm-dao) Irati Casi Satrústegui. Página 117.
(119) Comparativa de arquitecturas MV*. Figura 122: Diagrama de clases de klondike.distributed.dispatchers (mvp.pm-dao). Irati Casi Satrústegui. Página 118.
(120) Comparativa de arquitecturas MV*. Figura 123: Diagrama de clases de klondike.controllers.implementation (mvp.pm-dao). Irati Casi Satrústegui. Página 119.
(121) Comparativa de arquitecturas MV*. Figura 124: Diagrama de clases de klondike.controllers (mvp.pm-dao). Irati Casi Satrústegui. Página 120.
(122) Comparativa de arquitecturas MV*. Figura 125: Diagrama de clases de klondike.models (mvp.pm-dao). Irati Casi Satrústegui. Página 121.
(123) Comparativa de arquitecturas MV*. Figura 126: Diagrama de clases de klondike.utils (mvp.pm-dao) Problemas Dependencia en modelos de las tecnologı́as de persistencia: El código encargado de la persistencia en ficheros se encuentra en su totalidad en los modelos, perdiendo de nuevo la cohesión de los módulos y rompiendo el principio abierto/cerrado. La incorporación de nuevas tecnologı́as de persistencia, como por ejemplo, persistencia en base de datos, supondrı́a la modificación del modelo y un aumento en tamaño en sus clases.. Irati Casi Satrústegui. Página 122.
(124) Comparativa de arquitecturas MV*. 13.. Solución MVP-PM aplicando patrón proxy. (Implementada en la rama mvp.pm+dao, serie de requisitos 4) Enfoque Esta última versión pretende solventar el problema mencionado en la solución anterior. Diseño Con la finalidad de desacoplar los modelos de las tecnologı́as de persistencia, se crea un nuevo paquete klondike.models.DAO [Figura 137] en el que se separan los métodos encargados de dicha persistencia. Dando lugar a las clases GameDAO, CardStackDAO, PileDAO y CardDAO que implementan la interfaz DAO , la cual cuenta únicamente con los métodos save(FileWriterfileWriter) y load(BufferedReaderbufferedReader) y la clase SessionImplementationDAO como único acceso externo a las funcionalidades de persistencia.. Figura 127: Diagrama de implementación(mvp.pm+dao). Irati Casi Satrústegui. Página 123.
(125) Comparativa de arquitecturas MV*. Figura 128: Diagrama de paquetes (mvp.pm+dao). Irati Casi Satrústegui. Página 124.
(126) Comparativa de arquitecturas MV*. Figura 129: Diagrama de clases de klondike.distributed (mvp.pm+dao). Figura 130: Diagrama de clases de klondike (mvp.pm+dao) Irati Casi Satrústegui. Página 125.
(127) Comparativa de arquitecturas MV*. Figura 131: Diagrama de clases de klondike.views.console (mvp.pm+dao). Irati Casi Satrústegui. Página 126.
(128) Comparativa de arquitecturas MV*. Figura 132: Diagrama de clases de klondike.views (mvp.pm+dao). Figura 133: Diagrama de clases de klondike.views.console.menu (mvp.pm+dao) Irati Casi Satrústegui. Página 127.
(129) Comparativa de arquitecturas MV*. Figura 134: Diagrama de clases de klondike.distributed.dispatchers (mvp.pm+dao). Irati Casi Satrústegui. Página 128.
(130) Comparativa de arquitecturas MV*. Figura 135: Diagrama de clases de klondike.controllers.implementation (mvp.pm+dao). Irati Casi Satrústegui. Página 129.
(131) Comparativa de arquitecturas MV*. Figura 136: Diagrama de clases de klondike.controllers (mvp.pm+dao). Irati Casi Satrústegui. Página 130.
(132) Comparativa de arquitecturas MV*. Figura 137: Diagrama de clases de klondike.models.DAO (mvp.pm+dao). Irati Casi Satrústegui. Página 131.
(133) Comparativa de arquitecturas MV*. Figura 138: Diagrama de clases de klondike.models (mvp.pm+dao). Irati Casi Satrústegui. Página 132.
(134) Comparativa de arquitecturas MV*. Figura 139: Diagrama de clases de klondike.utils (mvp.pm+dao) Problemas Dependencia en modelos de las tecnologı́as de persistencia Se ha roto esta dependencia con el movimiento del código encargado de la persistencia al nuevo paquete DAO.. Irati Casi Satrústegui. Página 133.
(135) Comparativa de arquitecturas MV*. IV. 1.. Comparativa Tamaño. Como se puede observar en la tabla 1, el tamaño de las soluciones aumenta tanto en número de clases, de métodos y de lineas. Este aumento se debe en parte a la inclusión de nuevas funcionalidades en las diferentes series de requisitos, pero el aumento también se produce en las soluciones de una misma serie de requisitos. El motivo de este incremento es el desglose que se ha ido realizando de las clases para separar responsabilidades. Requisitos. 1. 2 3 4. RAMA domainModel domainModel+command documentView mvp.pm mvp.pm.+facade mvp.pm.-doubleDispatching mvp.pm.+doubleDispatching mvp.pm.+composite mvp.pm+reusability mvp.pm-proxy mvp.pm+proxy mvp.pm-dao mvp.pm+dao. #clases 16 28 39 44 45 47 48 58 60 88 98 117 123. #metodos 75 96 115 135 150 130 142 215 215 291 323 399 416. #lineas 814 1.019 1.186 1.334 1.396 1.387 1.410 1.876 1.899 2.754 3.013 3.708 3.864. Tabla 1: Tamaño soluciones Tamaño de metodos y clases Las clases y los métodos pequeños son generalmente más fáciles de entender que módulos de gran tamaño. Cuando nos encontramos con clases o métodos grandes, es probable que estén tratando de hacer demasiado. Una clase no deberı́a tener más de 250-500 lineas y un método no más de 10-15. La tabla 2 muestra las lineas por clase y por método de media en cada solución. El tamaño medio de las clases disminuye considerablemente de la primera a la segunda versión con la separación del menú y luego se mantiene alrededor de las 30 lineas. De la misma forma, el tamaño medio de los métodos se mantiene alrededor de las 10 lineas.. Irati Casi Satrústegui. Página 134.
(136) Comparativa de arquitecturas MV* Requisitos. 1. 2 3 4. RAMA domainModel domainModel+command documentView mvp.pm mvp.pm.+facade mvp.pm.-doubleDispatching mvp.pm.+doubleDispatching mvp.pm.+composite mvp.pm+reusability mvp.pm-proxy mvp.pm+proxy mvp.pm-dao mvp.pm+dao. #lineas/clase 50,88 36,39 30,41 30,32 31,02 29,51 29,38 32,34 31,65 31,30 30,74 31,69 31,41. lineas/metodo 10,85 10,61 10,31 9,88 9,31 10,67 9,93 8,73 8,83 9,46 9,33 9,29 9,29. Tabla 2: Media de lineas por clase y método. Figura 140: Gráfica del tamaño medio de las clases. Irati Casi Satrústegui. Página 135.
(137) Comparativa de arquitecturas MV*. 2.. Cohesion “ La cohesión mide el grado de conectividad entre los elementos de un solo módulo. ” (Grady Booch). Un módulo cohesivo debe tener significado propio por sı́ mismo agrupando abstracciones lógicamente relacionadas. A mayor cohesión menor complejidad de los módulos, mayor reutilización y menor la cantidad de módulos afectados por los cambios lógicos. Una de de las métricas más aceptadas para medir la cohesión es LCOM (Lack of cohesión of methods), que calcula el conjunto de atributos comunes en los métodos de una clase. Un valor alto de LCOM implica falta de cohesión, por lo que es deseable conseguir valores bajos. En la tabla 3 se muestran los valores medios obtenidos en las diferentes versiones, también reflejados en la figura 141 . Se obtienen valores de LCOM más altos en las primeras versiones, lo cual significa que la cohesión va aumentando en las soluciones posteriores. Requisitos. 1. 2 3 4. BRANCH domainModel domainModel+command documentView mvp.pm mvp.pm.+facade mvp.pm.-doubleDispatching mvp.pm.+doubleDispatching mvp.pm.+composite mvp.pm+reusability mvp.pm-proxy mvp.pm+proxy mvp.pm-dao mvp.pm+dao. LCOM 8,38 5,04 3,74 3,93 3,78 3,77 3,85 3,55 3,79 3,71 4,34 4,07 4,48. Tabla 3: LCOM. Irati Casi Satrústegui. Página 136.
(138) Comparativa de arquitecturas MV*. Figura 141: Gráfica falta de cohesión. 3.. Acoplamiento “ El acoplamiento es la medida de fuerza de la asociación establecida por una conexión ente un módulo -elemento- y otro. El acoplamiento fuerte complica un sistema porque los módulos son más difı́ciles de comprender, cambiar o corregir por sı́ mismos si están muy interrelacionados con otros módulos. ” (Grady Booch). El acoplamiento entre clases se produce cuando una clase utiliza a otra. La métrica que se ha utilizado para calcular el acoplamiento es el factor de acoplamiento. El factor de acoplamiento calcula el porcentaje del número de acoplamientos existentes (no debidos a herencia) respecto al número total de acoplamientos posibles. Un factor de acoplamiento del 100 % se producirá cuando cada una de las clases utilice al resto, es decir, cuando tengamos un grafo dirigido completo. En el extremo opuesto, tendremos un factor de acoplamiento nulo cuando todas las clases sean totalmente independientes. En la tabla 4 se recogen los valores de esta métrica para cada una de las versiones, representados a su vez en el gráfico de la figura 142. Estos valores indican claramente que el acoplamiento disminuye considerablemente y progresivamente a lo largo de las versiones, desde un factor del 44,12 % en la primera versión hasta un 6,49 % en la última.. Irati Casi Satrústegui. Página 137.
(139) Comparativa de arquitecturas MV* Requisitos. 1. 2 3 4. BRANCH domainModel domainModel+command documentView mvp.pm mvp.pm.+facade mvp.pm.-doubleDispatching mvp.pm.+doubleDispatching mvp.pm.+composite mvp.pm+reusability mvp.pm-proxy mvp.pm+proxy mvp.pm-dao mvp.pm+dao. coupling factor 44,17 28,57 18,62 16,7 16,06 15,45 15,51 13,19 12,54 9,01 8,12 6,9 6,49. Tabla 4: Factor de acoplamiento. Figura 142: Gráfica factor de acoplamiento. Irati Casi Satrústegui. Página 138.
Documento similar
Cedulario se inicia a mediados del siglo XVIL, por sus propias cédulas puede advertirse que no estaba totalmente conquistada la Nueva Gali- cia, ya que a fines del siglo xvn y en
Sanz (Universidad Carlos III-IUNE): "El papel de las fuentes de datos en los ranking nacionales de universidades".. Reuniones científicas 75 Los días 12 y 13 de noviembre
(Banco de España) Mancebo, Pascual (U. de Alicante) Marco, Mariluz (U. de València) Marhuenda, Francisco (U. de Alicante) Marhuenda, Joaquín (U. de Alicante) Marquerie,
[r]
SVP, EXECUTIVE CREATIVE DIRECTOR JACK MORTON
Social Media, Email Marketing, Workflows, Smart CTA’s, Video Marketing. Blog, Social Media, SEO, SEM, Mobile Marketing,
Missing estimates for total domestic participant spend were estimated using a similar approach of that used to calculate missing international estimates, with average shares applied
The part I assessment is coordinated involving all MSCs and led by the RMS who prepares a draft assessment report, sends the request for information (RFI) with considerations,