Videoclub - Desarrollo Iterativo

Resolver el sistema del videoclub usando desarrollo iterativo

Antes de empezar

Al arrancar este proyecto, yo contaba con conocimientos casi nulos sobre flex. Este proyecto me sirvió entonces para aprender dicha tecnología. El resultado final no es un proyecto flex de la manera standart que propone Adobe y el mercado, por lo tanto desarrollé posteriormente otro proyecto para que sea el oficial de la cátedra. Sin embargo este proyecto es útil como caso de estudio en el cual se aplica desarrollo iterativo como principal arma para atacar la incertidumbre de una teconología desconocida.

Vamos a ir encontrando un modelo de aplicación mientras avanzamos por las distintas iteraciones. En cada iteración evoluciona en forma conjunta el modelo como el dominio de la tecnología.

Siempre es bueno tener a mano el sitio de documentacion oficial http://livedocs.adobe.com/flex/3/html/
El Flex builder tiene una sección de help que en ocaciones es útil

Mini-resumen de flex

Flex es un framework que genera aplicaciones con el bytecode de Flash, por lo tanto, estas aplicaciones pueden correr en cualquier browser que tenga instalada la VM de flash. Propone un ambiente de objetos haciendo énfasis en objetos visuales. Utiliza dos lenguajes: MXML (basado en xml) y ActionScript. Ambos pueden colaborar para construir una aplicación. Hay muchas maneras de integrarse con una aplicación servidor. La aplicación en el server puede ser de distintas tecnología. A lo largo de este ejemplo usaremos LiveCycle DS, que entre varias cosas, permite vincular objetos ActionScript con objetos Java.
Flex no impone ni propone ningún modelo ni arquitectura de Aplicación.

Elementos a instalar:

Flex Builder: Es un ide basado en eclipse especial para flex. No es gratis, pero se puede bajar una versión trial del sitio de Adobe https://www.adobe.com/cfusion/tdrc/index.cfm?product=flex Existen alternativas gratis, pero la verdad que desconozco cómo son. En mi opinión al flex builder le falta madurar un poco (se necesita mucho más opciones refactors). Tiene un debug aceptable y si se quiere construir pantallas visualmente es bastante útil (sincroniza una vista de diseño dónde se arrastran componentes con el código mxml). No es indispensable instalar esto para seguir este documento.

LiveCycle Data Services Es una aplicación que corre en un Servlet Container. La necesitamos para poder comunicarnos con objetos remotos. Dentro de esta aplicación vamos a agregar como lib el jar del dominio del videoclub. Sería como una aplicación contenedora de nuestra aplicación. Tiene licencia gratis si se corre una sola aplicación en un solo server. BlazeDS es una alternativa gratis. Otra opción (pero paga) es ColdFusion. El LiveCycle DS también se baja de Adobe, y no debe confundirse con LiveCycle ES (enterprise suite) (que es un framework para construir aplicaciones empresariales en Flex, que tampoco es free)
https://www.adobe.com/cfusion/entitlement/index.cfm?e=lcds26_td

Tomcat Yo uso el tomcat que vino con el LiveCycle DS, pero en teoría podría ser cualquier ServletContainer dónde se deploye el lcds.war. Otra cosa que me resulta útil es tener un Eclipse con el plugin del sysdeo (podría ser también wtp) apuntando a dicho tomcat, esto me permite debuguear la aplicación en el server.

Configuración inicial

Lo primero que vamos a hacer es que el lcds conozca al videoclub, por lo tanto copiamos videoclub.jar en TOMCAT_HOME\webapps\lcds\WEB-INF\lib
Como este proyecto usa commons-collections-3.2.1.jar, también copiamos ese archivo en el lib

