sábado, 23 de febrero de 2008

Programacion Modular en Flex

Update: 2009-03-30: Hay un nuevo post con mas informacion sobre modulos

Hay un viejo dicho en el mundo informatico que dice "Divide y venceras". Entre mas podamos dividir los problemas mas facil sera resolverlos... entre mas podamos dividir la carne mas facil sera comerla... entre mas podamos dividir el trabajo mas rapido sale...bueno!!! Hay veces que ni diviendo el trabajo sale mas rapido.. a veces demora mas tiempo... pero bueno entienden la idea

Cuando tenia tiempo para jugar hace como 15 anhos, mis juguetes favoritos eran los Legos. Me fascinaba como podia ir usando distintas piezas para crear nuevos disenhos que en mi imaginacion eran copias autenticas y reales de algo que existia en la vida real. Todo lo que ocupaba eran las distintas piezas para crear un carro, una casa o un ascensor (si yo se! quien hace un asensor con Legos pero bueno...). El producto final estaba formado con distintas piezas y cada pieza tenia forma distinta y yo solo tenia que utilizarlas de la mejor manera.

Bueno, a partir de Flex 2, se anhadio una funcionalidad parecida, los modulos. Los modulos son aplicaciones Flex aparte que son cargadas en tiempo de ejecucion por parte de la aplicacion cuando s. Esto hace que se puedan brindar las siguientes ventajas (entre otras):
  • Se puede dividir el tamano de la aplicacion en multiples pedazos que seran cargados unicamente cuando se necesiten.
  • Se puede dividir el trabajo entre distintas personas de forma mas definida.
  • La separacion de funcionalidad es bastante mas clara a la hora de utilizar modulos.

Existen 3 formas o modelos distintos para crear modulos:



1. Se crea un proyecto para la aplicacion principal y dentro de ese proyecto se anhaden los distintos modulos.
2. Se crea un proyecto para la aplicacion principal y se crea un proyecto aparte donde se mantendran los demas modulos.
3. Se crea un proyecto para la aplicacion principal y se crea un proyecto aparte por cada uno de los modulos.

Y cual es la diferencia entre ellos???

Bueno... baso mi respuesta en lo que esta ocurriendo en mi trabajo con un proyecto bastante grande. Este proyecto es un hibrido entre unas aplicaciones Flash y unas en Flex. En realidad toda la persistencia de datos la basamos en Flex con Remote Objects (usando obligatoriamente por supuesto el Cairngorm...) La parte visual y bonita esta hecha en Flash, exportados como componentes .swc (algunos de tamanos considerables) y nos comunicamos entre Flash y Flex por medio de eventos... Suena un poco raro.. pero creanme que esto funciona muy bien. El caso es que dentro de la aplicacion se definieron varios modulos y cada uno puede usar componentes de Flash distintos o algunas veces se repiten.

La idea de utilizar modulos se da debido a que queriamos rebajar el tiempo de carga que tuviera la aplicacion. Si cargamos todos los componentes Flash de un solo en la aplicacion la misma tendria un tamano inmenso y por lo tanto los usuarios preferirian ir a otros lugares. En cambio si cargamos las librerias y los modulos solamente cuando el usuario los ocupe, esto nos ahorraria mucho tiempo de espera en el lado del usuario.

Si hubiesemos seguido el modelo 1 ocurriria lo siguiente:
Cargamos todas las librerias en el proyecto, ponemos los distintos modulos y la aplicacion principal todo junto. En realidad no hubieramos dividido nada. Logicamente talvez exista una division debido a los modulos pero fisicamente en tamanho hubiera quedado igual una aplicacion inmensa ya que la aplicacion cargaria todas las librerias desde el inicio.

Si hubiesemos seguido el modelo 2 ocurriria lo siguiente:
Cargamos todas las librerias de flash en el proyecto con los modulos. La aplicacion principal se ahorraria de cargar todas esas librerias al inicio, sin embargo todos los modulos referenciarian a todas las librerias aunque no las vayan a utilizar. Osea continua siendo lo mismo.

Y como escogimos el modelo 3 ocurre lo siguiente:
La aplicacion principal tendra las librerias que se necesiten usar. Cada modulo como esta en un proyecto aparte hara referencia solamente a las librerias que ocupe cargar. Cada modulo tendra conocimiento solamente de la informacion que necesita saber. Esto hace que cada modulo quede de un tamanho mas pequeno y que sus cargas se hagan de manera mas rapida.

Bueno ya mucha hablada... Como se usan los modulos?

Bueno se tiene la aplicacion principal o shell y se tienen los distintos modulos.
Los modulos se empiezan a desarrollar como Aplicaciones Flex. Se crea una nueva aplicacion, se desarrolla, se prueba y se procede manualmente a hacer un cambio en el archivo MXML principal (ya que hasta el momento sino me equivoco Flex Builder no tiene una forma de como desarrollar un modulo desde el inicio)
Se tiene algo asi:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
<codigo comun y corriente.../>
<botones/>
<labels/>
<cromitos/>
<maripositas/>
<etc/>
</mx:Application>

