Mostrando entradas con la etiqueta Actionscript3. Mostrar todas las entradas
Mostrando entradas con la etiqueta Actionscript3. Mostrar todas las entradas

lunes, 16 de noviembre de 2009

Pseudo Threads en Actionscript

Como mencione en un post anterior el Flash Player aunque internamente tiene un sistema de Threads o hilos que permite ejecutar multiples tareas al mismo tiempo, no provee a nosotros los desarrolladores la funcionalidad para utilizar threads nativamente. Esto hace por supuesto que aplicaciones nuestras donde se procesen muchos datos o con funciones o procesamiento muy pesado haga que nuestras aplicacion se congele o se pegue...
Como desarrolladores no tenemos otra forma de hacer que esto funcion sino es emulando la funcionalidad de los threads. Digo emulando porque no hay forma de hacerlo nativamente y se hace dividiendo el proceso pesado en multiples pedazos.
Acerca de esto se ha escrito en multiples lugares con contenido muy completo y excelentes soluciones a distintos niveles de complejidad.
Las librerias anteriores y muchas otras lo que hacen es partir el proceso grande en multiples pedazos que seran ejecutados en momentos distintos. Esto disminuye la carga de trabajo y hace que el proceso no se ejecute de un solo sin permitir al FP refrescarse y por lo tanto pegarse.
Sin embargo de las librerias anteriores, mi favorita es la de Grant Skinner, se llama "Chunker" pues parte los procesos en pedazos. Sin embargo basado en esa clase, decidi hacer unas modificaciones que aqui presento:


package com.grayscale.util.threads
{
import flash.display.Shape;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.utils.getTimer;

/**
* Evento despachado cuando se concluye el proceso.
*/
[Event (type="flash.events.Event", name="complete")]

/**
* Esta clase es una implementacion simple de un pseudo thread en AS3.
*

Esta basada en la clase de Grant Skinner aunque con algunas modificaciones.
* http://www.gskinner.com/libraries/Chunker.zip


*/
public class SimpleThread extends EventDispatcher
{
//Nos permite tener acceso al evento ENTER_FRAME que sera el que lleve el
//paso de cada cuando se ejecutaran nuestros procesos.
private var shape:Shape = new Shape();
//Estado del hilo
private var _paused:Boolean = false;
//Cada cuanto se ejecutara
private var _execTime:uint;
//Funcion a ejecutar
private var _func:Function;
//Argumentos a nuestra funcion. Es un array de elementos que pasariamos a nuestra funcion
private var _args:Array;

/**
* Constructor.
*
* @param execTime Cada cuanto se ejecutara nuestra funcion
* @param func funcion a ejecutar
* @param args parametro opcional con los valores a pasarse en la funcion
*/
public function SimpleThread(execTime:int, func:Function, args:Array=null)
{
_execTime = execTime;
_func = func;
_args = args;

pause = false;
}

/**
* Para el thread o lo arranca
*/
public function set pause(value:Boolean):void
{
_paused = value;
if(_paused) shape.removeEventListener(Event.ENTER_FRAME, run);
else shape.addEventListener(Event.ENTER_FRAME, run);
}


/**
* Metodo que ejecuta nuestra funcion
*/
private function run(event:Event):void
{
var initialTime:int = getTimer();//registra el tiempo donde inicia este iteracion
while(!_paused && (getTimer() < _execTime+initialTime ))//revisa si no hemos excedido la cantidad de tiempo del inicio
{
//llama nuestra funcion y esta tiene que regresar un valor booleano. Si este es falso detiene el thread sino continua.
var res:Boolean = _func.apply(this, _args) as Boolean
if(!res)//ya se termina de ejecutar nuestra funcion, pausamos el thread y despachamos evento avisando que se concluyo
{
dispatchEvent(new Event(Event.COMPLETE));
pause = true;
}
}
}
}
}


El unico requisito para esta clase, es que la funcion que queremos partir debe devolver un valor booleano: true si todavia hay data que procesar, false si ya termino de procesar la informacion.
A continuacion presento dos ejemplos, ambos cargan el mismo archivo(analytics de este blog); uno lo hace sin los pseudo-threads y otro con el pseudo-thread. Podran ver la diferencia como uno se pega y el otro no. Es un archivo grande (4mb) asi que tengan paciencia. Apenas se carga se activa el boton de "Start"
Notas: 1. Debe aparecer un spinner cuando se aprieta el boton de "start". 2. los controles de la pantalla deben ser accesbles mientras se procesan los datos.

Sin Thread.









Con Thread.







Al partir nuestra funcionalidad en multiples ejecuciones y no solo en una, ocupamos una forma de llegar a saber donde terminamos de procesar y desde donde debemos empezar. Para esto puedo sugerir el uso del patron Iterator. Este patron permite a una coleccion encapsular la manera en que se recorre la coleccion y guardar dentro de si misma cual fue el ultimo elemento procesado, sin tener que tener mantener un indice de la coleccion por fuera. El iterador se encarga de todo. Esto es bueno ya que al partir nuestro proceso ocupamos mantener una referencia al dato que estamos procesando sin tener que crear otras variables.
Aqui presento las siguientes clases para tener nuestro iterator.

Interfaz Base:


package com.grayscale.util.iterator
{
/**
* Esta interfaz define los metodos basicos que debera contener un iterador en nuestra coleccion
* @author Ivan Ramirez - ivan.ramirez@gmail.com
*/
public interface IIterator
{
/**
* Devuelve "true" si tenemos mas valores que recorrer dentro de nuestra coleccion
*/
function hasNext():Boolean;
/**
* Devuelve el proximo valor en nuestro iterador
* @returns el siguiente objeto en la coleccion.
*/
function next():*;
/**
* Nos permite reiniciar el recorrido de nuestra coleccion
*/
function reset():void;
}
}


Implementacion basica:


package com.grayscale.util.iterator
{
/**
* Implementacion basica de nuestro iterator para el manejo de arrays. Podemos implementar esta interfaz
* en otras clases para hacer iteradores con Strings o de XML, etc.
* @author Ivan Ramirez - ivan.ramirez@gmail.com
*/
public class ArrayIterator implements IIterator
{
//Coleccion base
private var collection:Array = new Array();
private var index:int;

public function ArrayIterator(values:Array)
{
collection = values
}

public function hasNext():Boolean
{
return index < collection.length;
}

public function next():*
{
return collection[index++];
}

public function reset():void
{
index = 0;
}

}
}


La ventaja de tener una interfaz definiendo el iterador, es que podemos crear nuestras propias implementaciones del iterador de acuerdo a nuestras necesidades.
Ya con nuestro iterador cargado con la coleccion de datos que tenemos que procesar, procedemos a utilizar nuestro thread.

El codigo de las aplicaciones de este ejemplo esta aqui.

domingo, 8 de noviembre de 2009

Eval function en Actionscript