Luego vamos desde el FlexBuilder vamos a crear un nuevo proyecto flex (file-> new -> Flex Project), lo llamaremos Videoclub, dejamos la opción web application (Air es un superconjunto de flex, que permite armar construir aplicaciones d escritorio). En Application Server Type elejimos J2EE. Marcamos "use remote object service" y elegimos LiveCycle Data Services".
Clickeamos en next, y hay que configurar tres parámetros:
Root folder: es la carpeta dónde está la aplicación lcds. La usa para deployar automáticamente. suele estar en TOMCAT_HOME\webapps\lcds
Root url: Es la url a la cual le pide lo que deployó cuando pedimos run o debug. http://localhost:8400/lcds
Context root: Todavía no me explico por qué lo necesita, si se desprende del parámetro anterior, pero bueno, si lo quiere se lo configuramos, es "lcds"

Aceptamos y listo, aparece un archivo Videoclub.mxml. podemos arrastrar un componente en la vista de design, darle run al flex builder, y ver cómo tenemos un hola mundo funcionando.

Configurando el RemoteObject

Un objeto remoto es un objeto con comportamiento, pero que reside en el servidor. Cuando hablamos de java, la clase remota tiene que tener un constructor público vacío. El lcds lo instancia cuando lo necesitamos. En nuestro caso, lo que queremos es poder acceder al Dao de clientes. Como éste es un singleton, no puedo convertirlo en un objeto remoto (o por lo menos todavía no se cómo). Entonces me hice un proyecto java para que me haga de adapter entre el modelo de dominio y mi Applicación Flex. Ésta es la motivación de videoclub-flex-adapter.jar que debe incluirse en el mismo directorio lib que videoclub.jar.
Por otro lado, un RemoteObject tiene un atributo destination, la forma de utilizar este atributo varía según la tecnología remota. En nuestro caso vamos a asociarlo a un nombre de clase. Eso se hace en el archivo remoting-config.xml
El mismo se encuentra en TOMCAT_HOME\webapps\lcds\WEB-INF\flex

Note que hay otras formas de comunicar el cliente con el servidor, se puede usar pedidos http o web services. A mi me pareció interesante esta forma porque es la que mejor calza con la idea de objetos vivos en un ambiente

Versión 0 : videoclub.0.rar

La primer versión me sirvió para pelearme con flex, darme cuenta de las características que me pueden servir y cuáles tengo que tener cuidado. Sigue una filosofía "visual basic'" dónde generé la vista arrastrando componentes en la ventana de design. Declaré un RemoteObject con mxml y escribí funciones asociadas a los eventos.
Completé el ABM de cliente, y ahí frené para refactorizar (no está implementada la capacidad de alquilar películas). La aplicación resultante carece de diseño, quedó muy mezclado lo que es la vista del modelo.

Cliente.as
La clase Cliente.as está anotada con RemoteClass, lo cual permite que si le paso un Cliente por parámetro a un método del RemoteObject en el servidor se convierta en un Cliente java (y viceversa), basta con que los atributos se llamen igual y tengan tipos compatibles. De esta manera, los objetos que tiene la grilla son de Clientes. Si no existiera Cliente.as, flex construiría un objeto con las mismas propiedades (ActionScript permite agregar variables y funciones dinámicamente). Esto puede ser útil si sólo se necesita trabajar con datos.
La contra de esto es que tengo duplicado la definición de Cliente en el server y en el cliente. Esta es una característica que considero negativa y de la cual no pude desprenderme a lo largo de todo el proyecto.

Estados
Flex permite agregar o eliminar componentes en forma dinámica a la vista, lo cual permite pensar la aplicación de manera muy distinta a una sucesión de pantallas (cómo nos tiene acostumbrada las tecnologías web). Sin embargo, una manera de simular distintas pantallas es a través de los estados. En este caso, por requerimiento, tengo dos pantallas bien diferenciadas. Un estado es una definición de componentes. Se genera a partir de un estado anterior agregando o removiendo elementos (y alguna que otra cosita más). Si agrego componentes a la aplicación sin indicarle a que estado pertenecen, entonces pertenecen al estado default.
Esta versión maneja dos estados, el estado default que tiene casi todos los casos de usos y la grilla, y el estado ItemEdición (la pantalla de edición). Un estado se puede definir declarativamente en el mxml o visualmente (hay una vista de sates)
Para cambiar de estado simplemente se dice Application.currentState = "nombreEstado". Para ir al estado default, se usa null.