Y se pasa a algo asi:
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" >
<codigo comun y corriente.../>
<botones/>
<labels/>
<cromitos/>
<maripositas/>
<etc/>
</mx:Module>

Se compila y se genera un archivo .swf. Este se copia al folder donde estara el ejecutable del shell o aplicacion principal y en el shell se anhade un tag de ModuleLoader, algo asi:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
<mx:ModuleLoader url="nombre_modulo_generado.swf"/>
<codigo comun y corriente.../>
<botones/>
<labels/>
<cromitos/>
<maripositas/>
<etc/>
</mx:Application>
Eso es todo.

Que ocurre en el realidad?

Bueno el modulo es compilado como un SWF. Eso es todo lo que ocurre... es un swf pero no uno que se pueda ejecutar si se da doble click.. tiene que ser llamado desde otra aplicacion en un module loader. El module loader se encarga de cargar el modulo en la aplicacion.

Como me puedo comunicar entre la aplicacion principal (shell) y un modulo??

Bueno, los modulos pueden implementar interfaces lo que permitiria definir una interfaz y de acuerdo a los servicios que esa interfaz exponga el shell podra llamar a esos metodos y el modulo los ejecuta.
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" implements="INTERFAZ">
codigo...
</mx:Module>

La otra opcion y que es la que yo prefiero... es a traves de eventos. Por que? Porque nos permiten bajar el acoplamiento entre modulo y shell.... Por que? Ya son muchas preguntas no...:) ? El utilizar eventos hace que el modulo despache o reciba eventos e igualmente que el shell reciba o despache eventos... eso lo hacen sin importarle si va a haber alguien que va a recibir o despachar ese evento, ellos sencillamente tienen la "buena voluntad" de querer comunicarse si alguien asi lo quiere. De esta forma se eliminan interfaces que se tengan que implementar o conocer mas de la cuenta los modulos, por ejemplo suponga que tiene 3 modulos distintos que se van a cargar en una misma aplicacion... cada uno implementa una interfaz distinta... saque cuentas todo lo que usted tiene que saber para poder comunicarse con el modulo. Usando eventos usted nada mas oye por un evento o despacha un evento.
Mas informacion sobre esto en este EXCELENTE LUGAR

Asi que si vas a iniciar una nueva aplicacion en Flex y vas a tener problemas de tamano talvez puedas considerar la idea de utilizar modulos para proveer a los usuarios una mejor experiencia.

Algunas notas:
  • Se pueden hacer Modulos desde Actionscript, sin embargo es mas sencillo hacerlo desde el MXML.
  • Se pueden cargar distintos modulos en tiempo de ejecucion, cambiando la propiedad url en el moduleloader e invocando el metodo loadModule() en el moduleloader.
  • Los modulos pueden ser descargados igualmente en tiempo de ejecucion con el metodo unloadModule() del module loader.
  • Existe algo conocido como un ModuleManager que se encarga de la carga de multiples modulos, es algo muy util ya que lo hace de una manera centralizada.

19 comentarios:

Juan Felipe dijo...

Excelente!! no hace falta mas explicacion, funciona perfectamente la carga de modulos, haría falta un post de como llamar modulos que sean movibles dentro de la aplicacion.

Anónimo dijo...

como podria llamar un modulo que este fuera de mi aplicacion???
por ejemplo yo ya tengo mi aplicacion en flex en mi servidor apache simplemente localhost, pero necesito un modulo de una aplicacion de felx con blazeds que esta en un servidor tomcat (localhost:8400) entonces como podria llamar ese modulo con ModuleLoader???? lo intente con ulr="http://localhost:8400/blazeds/app/modulo.swf" pero me manda el siguiente error:
Error #2048: Violación de la seguridad Sandbox: http://127.0.0.1/pyhv/administrador.swf no puede cargar datos desde http://localhost:8400/blazeds/test_chat/callcenter.swf.
podrian ayudarme con esto???

Ivan dijo...

@Anonimo
Intenta con un archivo crossdomain.xml localizado en el servidor donde esta el modulo.
Para mas y MUCHO mejor info acerca de esto http://www.moock.org/asdg/technotes/crossDomainPolicyFiles/

Ivan dijo...

@Juan Felipe
Gracias!! A que te refieres con que sean movibles? Saludos

Juan Felipe dijo...

Hola Ivan, hace mucho no entraba a tu blog y no me llegò ningùn correo avisandome que me habìas respondido.
Ahora que volvì a tomar este tema lleguè de nuevo a tu blog y aùn sigo con la inquietud, lo que deseo hacer es poder cargar multiples modulos en la shell pero que estos se puedan mover dentro de esta(Drag-Drop) y la otra duda es como hacer para el modulo que tiene el foco se sobreponga a los otros modulos abiertos?.

Ivan dijo...