Recordando mis tiempos de programador en Java, entre recientemente al site de una herramienta llamada Bean Shell que use hace varios a~nos... La herramienta sencillamente era un interprete de codigo en Java (y en otros lenguajes pues interpretaba Python y combinacion entre Python y Java), en tiempo de ejecucion, es decir sin tener que compilar un archivo .class y generar el bytecode para que sea ejecutado por el virtual machine...
Nosotros utilizabamos de esta funcionalidad para una herramienta administrativa, donde ejecutabamos scripts en un pseudolenguaje para consultar multiples y distintos servidores de informacion. Esto nos permitia tener multiples consultas dinamicas sin tener que recompilar la aplicacion principal o que los usuarios finales tuvieran que aprender a programar en algun lenguaje extra~no para ellos o usar SQL o algo por el estilo.
Viendo esto, me intereso encontrar algo parecido en Flash/Flex. La funcion Eval que esta disponible en multiples lenguajes, incluyendo Javascript, tiene una funcionalidad algo parecida, nos recibe de parametro una cadena de caracteres donde se tiene codigo que sera interpretado (y ejecutado) por esa funcion. En Flash era comun encontrar esta funcion (o algo parecido) en ActionScript 2 pero fue eliminada en la version 3.
Sin embargo haciendo uso del trabajo hecho en Tamarin Project de Mozilla, donde se tuvo acceso a parte del codigo del AVM2 osea el nuevo Action Virtual Machine que corre en el Flash Player 9.x y mas versiones mas recientes. Tamarin nos permite ver como funciona internamente el virtual machine, como se ejecuta el codigo, como se procesa, etc. Es algo bastante interesante y avanzado a la vez y permitiria la optimizacion de aplicaciones en la plataforma flash, incluso hay proyectos donde se promueve el uso de AOP o aplicaciones que convierten codigo de C# o Java a codigo ejecutable por el flash player... todo con la informacion que provee este proyecto; pero bueno, esto seran tema de otros posts.
Como decia anteriormente - antes de desviarme diciendo cuan impresionante es el proyecto - haciendo uso del proyecto Tamarin, "Metal Hurlant" (creador de multiples librerias open source como AS3Cripto) creo una libreria que se comporta como la funcion Eval, interpretando codigo de Actionscript en tiempo de ejecucion. Pueden acceder a un demo desde aqui.
Solo puedo decir que este es un trabajo brillante y que tomando las medidas de seguridad pertinentes (para que no se inyecte codigo maligno en tiempo de ejecucion entre otras) y no abusando de la misma por cuestiones de rendimiento (este proceso demanda algo de recursos) puede llegar a ser de mucha utilidad. La creacion de aplicaciones mas dinamicas, mas inteligentes en tiempo de ejecucion, etc. nos permitira ofrecer mejores aplicaciones a nuestros usuarios y a la vez creando aplicaciones menos complejas y flexibles... nuevamente sin abusar de esto...
Disfruten...

sábado, 16 de mayo de 2009

La importancia del Feedback y las pruebas

Recientemente escribi sobre la importancia de recibir feedback en nuestra profesion de infomaticos.
No voy a extenderme mucho al tema, mucho ya lo dije en el post anterior sin embargo hoy quiero hablar un poco sobre la importancia de hacer pruebas y como se relaciona con el feedback.
Veran, las pruebas que hagamos (me gusta usar Fluint para flex y ultimamente estoy probando con Flex Unit 4 - version alpha en este momento) son una forma de feedback para nuestras aplicaciones y para nosotros mismos.
Cuando hagamos cambios grandes o refactoty en nuestro codigo y ejecutemos las pruebas que hayamos realizado sabremos sabremos si los cambios realizados por nosotros han afectado el comportamiento correcto de nuestra aplicacion. Eso tambien es feedback.
Cuando durante el fin de seman un companero de trabajo cambie algo en su codigo y lleguemos el lunes y nada funcione... podemos correr nuestras pruebas y darnos cuenta que es lo que fallo y encontrar la solucion de forma mas rapida (ademas de poder culparlo :o) ). Eso tambien es feedback.
Soy partidario del TDD (Test Driven Development) y reconozco la importancia de las pruebas, como forma de feedback y de asegurar una mejor calidad en mi desarrollo, pero tambien reconozco que a veces el tiempo no alcanza o el cliente no entiende la importancia de estas pruebas. Por eso es necesario ser prudente a la hora de escoger que probar y que no. Como decia una abuela mia "Ni mucho que queme al santo ni tan poco que no lo alumbre". Repito Nada malo con probar, pero tambien ser concientes de nuestros tiempos ya que no siempre tendremos el suficiente tiempo para probar todo.
Mis secciones favoritas para probar, son las que estan en constante cambio y que son criticas:
logica de negocio, acceso a datos (servicios remotos o a base de datos en AIR).
Componentes y vistas me gusta probarlos separados, aislarlos en una aplicacion aparte y probar su funcionamientos, estilos, etc. Eso me provee Feedback. Me gusta aislar las vistas que haga y sus interacciones basicas y proveerlas a quien sea que este a cargo de esa vista, sea el disenador grafico o el encargado del proyecto o cliente del mismo. Que jueguen con la vista por separado en lugar de tener que cargar toda la aplicacion y gastar mas tiempo en proveerme feedback, eso lo pueden hacer en otro momento. Existen herramientas para probar la interfaz como Flex Monkey y Selenium que permite grabar interacciones y ejecutarlas automaticamente. Tambien son validas.
Flex Unit 4 Alpha viene con muchas mejoras y cosas nuevas, verdaderamente lo recomiendo! Aqui mas info

Creando APIs en Actionscript

Recientemente he tenido en mis ratos libres la mania de bajar API's para Actionscript 3 de diferentes servicios que hay por ahi, como Digg, Twitter, Facebook, Salesforce, etc para probarlos, jugar con ellos y hacer alguna aplicacion sencilla con ellos aunque nunca vaya a ser utilizada.
Esto me divierte en realidad y mas importante me ayuda a ver codigo de otras personas, maneras de pensar y de implementar. Creo que es una experiencia enriquecedora. Muchos desarrolladores piensan que ver el codigo de otros es malo, es bajo, es denigrante. Honestamente creo que no! Primero yo escojo de quien veo el codigo y la mayoria de personas que hacen estos APIs son mucho mas competentes que yo! Ademas es una manera de aprender de mejorar y de desarollar mejor. Un claro ejemplo es el acceso que tenemos al framework de Flex. Si algo puedo decir de mi actual trabajo y de los dos maestros de Flex con los que trabajo es que se conocen ese framework de arriba a abajo. De ahi que puedan hacer las cosas que hacen.
Bueno siguiendo con mi fascinacion tan geek de las ultimas semanas, me he puesto a pensar en que requisitos son necesarios para construir un API en ActionScript.

Primero pensemos para que necesitamos realizar un API. Un API es utilizado para ofrecer una serie de servicios que puedan ser invocados por otras aplicaciones con el fin de ejecutar una accion. No es lo mismo que un framework. El API debe ser claro, sencillo y definido. Mejor si esta documentado. Mejor aun si tiene ejemplos. El API debe ser facil de usar, intuitivo y tener todo lo que nuestros futuros clientes vayan a ocupar para interactuar con nuestra plataforma. Incluyendo objetos definidos por nosotros mapeando la informacion de nuestros servicios.

Segundo analicemos la forma en que vamos a entregar nuestra informacion. Aqui desde dos perspectivas distintas:
a) Como se accedera a la informacion que se quiere facilitar (ya pensando en algo mas "fisico"). Esto incluye como se haran los llamados a nuestros servicios: REST Services? Web Services? Remoting? External Calls (como tiene el API de Facebook)? Todo esto debe ser transparente para el usuario de nuestro API. Si acaso lo mas es la opcion de escoger que tipo de canal usar para comunicarse con nuestros servicios, pero la implementacion y demas no debe ser de importancia para el.
b) La forma en que entregaremos la informacion recolectada de nuestros servicios. Si recibimos XML, no podemos pasarle simplemente XML al cliente y dejar que el piense que va a hacer con esa informacion (tecnicamente si podemos, pero no debemos :) ). La creacion de objetos que mapeen nuestro servicio hace que nuestro API sea mas facil de usar.