Binding
Esta capacidad de que la aplicación responda ante el seteo de una propiedad es interesantísima. Esto ocurre porque Flex tiene la capacidad de agregar observers desde el lenguaje. Alguien está escuchando el evento propertyChange de Application.currentState. más adelante usaremos esta característica.

RemoteObject
Al remote objeto se le declaran los métodos. El nombre del método tiene que concordar con el nombre que tiene en el servidor. Se indica de dónde saca los parámetros para la llamada. Cómo las llamadas son asyncrónicas (la aplicación sigue su curso y no se bloquea esperando la respuesta del servidor), se tiene que pasar un callback (función que se va a llamar cuando llegue la respuesta). Flex tiene capacidad de manejar llamadas syncrónicas, pero no lo vamos a utilizar.

Versión 1 : videoclub.1.rar

En esta versión intento empezar a separar los distintos conceptos de MVC. Primero quise separar la definición del RemoteObject del objeto Application. El mxml me estaba quedando incómodo de trabajar, y por eso decidí cambiar de estrategia y comencé a generar la vista programáticamente. Cómo lo que estoy haciendo es un ABM (CRUD en inglés), generé una clase Crud que es llamada desde la Application. La versión uno no es exactamente una versión posterior al 0, porque práctimente construí todo de nuevo ya que cambié la filosofía de la aplicación.

Entity y Reflection
Esta clase la hice como clase base a todas las entidades. Yo quería hacer un Crud de Clientes, pero que no me quede acoplado a Cliente, así de esta forma podía llegar a reutilizarlo. Por otro lado, no quiero manualmente agregar un inputText
a cada propiedad String de un objeto. Llevando la idea del "once and only once" cómo bandera, mis entidades se pueden describir y en base a esa declaración se generan los controles (programación declarativa).
Para describir al objeto usé reflection de flex. La forma de implementar reflection es para mi una de las características más flojas. Hay funciones globales que se pueden importar y lo que devuelve es un objeto XML, que tienen objeto XMLList, y la forma de acceder a los nombres y tipos de las variables es incómoda.

Model del Crud y Bindings
La separación entre el modelo y la vista se hace más fuerte. Antes, al buscar la lista de clientes, el callback del remote object actualizaba directamente la grilla. Ahora Tengo una lista que representa el resultado de la búsqueda y es lo que actualizo con el callback. Tengo también en el modelo un Cliente (entity), entonces al actualizar un inputText de la vista se actualiza directamente una propiedad de mi objeto Cliente. Esta es una decisión de diseño, yo encuentro dos aproximaciones usadas comunmente para representar el modelo: Tener un objeto o tener un conjunto de valores que luego se trasladan a un objeto. En este caso opté por la primera. Las consecuencias de cada una de las dos aproximaciones se escapan al objetivo de este documento.
Todas mis acciones actúan contra el modelo. Luego, la forma de actualizar la vista es haciendo que al momento de construirla se bindeen las propiedades de los campos de la vista con los del modelo. Para eso use la clase BindingUtils. Se puede generar bindigns con el mxml también usando llaves o el tag Binding. En este link hay más información.
Cómo la grilla de resultados tiene que cambiar cuando la propiedad searchResult cambie, Entonces searchResult tiene que anotarse con "Binding".
Otra decisión (o mejor dicho, consecuencia de la forma en que está implementado), es que el modelo de aplicación y las vistas se construyen en forma ansiosa. Es decir, al iniciar la aplicación, construyo todo el modelo, y todas las vistas. Esto en aplicaciones grandes puede tener como consecuencia una inicialización lenta y un consumo de memoria excesivo.

