Cairngorm 3 Overview

Ahora que Cairngorm 3 desde hace un tiempo ya es una realidad, on este artículo queremos mostrar que es, que nos aporta respecto a sus versiones anteriores y daremos un vistazo a su evolución.

Las versiones anteriores de Cairngorm se basaban en una implementación específica del patrón Model-View-Controller, en cambio Cairngorm 3, debido a la experiencia, quiere darnos una serie de guías, buenas prácticas y nos aporta unas librerías y herramientas para ayudarnos en el desarrollo.
Esto implica que el paso de Cairngorm 2 a 3 no sea un simple un cambio de versión si no un cambio de paradigma.

El objetivo de Cairngorm 3 es dar unas bases para conseguir unos desarrollos limpios, consistentes, testeables y fácilmente escalables.

Arquitectura de Cairngorm

Para aproximarnos a un diseño simple y testeable, Cairngorm recomienda una arquitectura concreta para las aplicaciones Flex. Esta arquitectura tiene como objetivo que la estructura de la aplicación se desglose en pequeñas unidades de funcionalidad.

Antes de ver la separación arquitectural, entendamos como concibe Cairngorm una aplicación. Está compuesta de 3 capas de alto nivel:

  • Capas de arquitectura: responsables de separar las clases según su responsabilidad
  • Áreas funcionales: agrupan clases que atañen el mismo ámbito funcional
  • Patrones de diseño: nos permiten coordinar los objetos de manera consistente

Capas de Arquitectura

Las clases con diferentes tipos de responsabilidad en las diferentes capas, pueden cambiarse separadamente por otras. De esta manera, si el diseño visual necesita ser ajustado, la mayoría de los cambios se limitan a clases de la capa de presentación y no a otras partes del código.

Cairngorm recomienda esta separación de capas según la responsabilidad general de cada una de ellas:

  • Presentation: se encarga de la apariencia visual y del comportamiento de la presentación. Cairngorm recomienda el uso del patrón de presentación Presentation Model, que se encarga de controlar el estado y comportamiento de la capa de visualización.
  • Application: coordina la presentación y la infraestructura de componentes. Coordina los componentes de distintas capas y los enlaza con los Domain Objects mediante el concepto de Controller que ya veremos.
  • Domain: se centra en las tareas sobre el modelo de negocio. Representa una abstracción del mundo real mediante un modelo de datos. Sus responsabilidades suelen ser: la validación, cálculos sobre los datos, filtro, ordenación y formateo de datos…
  • Infrastructure: coordina los objetos y su integración con otros sistemas, como el servidor y sus servicios remotos.

En la siguiente figura vemos la jerarquía de capas. De arriba hacia abajo, la comunicación entre una capa y su contigua es directa; en dirección contraria, la comunicación se realiza mediante eventos, callback functions u otras soluciones similares.
layers

Áreas funcionales

Las aplicaciones se suelen dividir en diferentes áreas funcionales. La codificación de cada área funcional suele estar agrupada y separada de otras áreas funcionales, para que así sean desarrolladas y probadas de manera independiente. Podemos tener una aplicación de ejemplo que esté compuesta por tres áreas funcionales: contactos, mensajes y gastos. Entonces, cada una de estas áreas es subdividida según las distintas capas de arquitectura, según sea conveniente, como podemos ver en la siguiente imagen:
areas-funcionales

Cada área funcional suele estar contenida en un package. Ciertas áreas funcionales, según su grado de relación, pueden estar contenidas en un proyecto separado y así extraerse en módulos. El código que suele usarse en diferentes partes de la aplicación, como componentes, suelen ponerse dentro de un proyecto de librería.

Las áreas funcionales suelen tener sus capas de presentación y aplicación. A menudo contienen sus propias capas de dominio, pero otras veces comparten conocimiento del modelo de dominio de otras áreas. En este caso, estos modelos de dominio suelen ser encapsulados en proyectos de librería. Las áreas funcionales pueden interactuar con otras mediante interfaces y eventos AS3.

Capa de presentación

Presentation Model

Una de las cosas que nos recomienda Cairngorm 3 es tender a minimizar el código dentro de los mxml. Si es posible debemos intentar no tener código ni funciones, así las vistas reducen su tamaño y se centran solo en la disposición de sus componentes; haciendo más fácil la lectura.

La manera de hacerlo es extrayendo las variables y funciones que estarían en el Script-block en presentation models.
Cada componente o vista MXML significativa debe tener su propio presentation model. El PM se centra en el estado y comportamiento requeridos para representar los datos en la vista.

Un PM no debe saber nada de otro, ni de la vista relacionada ni de qué sirve a la aplicación. Un PM no debe tener referencia a la vista a la cual sirve, sino que es la vista que observa al PM relacionado. La comunicación entre ambos se realiza mediante Bindings o eventos.

Con esta aproximación minimizamos los errores en la vista y la lógica se localiza en el PM, que es fácilmente testeable.

Coordinación entre PMs

Cairngorm nos muestra dos entidades para coordinar los presentation models con otras entidades: Presenter y Controller. A continuación los vemos con mayor detalle.

Presenters

Su ámbito se centra en la capa de presentación. Se encarga de la coordinación local entre Presentation Models de una misma área funcional o de una región de ésta. Entendemos pues que su rol está por encima de los PMs.

Sus principales objetivos son:

Desacoplar la presentación del Dominio
presenter1

Coordinación de PMs
presenter2
Como vemos en la figura anterior, reducen el acoplamiento entre PMs y los domains, escuchando eventos procedentes de los domains y comunicándolos a los PMs.