Tercero consideremos en la naturaleza Asincronima de nuestra plataforma. Cuando hacemos una invocacion a un servicio externo sea por WebService, Remoting o simple REST Services no sabemos cuando vamos a recibir la informacion de vuelta. Esto hace que nuestros APIs no sean tan facil de usar cuando invocamos servicios remotos como hacer:

var misUsuarios:ArrayCollection = miAPI.cargarUsuarios(); //ESTO NO FUNCIONA!!

El metodo cargarUsuarios puede demorar un tiempo (incluso has segundos) en devolvernos esta informacion, asi que la asignacion a mis usuarios no va a ser correcta.

Soluciones:
a) Una forma de hacerlo es pasarle al metodo el arraycollection que queremos cargar y cuando se reciba la informacion se carguen los resultados en esa variable pasada como parametro. Recordemos que nuestros objetos en AS3 se pasan por referencia y no por valor, asi que los cambios que hagamos al objeto pasado por parametro, se reflejaran en nuestro objeto original (a menos que se haga una copia del mismo. En lo personal la siento como valida, pero no es aplicable en todas las ocasiones. A veces ocupamos darnos cuenta cuando algo fue procesado y eso se logra a traves de eventos.

b) Otra forma de hacerlo es atraves del uso de eventos. Cuando nuestra funcion recibe el resultado, esta manda un evento indicando que fue recibido. Anadiendo un event listener a ese evento, podemos procesar esa informacion desde donde queramos. Algo importante es aislar cada llamada o cada proceso de datos por aparte, para que cada llamada despache un solo evento, en lugar de estar llamando handlers de otras locaciones por eventos que se invocan con otros propositos. Por supuesto es importante recordar el removeEventListener una vez que es ejecutado un event handler que no se ocupa tener mas y poner las referencias como weak, pero igual si no se aislan las llamadas pueden crear conflictos.

Esta practica es seguida en el API para Facebook, a continuacion parte del codigo de uno de sus ejemplos:

var call:AddComment = new AddComment(story_id, body);
call.addEventListener(FacebookEvent.COMPLETE, onAddComment);
facebook.post(call);


onAddComment Va a encargarse de utilizar la informacion recibida como se quiera, puesto que ya esta informacion viene procesada y convertida en el tipo de dato que se quiere todo esto cuando se despache el evento de Complete.

c) Otra forma de hacerlo, es aislando el resultado de la funcion invocada y que ella se encargue de manejar el resultado. Esto es como lo que hacen con el API de Digg . Esto es delegar la llamada y el procesamienta del resultado y posterior conversion a objetos normales a un objeto que es devuelto por nuestra funcion invocada. Por ejemplo:

Del API de DIGG

public static function getUser(user:*):UserResponse
{
var request:URLRequest = new URLRequest(getUserURL(user));
return load(request, new UserResponse()) as UserResponse;
}


Esta clase devuelve un UserResponse, que hereda de la clase Response que a su vez es la que hace el llamado al servicio y delega en UserResponse el procesamiento y conversion del resultado en un objeto utilizable en la aplicacion y no simple XML.

Como ven, enfoques distintos, pero el mismo principio aislar la invocacion para que pueda ser tratada como una llamada distinta.

Espero esto pueda ayudar a otras personas que tengan que crear APIs para servicios externos para AS3 o que anden buscando como ingresar a esto de APIs y servicios externos y que puedan de este humilde texto encontrar algo que les ayude
Disfruten...

sábado, 28 de junio de 2008

Reflection en Actionscript - Parte 2 - A

Esta es la segunda parte del tutorial sobre reflection. Este esta mas orientado a aplicaciones de la vida real que le podemos dar a reflection. Voy a dividir la parte en dos por lo largo que toman la explicacion de los ejemplos.

Ejemplo 1:

Serializador


Problema:

Se ocupa serializar los objetos de una aplicacion en XML para ser enviados al servidor con sus respectivos valores, nombre de los campos y tipos de los mismos.

No se desean modificar las clases ya construidas.

Solucion:

Para empezar nuestro ejemplo vamos a tomar las siguientes clases de Actionscript. Son tres clases simples describiendo tres abstracciones distintas y sin relacion. Estas clases seran las que tendremos que serializar en un XML. Como no se quieren alterar las clases, se crea una clase utilitaria que se encargara de realizar esta serializacion.

A continuacion la descripcion de las clases:
package serializador.classes
{
public class Perro
{

public var nombre:String;
public var raza:String;
public var peso:Number;
public var color:String;

public function ladrar():void
{
trace("guaw guaw!");
}

}
}
package serializador.classes
{
public class Carro
{

public var marca:String;
public var fabricante:String;
public var anho:Number;
public var motor:Number;

}
}

package serializador.classes
{
public class Persona
{

public var nombre:String;
public var apellidos:String;
public var edad:Number;
public var sexo:String;
public var altura:Number;

}
}

Lo dificil de esta solucion (sin usar reflection) es que se tendria que crear un serializador para cada una de clases (ya que entre ellas no tienen relacion) para poder acceder a cada una de las variables o metodos que se tenga en cada clase (ya que todo esto es desconocido).

Pero con reflection las cosas cambias ya que en tiempo de ejecucion puedo averiguar los metodos, variables y accesors que tiene una clase. Con esto hacemos un metodo que reciba de parametro un objeto y utilizando describeType nos devuelve un XML con la descripcion completa de la clase y lo mejor es que podemos aplicar la solucion a cualquier clase que se quiera sin tener que hacer nada nuevo.

Masomenos algo asi es lo que nos devuelve la funcion describeType:


<type name="Perro" base="Object" isdynamic="false" isfinal="false" isstatic="false">
 <extendsclass type="Object">
<variable name="peso" type="Number">
<method name="ladrar" declaredby="Perro" returntype="void">
<variable name="color" type="String">
<variable name="raza" type="String">
<variable name="nombre" type="String">
</variable>
Esta es la funcion que hacemos:


public static function serialize( item:Object ):XML
{
var descripcion:XML = describeType(item); // invoamos a funcion para describir la funcion. Nos retorna un XML
var root:XML = new XML("<Object type=\""+ descripcion.@name +"\"/>"); //Creamos un nuevo XML que devolveremos posteriormente.

for each (var variable:XML in descripcion.variable){//del XML navegamos por todos los elementos dentro del nodo de Variables

// Creamos un nuevo nodo, su nombre es el de la variable (cargada del XML), el tipo se carga igualmente de la descripcion que encontramos
// en el XML que genera describeType y el valor lo hacemos usando Introspeccion en el objeto pasado por parametro invocando la
// variable por medio de objeto[ variable ]
var node:String = "<property name=\"" + variable.@name + "\" type=\""+ variable.@type + "\">" + item[variable.@name] + "</property>";

root.appendChild(node);//agrega al nuevo XML
}

return root;//retorna nuevo XML con nuestra serializacion
}


Este es el resultado de nuestra funcion pasando de parametro instancias de las clases Carro, Perro y Persona (en ese orden):
<Object type="serializador.classes::Carro">
<property name="fabricante" type="String">Nissan</property>
<property name="marca" type="String">Maxima</property>
<property name="anho" type="Number">2003</property>
<property name="motor" type="Number">1300</property>
</Object>

<Object type="serializador.classes::Perro">
<property name="color" type="String">Cafe</property>
<property name="peso" type="Number">25</property>
<property name="raza" type="String">Bulldog</property>
<property name="nombre" type="String">Bruno</property>
</Object>