RemoteOject con action Script
No hace falta definir los métodos en el RemoteObject. Cada operación es un método que se agregó dinámicamente a una instancia de RemoteObject. La forma de decirle que llame a una función callback al ejecutarse un método es pasándole un objeto Funtion al agregar un eventListener. En nuestro caso, la línea para asociar el método found con el callback del método find del objeto remoto es:
server.find.addEventListener(ResultEvent.RESULT, found);
Luego construí un botón asociado al método find del crud, que dispara el mensaje al servidor haciendo:
server.find(this.model);

Note que en esta versión, cambié la interface del objeto remoto usado en la versión anterior. Lo hice por cuestiones de prolijidad principalmente, lo que me va a permitir tener Cruds de cualquier tipo de objetos.

Versión 2 : videoclub.2.rar

En esta versión agregué las acciones que no necesitaban un cambio de pantalla. A partir de ahora, si se nota más como el desarrollo es iterativo, haciendo mucho refactor de lo que estaba antes, pero sin cambiar radicalmente la filosofía. También se puede ver cómo voy anotando ideas en el código. Estas ideas muchas veces en versiones posteriores se llevan a cabo. Otras anotaciones son simplemente cosas que quiero refactorizar después. También anoto las cosas de las cuales no estoy seguro, esto me sirve para que si en algún momento esa parte del código me queda molesta, lo cambie sin sentir culpa alguna.

Action
Cómo cada acción significaba un llamada al remote object, y pasarle un callback. Encontré la abstracción de Acción. que básicamente saben configurarse para actuar sobre un modelo, agregarse a una vista, y ejecutarse. La forma de hacer estas cosas a lo largo de todo el proyecto fue cambiando, pero esas responsabilidades siempre quedaron. No me quedó del todo prolijo el que hacer después de ejecutar una acción, y me quedó acopladísimo con el Crud, pero es un problema que dejé para solucionar más adelante.

Versión 3 : videoclub.3.rar

Le di una vuela a las acciones para encadenarlas. Eso me dió muchísimo poder para describir la secuencia de acciones que ocurren en un caso de uso. Puedo decir que: "Despues de agregar un cliente, se tiene que buscar la lista de clientes"

Otro cambios: Las entities saben limpiarse. Esto lo necesito por consecuencia de mi decisión de que el modelo es el mismo cliente durante todo el crud.

Versión 4 : videoclub.4.rar

Ataco la necesidad del cambio de pantalla: Cuando quiero modificar un objeto, la pantalla que muestro es considerablemente distinta a lo que estaba mostrando.

Mode
En la versión 0 los cambio de pantalla los hice manejando los states de flex. Esa aproximación me pareció interesante. Sin embargo, el concpeto de "State" es algo propio de la implementación de flex. Buscando una abstracción que me lleve más cerca del lenguaje en el que quiero hablar para construir la aplicación es que aparece el objeto Mode. La metáfora es: "Un caso de uso (crud por ahora) puede estar en distintos modos: puede estar en módo búsqueda o en modo edición" Cada modo tiene su propia vista con sus propias acciones, sin embargo comparten el modelo.
Para el crud, me alcanza con estos dos modos, luego voy a asociar un state a cada modo, y cuando cambie de modo (acción de negocio) cambiará el estado (cuestión de implementación). El mode All es como un modo abstracto, para que sea base del resto de los modos.

ViewBuilder
Ya no me alcanza construir la vista agregando objetos a un container de flex, que es cómo venía trabajando. Entonces el viewBuilder le puedo decir que agregue componentes en un modo. Esta es la interface que quiero usar para construir aplicaciones.

ViewBuilderImpl, StateBuilder y sus subclases
Son objetos internos, son los que realmente agregan los componentes a los estados que corresponden y arman esa definición de que un estado es un incremento de un estado anterior. Además necesito distintas subclases porque el estado default se maneja particularmente distinto.