Hola Juan, el Moduleloader que es donde se carga el modulo desciende de la clase VBox y por ende de podes utilizar la funcionalidad de drag-n-drop como con cualquier otro componente de flex. Esta tendrias que implementarla denro de tu contenedor de modulos, que puede ser un canvas o el Application mismo o dentro de tu module loader o incluso haciendo uso de una funcionalidad de la cual escribi en la segunda entrada sobre modulos y que tiene un link arriba en este mismo articulo.
Acerca de como hacer que el modulo actual tengo el foco, pues hay varias maneras. Es basicamente jugar con el indice del contenedor de los modulos y hacer que el modulo actual tenga dentro de los hijos el indice mas alto: contenedor.setChildIndex(module, contendor.getChildren().lenght -1);
Saludos

Novatilla dijo...

Yo estoy empezando ahora a usar esta aplicación soy bastante novata y quería saber a que conclusión se llega leyendo esta información, es decir cúal es la mejor forma de modular?? La opción una, la dos o la tres?? Contestadme cuanto antes please

Ivan dijo...

Hola Novatilla, la respuesta a tu pregunta va a depender de lo que quieras hacer. Si vas a tener multiples desarrolladores trabajando en distintos proyectos o modulos, puedes pensar en crear proyectos por aparte. Si vas a ser tu sola o con 1 o mas personas, pues te recomendaria que hicieras un solo proyecto y que de ahi pusieras tus modulos.
Saludos

Anónimo dijo...

En teoria es un proyecto a realizar en ppio yo sola, pero va a ser un poco ampli, no exageradamente, pero es bastante grande. En el caso que me indicas no se me realentizara demasiado la carga del programa???

Anónimo dijo...

El ultimo anonimo (soy Novatilla)

Anónimo dijo...

ya que estamos otra preguntilla, jajajjajaa.

Se puede combinar el introducir algun modulo dentro del mismo proyecto y desde este último llamar a modulos creados como proyectos??

(soy Novatilla)

Ivan dijo...

Si.. no hay problema en llamar modulos desde otros modulos (que tan facil de dar mantenimiento sera, no lo se). Los modulos son compilados en .swf separados y son cargados como archivos independientes, asi que no hay problema en cargar varios al mismo tiempo.

Ivan dijo...
Este comentario ha sido eliminado por el autor.
Zucarmex dijo...

Ivan:
Tengo una aplicacion X creado en Flex 2, lo migre a Flex 3 porque voy a crear otra aplicacion Y y quiero convertilos a modulos para cargarlos de una aplicacion Principal. Ya lo cargo sin problema, el detalle esta que me marca un error al momento de llamar una function de algunos de estos modulos "No destination with id 'x' is registered with any service." Observe que cuando cargo solo un Modulo ya sea el X o Y, funciona correctamente.

Espero poder contar con tu cuenta de correo para poder intercambiar conocimientos y experiencias. El mio es lega82@gmail.com

martin.odetti dijo...

Ivan, muy interesante la publicación. Ya había leido algo sobre módulos hace un tiempo pero nunca tan bien explicado.
Mi duda, el link que dejas con información adicional, allí hay una aplicación de ejemplo muy sencilla pero me parece que no se refiere a la opción por la que has optado tu (proyecto para cada uno de los módulos) sino que hace un proyecto para todos los modulos y la app... me podes confirmar esto?
En caso que sea cierto, tendrás algún ejemplo de tu implementación a mano?
Saludos

Ivan dijo...

@martin.odetti efectivamente Martin, el link provisto va a una aplicacion con varios modulos adentro de un solo proyecto. A mano no tengo ningun ejemplo con varios mas de un proyecto y modulos dentro de esos proyectos... pero es tan sencillo como crear proyectos nuevos y en cada proyecto agregar un componente de tipo "Module" el cual sera lo que cargaremos desde nuestra aplicacion principal. Cuando uso este enfoque, me gusta crear dentro de cada proyecto una applicacion que funciona como runner del modulo (osea me carga el modulo que estoy creando en mi proyecto) para poder probar mas facilmente y con mayor velocidad...
Gracias por la visita e intentare subir algunos proyectos de prueba posteriormente.

martin.odetti dijo...

Gracias Ivan por tu respuesta. Y en el caso de que varios módulos como también la app principal utilicen clases AS en común, debería cargarla en todos los módulos? Al momento de desarrollar cada uno individualmente entiendo que sí, pero después bastaría en que los cargue solo la app ppal no?

Ivan dijo...

@martin.odetti Lo mejor para evitar la duplicidad de codigo y un mejor mantenimiento (imaginate que es cambiar una clase y tener hacerlo en todos los proyectos...) crear una proyecto "Flex Library" el cual contendra tus clases AS3 y referencia tus proyectos a esa libreria, asi todos los proyectos comparten las mismas clases en un solo lugar... espero te sirva

poncho_rojas dijo...

hola solo para agradecer la publicacion, y para comentar un problema que tengo con los modulos y los remoteobject, la primera vez que se carga el modulo en la aplicacion principal funcionan bien pero la segunda vez se traba en el reloj. de atemano agradeceria su ayuda