<Object type="serializador.classes::Persona">
<property name="altura" type="Number">1.6</property>
<property name="edad" type="Number">38</property>
<property name="apellidos" type="String">Muller</property>
<property name="sexo" type="String">Masculino</property>
<property name="nombre" type="String">Steven</property>
</Object>
Como dije anteriormente la ventaja de esta solucion es que podemos usar cuantos objetos queramos de distintas clases sin tener que alterar nada en nuestra funcion de serializar.

lunes, 23 de junio de 2008

Reflection en Actionscript - Parte 1

Comienzo una serie de dos temas acerca de reflection en Actionscript y Flex.
Cuando hablo de Reflection no me refiero al efecto visual que se genera cuando una imagen o parte de la misma es reflejada en otra area.

El reflection al que me refiero es a la facultad de un programa para que en tiempo de ejecucion pueda examinar su estructura y la de su ambiente y poder modificar lo que hace dependiendo de lo que encuentre. Es una tecnica presente en lenguajes de programacion recientes.

En Java por ejemplo, la funcionalidad de reflection se encuentra dentro del paquete java.lang.reflection, de donde se encuentran toda una serie de clases y metodos para poder examinar la estructura clases y tomar desiciones basados en esa informacion. En Actionscript esta funcionalidad esta basicamente incluida en cuatro funciones que veremos mas adelante.

Debo admitir que el uso de reflection en nuestras aplicaciones no es algo de todos los dias, sin embargo las veces que es utilizada se presenta como una solucion muy elegante para ciertos problemas.

Un poco de mi experiencia personal con reflection:

Mi primer contacto con reflection fue hace como unos 5 a~nos. Ingresaba a laborar en una pequen~a empresa en Miami. No habian muchos empleados aunque si muchos clientes y sobre todo un sistema muy robusto y muy bien disenado que cumplia con todas las necesidades y mas de la empresa. El programador lider era un excelente arquitecto. Tenian un sistema que se conectaba a 6 distintos proveedores - con conectividad e interaccion distinta en cada uno - a traves de un framework inventado en la empresa, que con el uso de interfaces y de reflection lograba en tiempo de ejecucion descargar y cargar las librerias de conectividad e interaccion para los distintos proveedores y realizar la funcionalidad necesaria. Todo era configurado desde un XML y si se necesitaba agregar un nuevo proveedor, se creaba la nueva libreria (.jar en ese caso) y se agregaba en el XML. Reflection hacia toda la magia de la carga de las clases y de encajarlo todo dentro de la aplicacion sin tener que compilarla en ningun momento.

Luego pase a aplicar reflection dentro de aplicaciones Web y de escritorio. Cada vez era mas sencillo utilizar el reflection en las aplicaciones y agregar funcionalidad en tiempo de ejecucion sin tener que compilar mi aplicacion nuevamente. Con la ayuda de un gran libro logre ir aprovechando mejor la herramienta, hasta que migrando de Java a Flex, pude descubrir la funcionalidad que brinda Actionscript y logre anadirla en algunas aplicaciones.

Manos a la obra:

Actionscript provee en el paquete flash.utils una serie de funciones para manejar reflection:

describeType: Recibe un objeto como parametro y devuelve un XML con la descripcion de la clase de la cual es el objeto.

Supongamos que tenemos la siguiente clase:



   1:  package 

   2:  {

   3:      public class Perro

   4:      {

   5:          

   6:          public var nombre:String;

   7:          public var raza:String;

   8:          public var peso:Number;

   9:          public var color:String;

  10:   

  11:          public function ladrar():void

  12:          {

  13:              trace("GUAW GUAW");

  14:          }

  15:   

  16:      }

  17:  }





Aplicamos describe type:

   1:  var bulldog:Perro = new Perro();

   2:  describeType(bulldog)



Salida:




   1:   

   2:  <type name="Perro" base="Object" isdynamic="false" isfinal="false" isstatic="false">

   3:   <extendsclass type="Object">

   4:   <variable name="peso" type="Number">

   5:   <method name="ladrar" declaredby="Perro" returntype="void">

   6:   <variable name="color" type="String">

   7:   <variable name="raza" type="String">

   8:   <variable name="nombre" type="String">

   9:  </variable>



Una vez que tengamos toda la informacion de la clase variables, accessors, metodos, super clase, etc; podremos ser capaces de acceder a la informacion o invocar los metodos que necesitemos.

getDefinitionByName: Recibe un String como parametro con el nombre completo de una clase y devuelve (si existe) un objeto del tipo clase asignada por parametro que puede ser casteada posteriormente como un Class.

Utilizando la misma clase Perro del ejemplo anterior:




   1:  var clazz:Class = getDefinitionByName("Perro") as Class; //Puede ser getDefinitionByName("paquete.de.la.clase.Perro")

   2:  var miPerro:Object = new clazz();



Se crea una clase del tipo pasado en el String de parametro. Pueden ser clases del framework de Flex o de API de Actionscript o customizadas, como este caso. Solo se ocupa que se contenga la ruta completa (incluyendo el paquete)

El unico problema que tiene esto es que:
  • El compilador, para reducir el tamano de los swfs no incluye en el swf final los archivos de clases que no son utilizadas en algun momento desde nuestra aplicacion. Esto quiere decir que si en ningun otro lado de la aplicacion se crea una nueva instancia de la clase Perro, esta no sera incluida dentro del SWF final y el uso de reflection generara error algo como "ReferenceError: Error #1065: Variable is not defined.". Esto le quita un poco la funcionalidad al reflection ya que te limita a clases que esten instanciadas dentro de la aplicacion. Sin embargo vamos a ver en el siguiente post como podemos crear aplicaciones utilizando reflection a las que podremos anadir funcionalidad en tiempo de ejecucion y sin tener que compilar la aplicacion principal.

getQualifiedClassName
: Recibe un objeto como parametro y devuelve un string con el nombre completo de la clase del cual es tipo el objeto.




   1:  var clazz:Class = getDefinitionByName("Perro") as Class; //Puede ser getDefinitionByName("paquete.de.la.clase.Perro")

   2:  var miPerro:Object = new clazz();

   3:   

   4:  trace( "Objeto Creado de tipo: " + getQualifiedClassName(object) );



Salida:

Objeto Creado de tipo: Perro

getQualifiedSuperclassName: Recibe un objeto como parametro y devuelve un string con el nombre completo de la super clase del cual es tipo el objeto.

Es parecido al ejemplo anterior.

Esto es todo por ahora, en el siguiente post presentare dos aplicaciones del mundo real que se le puede dar al reflection desde actionscript, uno un sencillo serializador de clases a XML y el otro una aplicacion que carga desde un XML distintos proveedores en tiempo de ejecucion y que permite anadir nuevos proveedores sin tener que compilar la aplicacion principal.

miércoles, 23 de enero de 2008

Eventos en Flex

Los eventos en AS3 son a mi parecer la clave que permite crear RIAs interactivas, agradables y completas.
Un evento es generado la mayor cantidad de veces por la interaccion del usuario (tambien conocido como gestos) con el sistema (un boton, un campo de texto, cualquier interaccion que se haga por mouse o teclado). Algunos eventos son generados por el sistema automaticamente.
Los eventos son maneras eficaces para realizar aplicaciones con un acoplamiento bajo, esto debido a que la comunicacion se da a traves de ellos, un componente dispara un evento y solo se preocupa por eso. Si algun otro componente o contenedor ocupa de ese componente recibira el evento y procedera a realizar la funcionalidad que requiera con ese evento y la informacion que el contenga, sin conocer absolutamente nada del componente ni siquiera saber quien lo envio.
Otra cosa muy interesante de los eventos es que uno puede crear sus propios eventos customizados, descendiendo de la clase Event. Aqui un ejemplo:

package{
import flash.events.Event;

public class miEvento extends Event{
public static const AGREGAR_PERSONA:String = "AgregarPersona";

public var nombre:String;
public var apellidos:String;
public var action:String;

public function miEvento(action:String,nombre:String,apellidos:String,bubbles:Boolean=false,cancelable:Boolean=false){
super(action,bubbles, cancelable);
this.action = action;
this.nombre = nombre;
this.apellidos = apellidos;
}

override public function clone():Event{
return new EventoEvent(action, nombre, apellidos, evento);
}
}
}

En este ejemplo simple y chapucero, se pasan dos variables, nombre y apellidos que seran seteadas por el disparador del evento y que podran ser recolectadas por cualquier componente O o contenedor que este interesado en recibirlo. Nota, se pueden incluir clases para encapsular la informacion o incluso clases de cualquier tipo que se hayan creado.

Existen 3 fases de propagacion, durante los eventos:

1. Capturing: De arriba a abajo.
Un componente dispara un evento y Flex se encargara de buscar desde el contenedor mas afuera de ese objeto (generalmente el application) hasta el contenedor directo del componente mismo. Cada vez que va cambiando de componente, la variable currentTarget del event va cambiando. Cabe aclarar que los eventos tienen dos propiedades importantes: target y currentTarget.
El target en los eventos de AS3 se refiere al que emitio o disparo el evento y el currentTarget se refiere al nodo u objeto que se esta chequeando por EventListeners. No se, talvez a los de Adobe no les dio mas para ponerle otros nombres pues es algo confuso... Con estas dos propiedades podemos averiguar quien hizo quien y quien va a encargarse de...
Ejemplo:
Tenemos esto:
Application -->
Canvas -->
Button

El Capturing buscaria por event listeners en este orden: Application, Canvas.
Si existieran mas capas arriba del button, pues se revisaria en cada una de estas si tenian event handlers en cada una de ellos. El default del capturing es false.

2. Targeting:

Es el mas sencillo, solo se revisa por event listeners dentro del componente que dispara el evento, como cuando se define en el boton la propiedad click="funcion()". Esto ademas indica que el target y currentTarget son los mismos.

3. Bubbling: De abajo para arriba.
Es el contrario al Capturing
Ejemplo:
Tenemos esto:
Application -->
Canvas -->
Button

El Bubbling buscaria por event listeners en este orden: Canvas, Application.
Flex buscara event listeners hasta que se le permita. Puede ser que llegue hasta al application o puede ser que se le pare en el contenedor siguiente al componente que despacha el evento, en este caso el Canvas. El default del bubbling es false.

Tanto para capturing como para bubbling, es posible el parar la propagacion desde un listener que se quiera, con stopPropagation() y stopImmediatePropagation().

Lo mejor en la propagacion es ver cual es la que mejor sirve para su aplicacion para optimizar tiempos. Por ejemplo si solo ocupa targeting, deje bubbling y capturing en false. Si ocupa capturar un evento solamente desde el contendor del componente, pues user bubbling. Si lo ocupa hacer desde mas afuera, pues hagalo con capturing. Si ocupa capturar el evento por alguien mas que el target y no usen bubbling o targetting no se va a poder capturar los eventos lanzados a no ser que agregue el listener al contenedor, pero no siempre se puede hacer.

Esto es algo muy basico, pero necesario y que hay que estar revisando casi todos los dias para comprenderlo mejor. Cuando se dominen los eventos en Flex, estoy seguro que tendra un 80% de lo escencial dominado.

miércoles, 16 de enero de 2008

Patron de Comando en Actionscript

Patron de Comando:

Es un patron de comportamiento, que nos permite eliminar el acoplamiento entre objetos.
Ejm:

Objeto A ocupa invocar un servicio del Objeto B. Generalmente se hace a traves de la invocacion directa del servicio ObjetoB.method();
Eso genera un acoplamiento alto, debido a que de esa forma, Objeto A ocupa saber los metodos del Objeto B y si los mismos se llegaran a cambiar alteraria (nombre, firma, etc) la compilacion del Objeto A daria error y habria que modificarlo ahi o en cualquier otro objeto que invoque ese servicio.
Para evitar esto, se procede a crear una clase intermedia (el command), que sera la que conocera todo acerca de la clase B y la cual sera invocada por la Clase A, para ejecutar la tarea.
El Command no se preocupa por la respuesta que se genera o a quien debera retornarla, solo ejecutarla.
Esto se hace a traves de la definicion de una Interfaz con el metodo execute (o ejecutarAccion o ejecutar o como se quiera, pero que todos los comandos implementen ese metodo)

Ejemplos:

Sin Command:

ObjetoA -- invoca metodo --> ObjetoB

Con Command:

ObjetoA -- invoca execute --> Command -- invokes metodo --> ObjetoB

La ejecucion de la accion es desconocida por el que la inicio y eso permite que no exista acoplamiento entre componentes ni objetos y que al mismo tiempo las modificaciones que se hagan mas adelante, no generen errores en clases o componentes que ya estaban listos.
Esto es basicamente lo que sucede con Cairngorm y los comandos que se implementan dentro del framework.

Ejemplo de Codigo (la sintaxis no esta chequeada contra el compilador ni con Cairngorm):

Interface Command

package com.ejemplos.patrones.ejemplo{
public interface ICommand{
public function ejecutar():void; //No devuelve ningun tipo de valor
}
}

Clase CommandoLlamarClaseB

package com.ejemplos.patrones.ejemplo{
public class CommandoLlamarClaseB implements ICommand{

public function ejecutar:void{
var claseB:ClassB = new ClassB();
claseB.llamadoEnClaseB();
}

}
}


Clase A

package com.ejemplos.patrones.ejemplo{
public class ClassB{
public function llamarClaseB():void{
var comando:ICommand = new CommandoLlamarClaseB();
comando.ejecutar();
}
}
}

Clase B

package com.ejemplos.patrones.ejemplo{
public class ClassB{
public function llamadoEnClaseB():void{
trace("Desde Clase B");
}
}
}

viernes, 14 de diciembre de 2007

Interaccion de Flex con datos externos

Empiezo este tema hablando lo negativo... Flex no tiene acceso directo a bases de datos.

Y la respuesta inicial de muchos:

Como???? Entonces de que me va a servir a mi o a mis clientes, si lo más importante de sus aplicaciones es la información, que generalmente se guarda en una Base de Datos??? Mejor me quedo con mi lenguaje web que me permite conectarme con la base de datos desde la misma página que esta cargando el usuario (por que para muchos esa es la mejor manera de hacerlo...)
Si Flex no tiene acceso directo a base de datos, como entonces puedo acceder a mi informacion?

Funcionalidad Flex

Flex fue hecho para funcionar como una interfaz de interacción de un usuario con un determinado sistema. Razón suficiente para preocuparse en brindarle al programador los recursos necesarios para realizar una experiencia totalmente distinta a la de sitios con el tradicional HTML.

Ahora, lógicamente que para interactuar con un sistema, se debe de tratar con datos. La datos es lo más importante en un sistema y de que sirve interactuar con alguien si no le responde a uno nada...? Se hace necesario el uso de un Backend que se encargue de manipular la informacion y transmitirla a la aplicación en Flex.

Ocupo programar en algún lenguaje especial para que funcion esto?

El acceso a datos desde Flex es totalmente independiente del lenguaje en que se programe en el backend. Puede hacerse en Java, Cold Fusion, PHP, Ruby, .NEt, lo que usted se imagine ya que provee varias maneras distintas de accesar la información.