Versión 5 : videoclub.5.rar

Si bien faltan muchas cosas del modelo de aplicación para avanzar, es hora de retocar un poco el aspecto visual de la aplicación. Pensando en cómo me gustaría que sea, me amigue con el mxml y el editor visual. El Videoclub.mxml es ahora también un template.

ElementType
En el template definí distintos lugares para agregar elementos. En particular me interesaba diferenciar los botones de las acciones con respecto del resto de los controles. Esta separación no es un capricho de visualización, significa que hay alguna diferencia conceptual entre ambos, y como toda diferencia significativa que influye en mi aplicación, corresponde generar una abstracción que la represente. Así surge el ElementType, que a nivel de implementación me asocia el concepto de Acciones o Controles con su respectiva región para agregar componentes.
Ahora el ViewBuilder los componentes se agregan en un Mode y son de un ElementType.

UseCase y CrudModel
Por otro lado seguí trabajando en la separación entre el caso de uso y el modelo del caso de uso. En useCase me quedó la capacidad de iniciarse y de cambiar de modo, mientras que moví a CrudModel todo el resto de las responsabilidades. En versiones posteriores, seguramente el CrudModel debería ser una implementación de UseCaseModel, y así seguir subiendo el nivel de abstracción para separar el modelado de una aplicación con una aplicación particular.

Tamaño de botones
Otra cosa chiquita que hice, para darle un aspecto visual más consistente, es hardcodear el tamaño del botón para que tenga el mismo ancho del panel. Estoy seguro que se debe de poder hacer en forma dinámica, pero me llevaría bastante tiempo descubrirlo, y con ese pequeño hack, le di la consistencia que necesitaba. En otro momento me ocuparé de arreglarlo.

Versión 6 : videoclub.6.rar

Ahora ataco el segundo caso de uso, que es el alquilar. Para poder lograrlo, tuve que modificar nuevamente el modelo de dominio, porque Cliente.java no tenía a la lista de pedidos como una property (no respetaba el contrato de javaBean). Esto es lo único que nos obliga la forma de comunicación a través de RemoteClass. Entonces, hay que reemplazar el jar videoclub.jar por videoclub2.jar
Por otro lado, en el proyecto flex-adapter, le cambié el significado al objeto Crud, y lo comencé a llamar Home. Construí las homes de las entidades que me faltaban, y les agregué la posibilidad de que a través de la misma se pueda enviar un mensaje desde flex al entity del server. Hay que reemplazar el archivo videoclub-flex-adapter.jar con videoclub-flex-adapter2.jar.
Las nuevas homes están mapeadas en una nueva versión del archivo remote-config.xml. Descargue el archivo remote-config2.xml, renómbrelo a remote-config.xml y reemplace el anterior.

Interface UseCaseModel
Cómo se veía venir, el modelo tengo que usarlo para otros tipos de cas de uso, y por eso surge la interface UseCaseModel del cual el CrudModel es un tipo particular. Hay un cambio sutil de la forma en la que hablan, y es que el caso de uso deja de pedirle acciones al modelo para luego agregarlas a la vista, y comienza a delegar en el modelo eso. Me quita un problema de encima a la hora de tratar la comunicación entre ambos objetos.

ApplicationModel
Quise adaptar mi aplicación para que soporte más casos de usos. Cómo mi aplicación sabía hablar sólo de cruds, agregué un Crud de películas. La filosofía de que el main de la aplicación sea iniciar un caso de uso me pareció que estaba bien, y por eso generé un caso de uso que tenía como modelo un "ApplicationModel" que me modela los distintos casos de uso que tiene mi aplicación, y al iniciar agrega acciones del tipo "UseCaseBeginAction". Estas acciones tienen definido un nuevo ElementType que define la region de la barra de control.