También son usados para manejar los eventos procedentes de PMs y delegarlos a otros PMs.
Las razones que nos pueden motivar a usar Presenters son:

  • Facilitan la lectura y control a alto nivel de la coordinación entre PMs
  • Se encargan de asegurar el orden en la gestión de los eventos lanzados por los distintos PMs, ya que los mecanismos de mensajería, normalmente no suelen definir un orden
  • Evitan el código de gestión de eventos (event-handling) en cada PM para escuchar a las peticiones de los otros

Controllers

Los Controllers se sitúan en la capa de Application. Tienen la responsabilidad de gestionar la coordinación general de los Presenters, no en un ámbito local, sino más global de un grupo específico de PMs. Se encargan de:

  • Traducir los eventos procedentes de un área funcional a eventos de otras áreas funcionales
  • Interceptar eventos a nivel de aplicación
  • Traducir los eventos de aplicación a llamadas de la API de dominio con la finalidad de mantener los objetos de dominio libres de cualquier conocimiento relacionado con otras capas arquitecturales

controller

En situaciones determinadas, los PMs pueden comunicarse directamente con los objetos de dominio y recibir sus cambios mediante eventos, como podemos ver en la siguiente figura:
pm-dm

Aplicaciones Modulares

La modularidad va más allá de los conceptos de Flex Module y ModuleLoader. Implica la separación de aplicaciones en unidades pequeñas que pueden ser desarrolladas y testeadas independientemente.

Beneficios de la Modularización

  • Un modulo puede ser desarrollado, y probado con una relativa independencia
  • Los tiempos de compilación se minimizan, ya que los cambios en un módulo no requieren de otros módulos
  • Los módulos pueden ser cargados bajo demanda, lo que hace que la carga inicial de la aplicación es mucho menor
  • Si un usuario no usa un determinado módulo, no es necesario cargarlo
  • Se pueden cargar diferentes módulos para distintos usuarios, según sus privilegios
  • Un modulo es más fácil de entender y mantener que una aplicación monolítica, consiguiendo una mejor cohesión funcional
  • La interacción entre módulos puede determinarse con APIs, independientemente del crecimiento de la aplicación

Modularización y Cairngorm 3

Como hemos visto, una de las claves de Cairngorm 3 es separa las aplicaciones en diferentes áreas funcionales que pueden ser desarrolladas independientemente; viene a ser una arquitectura modular, donde cada área funcional sería un módulo. Cairngorm recomienda que la comunicación entre las distintas áreas funcionales se haga mediante APIs definidas por interfaces, eventos y DTOs. Así minimizamos las dependencias entre las distintas áreas.

Tendencia hacia el bajo acoplamiento

Cairngorm 3 da mucha importancia a que las capas arquitecturales tengan un mínimo acoplamiento, asumiendo que cada capa cambia por motivos diferentes. Con un bajo acoplamiento en las distintas capas, éstas pueden tolerar mejor el cambio. Por otro lado, el bajo acoplamiento tiene un precio: cuanto menos acoplado esté un objeto a otro, se incrementa la dificultad de lectura.
Hay distintas opciones para conseguir un bajo acoplamiento que los desarrolladores deben tener en cuenta.

Opciones para construir, recuperar y aislar objetos

La manera en que creamos, recuperamos o aislamos los objetos en una aplicación Flex, es un aspecto importante.
Por ejemplo, creando un objeto de dominio dentro de un PM, provocamos una dependencia directa. Implica que el objeto queda aislado y si otra parte de la aplicación requiere este objeto, no tendrá acceso directo para consultarlo.

Además con esta dependencia forzada con el objeto de modelo dentro del PM, estamos atando fuertemente la capa de presentación a una implementación concreta del dominio. Con una interface del dominio y usando eventos, podemos bajar el acoplamiento, desacoplando las capas arquitecturales.

La implementación de un objeto de dominio no puede cambiarse sin cambiar la implementación del PM, lo cual puede restringir la flexibilidad de la aplicación.
Los objetos de modelo tienen un significado a más alto nivel que el PM. Cuando el dominio puede abstraerse y controlarse con objetos de más alto nivel, conseguimos una inversión de control, que se opone a la aproximación usual de que objetos de bajo nivel controlan a otros.

Opciones de separación de la construcción y comportamiento de los objetos

Puede ser muy incómodo para el PM substituir el objeto de dominio con una implementación diferente cuando el PM crea al objeto de dominio. Puede también ser muy incómodo el hecho de recuperar una misma instancia del dominio en un determinado lugar de la aplicación. Tenemos diferentes opciones de separar la creación del comportamiento de un objeto para simplificarlo, a continuación mostramos las dos más comunes.

  • Aproximación transversal: El modelo de dominio se instancia en el PM o Vista de más alto nivel y se va propagando jerárquicamente a las subvistas o PMs relacionados.
  • Aproximación con framework de IoC: Se responsabilizan de la construcción de los objetos. El desarrollador especifica los objetos que se necesitan en el container de IoC.
    Así el framework IoC puede proporcionar estos objetos mediante inyección de dependencias o dependency lookup.

Librerías que nos proporciona Cairngorm

Cairngorm 3 proporciona diferentes librerías, alguna de ellas construidas sobre frameworks existentes como Parsley, Swiz y Spring ActionScript.
Estas librerías son interesantes, tenemos librerías para validación, para la gestión de popups, de navegación, gestión de módulos, etc. Recomiendo que leáis este apartado para que veáis que nos proporciona.

Para entender más como funciona Cairgorm 3 y los distintos conceptos, es necesario mirar y analizar un poco el código de las aplicaciones de ejemplo.

La información de Cairngorm 3 está en este link.

Comparte:



4votos  Vota!!

Acerca de esta entrada