Métodos Básicos

HTTPService: Permite acceder a la un archivo "hosteado" en un servidor. Se puede acceder a información en el mismo servidor o en otro. Esto permite realizar peticiones tipo REST a un servidor, ya que permite el envio de Parametros en el request, pero además permite la manipulación del resultado que esa página produzca... todo por medio de llamadas asincrónimas. Permite no solo la invocación a HTML plano, sino tambien a archivos generados dinámicamente en PHP, JSP, ASP, etc, devolviendo estos el resultado en la forma en que quieran y que el programador pueda interpretar más facilmente. Lo general es devolver el resultado en formato XML. El Actionscript 3 provee una forma muuuuuuy sencilla de manipular el XML (E4X), pero eso se merece otro post aparte

Ejemplo:

<mx:httpservice id="httpLogin" destination="http://127.0.0.1/login.php" result="resultHandler(event)" fault="faultHandler(event)">

</mx:httpservice>

Esto es:
id ==> Nombre con que se manejara el servicio en el MXML y en el Actionscript
destination ==> Direccion del recurso que se quiere accesar. Puede ser incluso un archivo XML directamente
result ==> nombre de la función en actionscript que se encargara de manipular la información que devolver el script login.php (en este ejemplo)
fault ==> nombre de la función en actionscript que se encargara en caso de que el llamado falle, de hacer lo que el programador desee (mostrar mensaje o lo que sea)

Todavía no hemos invocado a la pagina, solo tenemos la definicion del servicio... Esta definicion se puede hacer tambien por actionscript.

Continuamos con el ejemplo:

<mx:script>
<!--[CDATA[
//Funcion que invocara el servicio
public function invocarLogin():void {
//Uso de Token
var call:AsyncToken = MyService.send();
//Hasta aqui se hace la invocacion a la página
call.marker = "login";
}
//Manejo de resultado
private function resultHandler(event:ResultEvent):void {
var call:object = event.token
if (call.marker == "login") {
//manipular informacion a través de: event.result;
trace(event.result) //imprime el resultado enviao por la pagina
}
}
//Manejo en caso de falla
private function faultHandler(event:FaultEvent):void {
Alert.show(event.fault);
}
]]-->
</mx:script>

<mx:remoteobject id="ro_tasklist" destination="TasklistService" result="onROResult(event)" fault="onROFault(event)" showbusycursor="true">
</mx:remoteobject>
Precaución: Al igual que con Ajax y con otras aplicaciones que se ejecutan en el cliente, el acceso a recursos que se encuentren en un servidor distinto al en que se descarga la aplicación flex, esta prohibido. Las reglas para acceso a recursos de un proveedor externo están restringidos por motivos de seguridad. Sin embargo una manera de evitar este problema, es utilizando un "proxy". Por ejemplo (un poco cavernicola...) tengo mi aplicacion flex en miserver.com que lee los feeds de un RSS localizado en CNN.com, puedo crear un archivo en mi servidor (el proxy) php, jsp, asp, o lo que quiera que se encargue de leer el contenido en CNN.com y se lo devuelva a mi flex...