Model y SearchModel
Las cosas que tienen sentido para el negocio, empiezan a tener cosas en común, y por eso aparece la interface Model. Luego, cómo veo que el caso de uso para alquilar tiene una búsqueda de películas muy similar a la que aparece en el crud, separé el SearchModel del CrudModel.

Entity
El entity empieza a ganar importancia, ahora es el mismo entity quien puede encontrar su home (representada por un objeto remoto). Tambien empiezo a delegar ahí la capacidad de construir su vista. La separación no queda del todo prolija pero empieza a tomar forma.
El entity a su vez puede construir acciones de comenzar otros casos de uso, eso me da el lugar para que desde el crud de clientes, se pueda elegir un cliente y empezar a alquilar. Cómo el cliente que construye el modelo del Alquiler es el que se usa como modelo del crud y no el objeto seleccionado, tenía el problema que al clickear el alquilar, se perdiera el cliente. Varias formas de arreglar ese problema se me ocurrieron, pero ninguna me convenció del todo. Lo que terminé haciendo es un objeto "UseCaseConnector" que intercepta las acciones que crea el entity y le agrega una acción para copiar en el modelo los datos del entity seleccionado.

Usando componentes realizados por terceros
Empiezo a manejar en la visualización de un entity, la capacidad de tener colecciones. Estas colecciones son del tipo ArrayCollection y no Array debido a que ArrayCollection implementa la interface ListCollectionView que tiene la capacidad de observar los eventos de agregar y remover items, con lo cual, un componente visual puede reflejar dichos cambios. Ahora cuando se va a la pantalla de modificar un objeto, se puede ver también el contenido de sus colecciones. Sin embargo, me pareció interesante la idea de que esta lista se pueda colapsar. Cómo flex no traía ningún panel colapsable, busqué por internet un componente realizado por un tercero. Este componente compilado es un archivo swf. Lo agregué a la carpeta lib y apartir de ese momento ya puedo utilizarlo.

Caso de uso alquilar
No necesité generar más abstracciones de las creadas anteriormente, simplemente un model particular y unas acciones particulares que me servían para ir armando un pedido y luego decir remotamente al cliente que agregue dicho pedido.
Toda la construcción ocurre en el cliente y al servidor le llega el pedido ya consistente.
Dos problemas que se me presentaron que los resolví de forma similar:
Ni la película ni el pedido tenían las propiedades de costo. En el pedido porque es un atributo calculado (se resuelve a través de un mesaje) y en la película porque es un valor constante que no admite un set.
La forma en que lo solucioné, es agregando un atributo "total" en el pedido de ActionScript. Este total se recalcula cada vez que hay un cambio en la colección de películas, para lo cual agregué un eventListener a la misma. La forma de calcularlo es mandado el mensaje "getCosto" a un objeto pedido reflejo de ese en el lado del servidor. Todo esto ocurre en la clase Pedido.as

Problema con los modos y los elementTypes
Un problema que ocurre, es que los modos del crud no son exactamente los mismos que los modos del alquiler. En alquiler adopté el modo "Search" porque al usar un searchModel se estaba fijando este valor. Por otro lado las entities se agregan igual para todos los modos, con lo cual al cambiar del modo "search" al modo "Medio de pago", los input para buscar la película no desaparecen.
Además se puede ver que los elementTypes definidos a nivel aplicación me quedan cómodos en el Crud, pero no me alcanzan para el alquiler.

Estos dos problemas implican un refactor bastante grande, y por eso di por finalizada la iteración.

Versión 7 : videoclub.7.rar

Con la funcionalidad completa, me dediqué a refactorizar el problema de los modos y otras pequeñas cositas que venía usando. Entre los cambios chiquitos pero saludables se encuentran el uso de estructuras for each propias del lenguaje en lugar de usar el método forEach de Array, y que en los lugares en que necesitaba realizar alguna diferenciación por el tipo de un atriubuto dejé de utilizar el propery.@type == "…" por un object[property.@name] is "…". La segunda versión es similar a un instanceof de java, y por eso se fija en toda la jerarquía de objetos.
Otro cambio pequeño pero importante, es que la vista del caso de uso ya no se construye en forma ansiosa, ahora se espera al inicio del caso de uso.

ComponentFactory
La forma de independizar la construcción de vistas de los modos fue generando objetos que tengan por funcionalidad construir vistas (ComponentFactories). Entonces, al modelo de un caso de uso, se le agregan estas partecitas que en su conjunto pueden construir la vista del caso de uso completo. Cuando instancio un ComponentFactory, le indico un conjunto de modos en los cuales tiene que operar lo que construye. Esto me quita el hardcodeo de que el searchModel tiene que actuar en modo "search". El Crud instancia al SearchComponentFactory en modo "Search" mientras que el alquilar lo hace en el modo "Pedido Building" (por qué el spanglish?? no se… tengo que verlo con mi psicóloga, les juro que tenía sentido para mi cuando lo construía)

Action Factory
Es un tipo especial de ComponentFactory pero me sirve para crear acciones (cambia el template method a sobreescribir)
Un refactor para hacer a futuro es quitar los modos de las acciones, y que trabajen contra un StateBuilder cómo hacen los ComponentFactories. Sin embargo al escribir un ActionFactory, no necesito setear el modo en las acciones. El ActionFactory les va a trasladar los modos que tenga configurados.

Fíjense que esta iteración no cambió nada visual, pero me cambió un poco la filosofía: Ahora mi Aplicación tiene casos de usos que tienen UseCaseModels. Los UseCasesModels pueden usar otros objetos Model pera la forma de construir las vistas y acciones de los mismos se hace agregando objetos externos. Ahora un caso de uso es: UseCase + UseCaseModel + varios ComponentFactories.

Modes
Moví las constantes de los modes predefinidos a CrudModel, porque en realidad eran modos que tenían sentido sólo en el Crud.

Funciones transformers
El componente SearchComponentFactory sabe construir a partir de un SearchModel los objetos visuales que mapean contra el mismo. Ahora, mi crud usa un SearchFactory, y yo quiero usar mi SearchComponentFactory, entonces le agrego una función que sabe a partir de mi CrudModel obtener un SearchModel.
Acá hay un posible refactor para hacer: Si yo pudiera decir declarativamente que mi Crud se compone de un Search, podría inferir solito la forma de llegar hasta el mismo. Otro posible refactor (que no es contradictorio con el Anterior) es que los ComponentFactories se puedan agregar a cualquier tipo de Model y no solo al useCaseModel.

Version 8: videoclub.8.rar

Primero solucioné algún que otro bug de que estaba mal configurado los modes en los ComponentFactories de Alquiler.
Otro de los cambios chiquitos, es que me di cuenta que no necesito guardarme el application en ApplicationModel. Hay un objeto Application que me lo sabe dar.
También fui quitando el application de dónde no lo necesitaba y reemplazando objetos useCase por useCaseModel. Quizás en algún momento Ambos objetos se conviertan en el mismo.

ViewRegion
Dejé de mentir… nunca supe que significaba un ElementType, sólo sabía que me definía una región de la pantalla. Entonces cambié el nombre y lo empecé a llamar ViewRegion. Si en algún momento descubro que significa le cambio el nombre, pero me pareció saludable el sinceramiento.
otro cambio que realicé, es que ya no hace falta setearle un container desde afuera. Interceptando el get de la propiedad container, hice que la primera vez que alguien lo pide, busque por nombre en toda la estructura de la aplicación. El primer container que tenga por id el nombre de la ViewRegion es dónde se agregan los objetos.
Ahora los componentFactories tienen además de un modo en el cual actuar, una viewRegión dónde generar los componentes