RemoteObject: Mi favorito....este es definitivamentelo que hizo que me enamorara del Flex. Es totalmente RPC (remote procedure calls). Funciona en palabras simples asi:
Se tiene un backend creado en X lenguaje, en servidor se tiene una configuración especial para ese lenguaje y el Flex a través de esa configuración puede acceder a los métodos de las clases definidas en la configuración, pasando objetos como parametros y recibiendo objetos como resultados (literalmente objetos, nada de XML ni eso). Esto a través del protocolo AMF, que lo que haces serializar los objetos y mandarlos sea al servidor o al cliente para su respectiva deserialiazación y manipulación. El AMF serializa estos objetos en formato binario, osea es mucho más rápido (mucho más y sino lo cree, corra este ejemplo de James Ward: http://www.jamesward.org/blazebench/) y los manda encapsulados y comprimidos en un metodo POST por http (no teniendo problemas con proxies ni firewalls). No tienen que ser solamente un objeto a la vez, puede enviar colecciones de objetos (Arrays, listas, etc)
Algo bueno es que acaba de ser abierto por Adobe, lo que permitirá que otras personas intenten mejorarlo o darle nuevas aplicaciones...
RemoteObject es asincronimo tambien y hay que manejar tambien el Resultado o la Falla como en el HTTP Service.
Inicialmente funcionaban solamente con Java y ColdFusion (adobe provee librerias para configurar los servicios) sin embargo ya existen las librerias necesarias para configurar en otros lenguajes, ejemplo PHP --> amfphp, Ruby --> rubyamf, WEBORB, AMF.NET --> .NET entre otros.
Ejemplo:

Suponga que tenga una aplicación que tiene un metodo para crear usuarios llamado creaUsuario y que recibe un parametro de tipo Usuario (una clase) con nombre, username y password.

En actionscript, define su clase llamada Usuario también, con las propiedades nombre, username y password, esta clase es un mapeo de la clase Usuario en el server.
Algo asi:

package com.sitio.clases
{
//RemoteClass especifica a que clase en el server va a asemejarse esta. Apunta al mismo folder donde se encuentra la clase pero en el server.
[RemoteClass (alias="com.sitio.clases.Usuario")]
public class Usuario
{
public var nombre:String;
public var username:String;
public var password:String;
}
}

En el MXML (o en Actionscript tambien) se definira el RemoteObject

<mx:remoteobject id="ro_usuario" destination="ServicioEnServidor" result="resultHandler(event)" fault="faultHandler(event)" showbusycursor="true">
</mx:remoteobject>

Esto es:
id ==> Nombre con que se manejara el servicio en el MXML y en el Actionscript
destination ==> Nombre del Servicio o Clase que se configuro en el servidor para ser accesado por el Flex
result ==> nombre de la función en actionscript que se encargara de manipular la información que devolvera el método
fault ==> nombre de la función en actionscript que se encargara en caso de que el llamado falle, de hacer lo que el programador desee (mostrar mensaje o lo que sea)
showBusyCursor ==> Muestra un cursor con un relojito, mientras se hace el request...mas estetico que otra cosa

Todavía no hemos invocado al metodo, solo tenemos la definicion del remote object... Esta definicion se puede hacer tambien por actionscript.
Además en su aplicacion tiene un boton, que cuando sera presionado invocara a una funcion que preprara el usuario e invocara el metodo en el server:

<mx:button label="Add Item" id="submit" click="enviarForm()"/>

El Script:
<mx:script>
<!--[CDATA[
//Funcion que invocara el servicio, ejecutada cuando se apreta boton
public function enviarForm():void {
//Creacion de un objeto en AS3 de tipo usuario, que sera transmitido al server
var usuario:User = new Usuario();
usuario.nombre = "Mi Nombre";
usuario.username = "username";
usuario.password = "password";
//Uso de Token
var call:AsyncToken = ro_usuario.creaUsuario(usuario);
//Hasta aqui se hace la invocacion al metodo, pasandose de parametro el usuario creado
call.marker = "crearusuario";
}
//Manejo de resultado
private function resultHandler(event:ResultEvent):void {
var call:object = event.token
if (call.marker == "crearusuario") {
//manipular informacion a través de: event.result;
trace(event.result) //imprime el resultado del metodo
}
}
//Manejo en caso de falla
private function faultHandler(event:FaultEvent):void {
Alert.show(event.fault);
}
]]-->
</mx:script>

De verdad.. si está pensando en iniciar una aplicación en Flex con acceso a datos en el servidor, considere seriamente esta opción pues es mucho más facil que las demás...

WEBService: Permite acceder a información por medio de SOAP. Utiliza la especificación WSDL 1.1. Este método en realidad no lo he usado. Sin embargo está disponible y funciona igualmente con llamadas asincrónimas, haciendo que el programador maneje las funciones de resultado y de falla igual como el HTTP Service. Existen ya varias aplicaciones que utilizan de este medio, por ejemplo Yahoo ofrece varios de sus servicios para desarrolladores en Flex por medio de Web Services, como en los mapas o el clima: http://developer.yahoo.com/flash/astra-webapis/ (ellos "wrappean" los llamados a los servicios desde sus librerías)

Esto por ahora en cuanto a interaccion con datos...
Saludos

viernes, 23 de noviembre de 2007

Flex Básico

Si busca una manera rápida para entrarle al Flex, le adjunto algunos puntos básicos para poder iniciar sin temor en la herramienta.
  1. Flex cuenta con un Ambiente de Desarrollo muy avanzado, llamado Flex Builder el cual está basado en el IDE Eclipse Un IDE ideado por IBM y que posteriormente puso a disposición de la comunidad en general. Esto ha permitido un desarrollo acelerado de la herramienta, teniendo a disposición múltiples plug-ins para distintas tareas. Este IDE es principalmente utilizado por programadores en JAVA, sin embargo puede ser adaptado para otros lenguajes. En lo personal me gusta más este IDE para Java que otros que he intentado, por ejemplo Netbeans. Adobe logró coger la estructura principal del eclipse y aplicarla a las necesidades que tenían para el desarrollo en Flex, una herramienta intuitiva para desarrollo de interfaces gráficas, compilación desde el mismo IDE, auto-complete del código, etc...
  2. Si no cuenta con dinero para el Flex Builder (que por cierto le bajaron su precio) o es de esos programadores que les gusta la línea de comando, Adobe le permite bajar gratuitamente el compilador de Flex, donde desde la linea de comandos (mxmlc) puede compilar sus archivos creados en notepad sin ningún problema (aparte de la creación de su codigo desde notepad por supuesto =p ). Solo para recordar, la clase principal debe estar en paquete sin nombre algo asi package {...
  3. El código fuente del Flex Framework esta disponible y abierto para ser bajado, leído o si es muy bicho, pues modificado. Aparte de permitir la extensión de los componentes del framework y la herencia por sustitución o por extensión.
  4. Existen dos maneras de desarrollar en Flex, por medio de Actionscript puro (con archivos .as) y por medio del MXML (archivos .mxml). El primero por medio de clases y paquetes con funciones. El segundo es un lenguaje de etiquetas (si...como el XML) el cuál es usado principalmente para la creación gráfica de las interfaces. Si ocupa hacer una interfaz gráfica lo recomendado es hacerlo por aquí. Si ocupa extender componentes o controles ya disponibles en el framework o crear componentes compuestos (los cuales son grupos de componentes dentro de otros, pueden ser dentro de un contenedor por ejemplo) lo ideal es hacerlo por MXML. Si ya ocupa crear un componente muy detallado y muy específico, lo recomendado es hacerlo en Actionscript. Por cierto, los archivos MXML, son convertidos posteriormente en Actionscript para ser compilado posteriormente en un .SWF (se dice suif)
  5. Dentro del MXML se puede tener código de Actionscript (dentro las etiquetas script) aunque esto no es recíproco.
  6. Prácticamente todos los objetos creados en Actionscript se pueden introducir al MXML por medio de etiquetas (markups) o desde el codigo AS3.
  7. Existen ya una serie de componentes gráficos muy interesantes y avanzados con los cuales se pueden hacer las aplicaciones, esto quiere decir que no hay que inventar la rueda... Recalco: son componentes bastante avanzados, no tan rígidos como los de Swing en Java por ejemplo.
  8. Se puede hacer uso de CSS, para tus componentes, incluso Adobe puso a disposición un Style Explorer de los componentes donde puedes escoger un componente y cambiarle sus atributos para posteriormente copiar el respectivo código CSS. Esto es bastante útil cuando se quieren tener "themes" o temas en tu aplicación o hacer diseños más avanzados.
  9. Existen múltiples contenedores para los controles. El principal es el Application. Sin embargo dentro de ese se pueden agregar contenedores para distribuir mejor los controles. Existen dentro de los contenedores distintos "layouts" o formas en la que se distribuyen los componentes, ejemplo, verticalmente: componentes uno encima de otro, horizontalmente: si... ya saben como, esta tambien el absoluto: donde se define con X y Y donde se quiere poner cada componente.
Esto sería por ahora... espero poder poner algunos puntos más posteriormente....
Termino con una frase que leí ayer y que me parece una certeza: "Lo que Natura non da, Salamanca non presta", refiriendose a la Universidad de Salamanca, una de las primeras universidades en el mundo... aquí mi interpretación: "se tiene o no se tiene (inteligencia, talento, lo que sea que sea necesario) para cumplir con una tarea... nadie puede poner eso en uno"

sábado, 10 de noviembre de 2007

Notas acerca de Cairngorm

Debo de admitir que después de muchos años, cuando ingrese al mundo de Flex, me pareció como un nuevo inicio para quitar vicios de mi programación en Java.
Uno de esos era la dependencia a ciertos frameworks como struts, spring, hibernate, etc. No es que los frameworks sean malos de hecho casi todo lo que hacemos, lo hacemos basados en un framework, pero algunas veces cuando se plantea un problema por resolver muchas veces se piensa directamente en como resolverlo para y con X o Y framework, en lugar de buscar resolver el problema de la mejor manera aunque no haga uso de un framework...
Cuando empecé a adentrarme en Flex, empecé a encontrarme con la palabra Cairngorm muy frecuentemente y como estaba siendo utilizado por bastantes desarrolladores de Flex. El Cairngorm según Adobe es una micro arquitectura y al mismo tiempo un framework. Es un conjunto de patrones de diseño que han sido recolectados a través de varios años.
Por bastante tiempo estuve en negación, no quise estudiar ni adentrarme en Cairngorm, hasta que después de varios meses, en un proyecto sencillo, pero que necesitaba otro tipo de solución a la que estaba empleando normalmente, decidí probarlo.
La verdad me arrepiento de no haberlo usado antes, muchas de las cosas que hice antes, se hubiesen podido resolver de una mejor manera haciendo uso del framework... ayudando a resolver muchos problemas de arquitectura, forzándote a usar algunos de los patrones de diseño.
En realidad es bastante complicado y no es algo que se aprende de la noche a la mañana, se necesita mucha experiencia para agarrarle el ritmo, pero cuando empiezas a entender el funcionamiento aún más de lo que entiendes la sintaxis o forma de implementación, cambiará la manera en que se pueden resolver ciertas RIAs, se buscará arquitecturas donde se busque reducir el acoplamiento, delegar en otras clases, programación a la Interface, uso de Singletons(de por si la aplicación es un cliente, una sola persona la usara...), etc, etc..
A continuación algunos conceptos básicos que mi primer experiencia con Cairngorm ha brindado, estoy seguro que no son todos y talvez no los entienda 100%, pero espero aprender muchos más y que le sirva a alguno que quiera iniciar con esto.

Va más o menos así: Componente --> Patron (es) q implementa --> Descripción

Eventos --> Observer --> Extienden la clase CairngormEvent y son utilizados para notificar a un controlador cuando hay una interacción de un usuario en la que se deba ejecutar algún proceso o comando
Commands --> Command Pattern --> Implementan la interfase Command, forzando a tener un método que se llama Execute, que recibe un evento de parámetro. Aquí es donde se realizaría la acción, sea comunicarse con un server o cualquier cosa que se quiera realizar, la lógica del negocio.
ModelLocator --> Singleton --> Mantiene una copia de toda la información que se maneja del dominio de la aplicación y la pone disponible a las demás "vistas" por medio de binding u otros métodos de setteo. No tiene gran lógica, solo una colección de los datos que se utilizan a través de la aplicación.
FrontController --> FrontController, Singleton --> Se instancia al inicio de la aplicacion y su tarea es registrar los distintos eventos que puedan suceder y los comandos o acciones que se quieran ejecutar en respuesta a esos eventos, desde un solo lugar. Es el que controla los hilos del juego...
Delegates --> Business Delegate --> Se encarga de realizar la comunicación y manejar las respuestas con un servidor (en caso que se ocupe realizar)
Service Locator --> Singleton --> Permite accesar a los distintos servicio de interacción con servidores que se tengan, sean servicios HTTP, acceso a WebServices, Remote Objects, etc... de una manera centralizada y sin tener que declararlos muchas veces, pues están declarados en un solo lugar.

Cairngorm no será la solución para todos los problemas, pero definitivamente hace que uno cambie la manera de pensar en como resolverlos. Igual que con todos los frameworks, "Úsese con cuidado y moderacion", no sea que se piense en como resolver el problema con X Framework, pero ni si quiera se entienda como resolverlo...
Para un verdadero entendimiento de la arquitectura y funcionamiento del Cairngorm, no dejen de visitar este diagrama. De verdad aclara el entendimiento.

PS: De verdad.. visiten el diagrama para que puedan entenderlo bien!

viernes, 9 de noviembre de 2007

Algunos conceptos basicos del ActionScript 3

El ActionScript3 es un lenguaje muy potente. De todas las versiones de actionscript, esta es la que me parece más de verdad (sin querer ofender a nadie...) Talvez por venir del lado de Java uno espera encontrarse con algo más maduro y la verdad eso ha pasado con el AS3. Pretendo ir mostrando algunas cosillas que me han ido llamando la atención en este camino.... Aquí hay una muy buena comparación entre el Actionscript 3 y Java si quiere profundizar más.

Algunos conceptos básicos:
En AS3, no existe la herencia múltiple (como en java), solo se permite heredar de una clase directamente. Sin embargo se permite la implementación de múltiples interfaces a la vez.

Las interfaces si pueden heredar de multiples interfaces a la vez.

Cada clase debe estar dentro de un paquete masomenos algo así:

package mi.paquete{

public class miClase{

}

}


No existen metodos o clases abstractas, como se conocen en java. Se pueden tener metodos sin cuerpo dentro de las clases, sin embargo no se obliga a las subclases su implementacion, solamente se podría documentar que el método se debe implementar o hacer uso de las interfaces, que si obligan a implementacion del método.


Ciclos

AS3 cuenta con los mismos ciclos que la mayoría de lenguajes. Sin embargo añade en esta version un ciclo que es muy útil y es el for each...
Se utiliza cuando se tienen una colección de objetos dentro de un Array o ArrayCollection y te permite navegar por la lista completa haciendo él la asignación automáticamente.
Ej:
Suponiendo una coleccion de objetos llamada "objetos" - todos de tipo MiObjeto

var obj:MiObjeto;
for each(obj in objetos){
trace (obj.nombre);
}

la variable obj va tomando un valor de acuerdo a como se va avanzando en la coleccion.
Esto tambien es bueno, ya que muchos programadores tienen la mala costumbre de crear nuevos objetos dentro del ciclo algo como:

for (var i:int=0; i < objetos.lenght ;i++){
var obj:MiObjeto = objetos.get(i);
trace (obj.nombre);
}

Esto lo que hace es ir añadiendo nuevos objetos a memoria y una vez que estos dejan de ser "accesibles" por el resto de la aplicacion, quedan como candidatos para ser recolectados por el Garbage Collector del virtual machine. Talvez se piense que no hay problema si son 10, 20 objetos disponibles para ser recogidos... pero cuando son 100, 1000, 2000 o mas? El performance de la aplicación puede bajar en caso que al GC se le ocurra correr.

Tipos

AS3 es un lenguaje estricto(con tipos definidos) y a la vez dinamico (que se puede alterar ciertas clases añadiendo nuevas variables y tipos en el camino).

Hay tres tipos distintos de Tipos: Null, void y Object.
Null y void tienen un simple valor: null o undefined.
Object puede contener todas los tipos de clases que se definan, pues es la super clase de todas las cases...

Sin embargo es una buena práctica ser lo más apegados a la definición de tipos(modo estricto), por dos razones principales:
1. El performance de la aplicación es mejor, ya que somos específicos con el compilador para decirle que hacer y no tener él que inventar que hacer.
2. Hay menos posibilidades de equivocarse, se permite al compilador ayudarte a comprobar si se esta otorgando a las clases la información que se quiere y no llamando a metodos o atributos que no existen.

Para hacer esa definicion se hace:
var variable:tipo = valor;

El tipo debe contener: nombres de clases u interfaces o el simbolo *, que indica que es una variable sin tipo osea q puede recibir cualquier tipo de informacion que se quiera, sin que se genere un error.

Para verificar si un objeto es de un tipo especifico, se puede realizar de la siguiente manera:

if(objeto is MiObjeto){
trace(objecto.nombre);
}else if(objeto is MiObjeto2){
trace("Es de tipo 2"+objeto);
}

El proceso de casting esta muy ligado con el polimorfismo y la herencia. Es un proceso que nos permite convertir un objeto de un tipo especifico a otro tipo.
Supongase que se tiene un clase que se llama Vehículo, de ahí descienden carro y moto.
Podemos hacer un UpCasting para pasar un objeto de tipo Moto como un objeto de tipo Vehículo. Osea de una subclase a una superclase.
Esto se haria masomenos asi:

var moto:Moto = new Moto();
var vehiculo:Vehiculo = moto as Vehiculo;
o
var vehiculo:Vehiculo = Vehiculo(moto);

El método para pasar de una super clase a una subclase (downcasting), es parecido:
var honda:Vehiculo = new Moto();
var moto:Moto = honda as Moto;
o
var moto:Moto = Moto(honda);

Sin embargo con el downcasting, existe el riesgo que se quiera hacer a una clase que no es subclase... por ejemplo castear de vehiculo a un objeto de tipo perro, que no tienen relación. Por eso es importante usar "is" como metodo de comprobacion, ej:
if(honda is Moto){
var moto:Moto = honda as Moto;
}

Namespaces

Como en XML, definen un area de acción que permite tener varias miembros con un mismo nombre, sin que existan conflictos entre otras clases, por ejemplo que se herede de componentes ya hechos y que no exista conflictos entre las nuevas definiciones y las echas en el componente previamente o para definir mismas funciones pero para distintos ambitos.

Se declaran asi:
Dentro de un paquete:
package mis.clases{
public namespace uno;
public namespace dos;
}

Luego desde una clase se importan:

import mis.clases.*;

y se utilizan desde la clase:

package mis.clases{
public class MiClase{
uno static function holaMundo():void{
trace('Hola Mundo desde namespace uno');
}
dos static function holaMundo():void{
trace('Hola Mundo desde namespace uno');
}
}
}

Y para accesar las funciones de MiClase, desde el cliente se usa la palabra "use"
Ejm:
...
use uno;
use dos;
...
MiClase.uno::holaMundo(); //Imprime: Hola Mundo desde namespace uno
MiClase.dos::holaMundo(); //Imprime: Hola Mundo desde namespace dos