Template del Caso de uso
Cada caso de uso va a usar además de las regiones definidas en Application sus propias regiones. Por eso agregué un método al useCaseModel llamado "addViewRegion", cuyo propósito es agregar en el viewBuilder los containers que luego usarán los viewRegion de ese caso de uso. Definir un template es más fácil con un objeto mxml, aquellos mxml que tienen como padre un canvas (u otro tipo de container) son también un container. Entonces construí de manera visual el archivo AlquilarTemplate.mxml. La única diferencia significativa entre hacer new de un objeto ActionScript y new de un objeto mxml, es que luego de instanciado, el objeto mxml necesita que se le invoque el método "initialize".Así al viewBuilder le agrego un objeto AlquilerTemplate inicializado, y cuando los componentFactories necesiten usar esas regiones, las van a encontrar.
Aquí hay otro refactor para hacer: Me alcanzaría con que que el UseCaseModel me defina la clase.

Version 9: videoclub.9.rar

Luego de tener la funcionalidad completa y la vista completa me dedico un poco a la usabilidad. En particular, el sistema me permitía ejecutar acciones en estados inválidos: Podía intentar dar de alta un cliente vacío o generar un pedido sin ninguna película. Estas acciones incorrectas traen problemas. Tengo tres estrategias para resolver el problema:
1. dejar que el servidor se encargue, y manejar mejor la exception.
2. Al ejecutar una acción, realizar validaciones.
3. Deshabilitar los botones de las acciones que no se pueden realizar.
Yo opté por la tercer opción, (si a alguien le interesa la 2da opción, puede ver el capítulo de validadores de la ayuda de flex) http://livedocs.adobe.com/flex/3/html/validators_1.html

Enabler
Para habilitar o deshabilitar un botón (u otro control) hay una propiedad "enabled". Yo modifiqué mi interface Action para que tenga el atributo enabled también (En ActionScript se puede definir variables definiendo sus funciones de set y get). Al construir un botón bindeo su propiedad enabled con el de la acción, de tal modo que al deshabilitar la acción deshabilito el botón.
La clase Enabler se aplica sobre una acción. Las distintas subclases de Enabler se aplican de forma distinta, pero en general lo que hacen es Bindearse contra alguna o varias propiedades del modelo de la acción, para que si ésta cambia, entonces revalúe si debe habilitar o deshabilitar a la acción.
Por ejemplo, el ConsistentEntityEnabler es quien se encarga de habilitar o no la acción para agregar o modificar un objeto en el crud. Él escucha todos los cambios sobre las propiedades de un Entity. Cuando hay algún cambio, habilita o no la acción según el entity esté o no consistente. En principio un entity es consistente si sus campos son no vacío. (Claro que esto con una metada más rica podría cambiar.
La función adapter cumple la misma función que en los Component Factories, adapta el modelo de la acción, a un objeto con el cual sabe interactuar.

Cómo sigue?

Esta no es la aplicación perfecta, de hecho tiene varios problemas descriptos en el mismo código y en este documento. Pero la realidad es que siempre hay cosas para mejorar y entrar en una etapa de permanente refactor no suele ser muy productivo. Los pasos que yo seguiría a partir de este modelo, es separar la aplicación Videoclub del framework que fuimos construyendo (todos los componentes arquitecturales que están en el package application) así sirve para construir otras de aplicaciones. Y en cuanto a las cosas a trabajar en el framework, creo que hay dos caminos que aún le falta mucho trabajo. Uno tiene que ver con la construccion de un caso de uso, el modelo, y los componentsFactories. Eso lo llevaría a una forma más declarativa. Por otro lado, el manejo de la metadata está muy limitado. El modelo del RemoteClass me lleva a tener duplicaciones de definiciones, por cada EntidadConcreta.java tengo un EntitadConcreta.As, y tengo que hacer configurar una home y programarla en el servidor. Este procedimiento es excesivamente burocrático. Yo prefiero llevarlo a un modelo en el cual el servidor me envia metada rica, y construir las vistas y modelos en función de su metadata.

Volver a Material

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License