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

domingo, 15 de noviembre de 2009

Como actualiza la pantalla el Flash Player...

El Flash Player(FP) es la maquina virtual que nos permite ejecutar nuestras aplicaciones hechas en Flash, Flex o Actionscript Puro (incluso ejecuta codigo en otros lenguajes cuyo bytecode es "traducido" a un lenguaje que el player entienda, pero eso es para otro post)
Una de los principales usos que se hacen del FP es la parte grafica que ha provisto por muchisimo tiempo excelentes herramientas para desarrolladores y dise~nadores para crear contenido totalmente fuera de lo normal. De hecho podriamos pensar que lo que ha hecho grande y famoso a la plataforma flash es la capacidad de crear aplicaciones que brindan al usuario excelentes experiencias.
Pero... esas excelentes ideas y deseos de buenas experiencias pueden verse truncados si nuestras aplicaciones no estan haciendo uso correcto del FP, sobre todo en la forma en que este maneja la actualizacion de la pantalla.

Ejecucion:

* Definicion: Frame Rate: es la cantidad maxima de veces que por segundo el FP revisara si hay cambios en nuestra aplicacion que se tengan que dibujar en la pantalla. Esto no significa que si tenemos un framerate de 24 fps(frames per second) es que el FP vaya a revisar si hay cambios, 24 veces en un segundo. Esto quiere decir solamente que si todo sale bien, si nada del codigo que uno como desarrollador escribio demora mucho tiempo, el intentara revisar esa cantidad de veces, pero a veces no sera posible.

- Nuestra aplicacion es cargada dentro del FP y es agregada al stage.
- FP ejecuta el codigo inicial de nuestro Frame.
- FP ejecuta algun event listener que sea despachado.
- FP ejecuta el proceso de rendereo (o actualizacion de la pantalla), que basicamente revisa si el codigo ejecutado previamente realizo algun cambio en la parte grafica que deba ser dibujado en la pantalla. Cuando se hace ese chequeo se despacha el evento Event.ENTER_FRAME.
- Si hay cambios, actualiza la pantalla.
- FP espera hasta que se vuelva a ejecutar el chequeo. Si algun event listener es ejecutado (eventos del mouse o del teclado, etc) los ejecuta.
- Chequea si hay cambios, si los hay actualiza la pantalla.
- Repitir.

Conclusiones importantes:

- Este ciclo de chequeo se repite infinitamente durante la ejecucion de nuestra aplicacion, sea que tengamos 1 o tengamos miles de Frames, el FP solo le importa saber si hay cambios que se tengan que reflejar en la pantalla y el gustosamente se encargara de chequearlo. Cambios pueden ser: dibujar algo (graphics.drawLine,etc), mover el X o Y o el width o height de nuestros componentes o los componentes dentro de nuestra aplicacion, cambiar el color de algo, etc.
- Los cambios que hagamos dentro de una funcion a nuestros componentes visuales no se reflejaran inmediatamente en pantalla (aunque a veces parezca que si), sino hasta que nuestro codigo termine de ejecutarse y el cambio proceso de rendereo se ejecute. Por ejemplo si tenemos algo como: comp.width = 100; comp.height = 200; dentro de un metodo, esto NO quiere decir que FP vayaa ejecutar nuestro codigo asi:
1. Cambie el width.
2. Dibuje la pantalla con el nuevo width.
3. Cambie height.
4. Redibuje la pantalla con nuevo height
El FP ejecutara el redibujado de la pantalla hasta que nuestro codigo se termine de ejecutar.
- Aunque nuestras aplicaciones no tengan muchos frames (2 en el caso de Flex) o solo 1 el evento ENTER_FRAME se va a despachar multiples veces porque el FP va a revisar si hay en cambios en la pntalla que deba actualizar. De ahi que el evento ENTER_FRAME sea utilizado multiples veces para ejecutar animaciones o procesos que deben ejecutarse infinitamente dentro de un mismo frame. Essto quiere decir que si tenemos un proceso que debe ejecutarse infinitamente, no debemos meterlo dentro de un ciclo infinito, digamos while(true), sino dentro de este event listener.
- El ciclo de rendereo, es realizado automaticamente por el FP.
- Si se esta ejecutando codigo de la aplicacion, el proceso de rendereo de la pantalla no se va a ejecutar y viceversa. Estos dos son exclusivos, no se puede chequear mientras se ejecuta codigo (funciones o event handlers) y no se puede ejecutar ningun metodo o event handler si se esta haciendo el chequeo. Por ejemplo, si nuestro frame rate es de 10 fps quiere decir que el FP va a revisar en teoria cada 100ms (1000 ms = 1 segundo, 1000 / 10 = 100 :) ) si hay que hacer una actualizacion. Pero como mencione arriba el framerate no necesariamente se va a ejecutar al mismo tiempo siempre. Si tenemos una rutina que recorre un Array con 1000 objetos por dentro y a cada objeto se le ejecuta algun metodo, una validacion y se le setea algunos valores, puede ser que esa funcion dure mas de los 100ms que esperaria el FP para revisar si hay cambios. Esto quiere decir que si la funcion demora 900ms, el FP no revisara si habra cambios hasta el siguiente segundo, no cuando se cumplan 200ms desde el primer chequeo.
- Si tenemos rutinas de codigo muy grandes, muy pesadas nuestra pantalla podria llegar a "congelarse" o verse "chunky", como pegada. Esto es porque como se expuso arriba la actualizacion de la pantalla no se va a realizar hasta que se termine de ejecutar nuestor codigo. Entre mas duren nuestras rutinas mas va a durar en refrescarse nuestra pantalla y peor puede ser la experiencia del usuario.
- Hay un tiempo maximo de ejecucion de codigo que por default es de 15segs. Si por ejemplo tenemos una clase y hacemos un ciclo while(true) en el constructor, podemos esperar 15 segs y ver como nuestra aplicacion va a mostrarnos un error. Esto es porque el tiempo maximo de ejecucion de una funcion fue excedida.

Formas de Optimizacion:

- Si tenemos rutinas muy grandes y que demoran mucho tiempo, lo mejor seria dividir esas rutina en varias para ejecutarse en distintos tiempos, algo como lo que se puede hacer con Threads en otros lenguajes. Recordemos que aunque el FP maneja Threads internamente, nosotros como desarrolladores no tenemos acceso a ellos y solamente podemos emularlos.
- Si utilizamos Flex, hagamos uso de los componentes creados en el framework que en su mayoria estan optimizados para este ciclo de actualizacion de pantalla. Si vamos a hacer nuestros propios componentes, sigamos las reglas y hagamos un override de los metodos sugeridos por Adobe (esto para FLEX 3) como commitProperites y updateDisplayList entre otros. Ambos metodos mencionados antes tienen su razon de ser una funcion especifica para hacer que se ejecuten las cosas de una mejor manera.
- Si no utilizamos Flex, podemos hacer uso del evento Event.RENDER. Este metodo es despachado por el FP exactamente antes de dibujar los cambios en la pantalla. Podemos recibir este evento haciendo un addEventListener normal, pero ademas de eso tenemos que llamar a stage.invalidate(). Esto forzara al evento a ser despachado. Ahora en que nos ayuda este evento? Pues al ser despachado justamente antes de ser actualizada nuestra pantalla, podemos revisar en nuestro listener, si nuestra clase tiene algun cambio en la pantalla. Si lo tiene, llama a la funcion que dibuje o haga los cambios que se quieran hacer en pantalla. Si no hay cambios simplemente no hacemos nada. Eso nos permite forzar al FP redibujar lo que cambio SOLAMENTE cuando haya cambios que de verdad alteren nuestra pantalla y forzar a que la actualizacion de la pantalla se haga solamente hasta que se tenga que hacer. Podemos hacer mas uso de esto, si ponemos setters en nuestros componentes que se encargue de registra que hay cambios en nuestro objeto en un flag booleano. En lugar de llamar dentro del setter al metodo que se encarga de dibujar nuestros graficos o mover nuestros componentes cada vez que se cambia una variable. El event handler del metodo renderer, consultara si nuestro flag esta activado y si lo esta ahi llamara a nuestro metodo. Asi en lugar de llamar el metodo que dibuja nuestra pantalla cada vez que se cambia una variable, este se ejecutara una sola vez y exactamente antes de que se ejecute el redibujado de la pantalla. Esto es muy parecido al proceso de optimizacion que tienen los componentes en Flex.

Otros recursos:
El excelente libro de Colin Moock, Essential Actionscript 3.0, especialmente el capitulo 23
Racetrack: Excelente analisis de como funciona el proceso de rendereo en el Flash Player.

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

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...

viernes, 17 de octubre de 2008

Pruebas - Integracion de Aplicaciones

Aunque nuestros desarrolladores de lado del servidor prueben su codigo, y nosotros probemos nuestro codigo (con flex unit, mercury, flexmonkey o lo que queramos usar) el proceso de integracion entre cliente y servidor es necesario probarlo con ambos capas interactuando juntas (no solo por aparte) y de manera continua y automatizada para comprobar cualquier cambio o problema que se pueda encontrar.
Con Flex el problema es que nuestros llamados son asincronimos y no tenemos idea cuando vamos a recibir la informacion de vuelta. Esto hace que nuestros tests usando FlexUnit (la principal unidad de pruebas para flex) pasen efectivamente aunque la respuesta del servidor no sea correcta (esto por la naturaleza sincronica del flexunit) ya que el assert no se ejecuta hasta que se regrese el llamado del servidor y la unica forma de arreglar esto es usando un pequeno hack con un Timer, que la verdad hace el diseno de pruebas complicado, tedioso y dificil de mantener.
En cambio utilizando la unidad de pruebas llamada Fluint tenemos una orientacion completa a llamados asincronimos. La naturaleza de la unidad es esa y falicita las pruebas no solo de llamadas remotas, sino tambien de creacion de componentes, integracion de componentes, etc. Su documentacion aunque no es la mejor es bastante buena y el codigo es abierto. Tiene ademas un Runner de las pruebas que es ejecutable en AIR,  y genera reportes en archivos XML intepretables por parte de alguna herramienta que utilicemos para el continuous integration, como Cruise Control o Hudson
En general Fluint cumple mas alla de mis expectativas ya que su soporte asyncronimo es perfecto para todo lo que ocupamos probar, a diferencia de lo que hacer FlexUnit. Mas adelante quisiera exponer un poco con herramientas de automatizacion de pruebas como Mercury o Flex Monkey que parece ser una excelente opcion open source para esto.
Todo esto como buenas practicas que desarrolladores de Flex deberiamos de tener en nuestro repertorio... Son cosas MUY importantes y que crearan un desarrollo mas fluido y tranquilo. 
Aqui un pequeno y muy BASICO ejemplo para probar llamadas remotas:
/**
* Prueba, invocamos al metodo login de nuestro servicio con
* los parametros 'username y 'password'
* y se crea un responder de tipo TestRespoder que provee Fluint para
* poder saber quien recibira que en nuestro llamado
*/
public function testLoginService():void
{
var responder:IResponder = asyncResponder(
new TestResponder( handleResult, handleFault ) , 3000 );
var token:AsyncToken = remote.getOperation('
login').send("username",
"password");
token.addResponder(responder);
}

/**
* Handle del result de la llamada. Hacemos el Assert.
*/
private function handleResult( data:Object, passThroughData:Object ):void
{
trace(data);
assertNotNull(data);
}

/**
* Handle del fault de la llamada. Inmediatamente despachamos un
* Fail del test.
*/
private function handleFault( info:Object, passThroughData:Object ):void
{
fail("Received fault from Server: " + info);
}


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.

martes, 20 de mayo de 2008

Problema Integrando Flex y Flash (eventos del mismo tipo con clases distintas)

En el proyecto en que me encuentro laborando actualmente me salio uno de los errores mas raros que he visto.

Sintomas

1. Tenia un componente hecho en flash (swc) incluido en una clase de Flex.
2. El componente en flash despachaba un evento customizado y la clase en Flex no tenia ningun problema con el evento customizado.
3. Cuando interactuaba con el componente que se cerraba o se abria conforme se necesitara, recibia el siguiente evento:

TypeError: Error #1034: Type Coercion failed: cannot convert fl.events::ComponentEvent@dc0f4c1 to mx.events.FlexEvent.
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at fl.core::UIComponent/set visible()

El error es que se estaba intentando convertir un evento de tipo fl.core.UIComponent a un evento de tipo FlexEvent. Pero... el evento que teniamos conocimiento que despachaba el componente era de una clase distinta. Ademas revisando el codigo del componente cuando veiamos el error, no se estaba despachando ningun tipo de evento desde el componente.

Despues de revisar muchas veces el codigo, nos dimos cuenta que el problema se daba cuando al componente se le hacia visible=false.
Entonces se nos encendio el bombillo y nos pusimos a revisar la documentacion del ComponentEvent y del FlexEvent .

Problema

Al componente Flash hacer visible=false, se despachaba el evento ComponentEvent.HIDE cuyo tipo es "hide" y si se hacia visible=true despachaba un evento ComponentEvent.SHOW de tipo "show". Coincidentemente la clase FlexEvent tiene los tipos de eventos SHOW de tipo "show" y HIDE de tipo "hide". Como pueden observar tienen el mismo nombre. Pero al mismo tiempo nuestro contenedor en Flex tenia listeners para SHOW y HIDE pero de FlexEvent y al tener el mismo tipo o nombre, esos listeners en el Flex iban a ser invocados. Lo que sucede es que los listeners esperaban eventos de tipo FlexEvent y no de ComponentEvent.

Solucion

Agregue listeners directamente al componente para los eventos ComponentEvent.HIDE y ComponentEvent.SHOW e inmediatamente pare su propagacion (event.stopPropagation) para que no llegaran hasta el Flex, osea el contenedor del componente.

Moraleja

Para aplicaciones que vayan a usar componentes Flash en Flex:

1. Se debe programar a la defensiva.. es decir buscar prevenir cualquier situacion en la que algo del Flash API nos pueda dar conflicto con algo del Flex Framework sea un evento, una clase, etc.
2. Cuando se hagan eventos customizados debemos tratar de diferenciar los tipos de ellos lo mas posible, talvez anadiendo el nombre del paquete donde se encuentran.

En fin.. espero que de alguna forma pueda servirle a alguien..

sábado, 26 de abril de 2008

A Leer!!

Si hay algo que he aprendido estos anos de trabajar en programacion, es la necesidad de estar actualizado. Nada es mas importante para un programador que mantenerse al dia con lo ultimo y si se puede un paso adelante que los demas! Talvez no puedas hacerlo todo pero te dara un mejor panorama para pensar en mejores soluciones.
Ahora con el internet es muy sencillo ingresar a Google y buscar cualquier cosa y asi solucionar el problema X que tengas en un determinado momento. Sin embargo concuerdo con otros, en que es necesario leer un libro que talvez no te pueda resolver un simple problema, pero te va a dar las bases, te ayudara a profundizar y te permitara conocer mas la teoria.
Gracias a Dios mi esposa en este aspecto de comprar libros, siempre me ha apoyado al inviertir en libros y si, digo invertir porque es literalmente eso, invertir en la carrera profesional de uno para tener mejores opciones y mayor calidad de trabajo.
En lo personal leer desde una computadora me cansa mucho asi que lo que prefiero es tener el libro y poder llevarlo donde quiera.. rallarlo.. marcarlo.. subrayarlo.. ponerle notas. Eso me sirve - en lo personal - mas que tener un simple PDF y marcarlo ahi.
Por ahora presento un resumen de lo ultimos libros que he comprado y he estado leyendo, talvez alguno le pueda ser de provecho:



Joel on Software:
Uno de mis favoritos... nunca me habia divertido tanto leyendo un libro de tecnologia. Joel es un famoso programador y bloguero que en este libro toca muchos temas picantes en general sobre el mundo de la programacion y su conexion con lo corporativo. Formas de documentar, formas de hacer pruebas, como hacer mejor software (no importando el lenguaje), como ser mejor profesional, etc.. en un formato agradable y divertido y con un autor que SABE LO QUE DICE.
Un libro que me gustaria tener el dinero para comprarlo a todos mis companeros de trabajo.


Rich Internet Applications with Adobe Flex & Java (Secrets of the Masters)

Este libro lo consegui el ano pasado en la conferencia de AJAX en NY. Es hecho por 3 de los programadores de Java/Flex con los que recibi un curso de Flex y que al mismo tiempo respeto. Un enfoque distinto entrando mas hacia el Flex desde el lado empresarial que del lado de diseno. Este libro es caro pero es de los mejores que he comprado. La verdad si pudiera recomendar un libro para programadores de Java entrando a Flex no dudaria en decir que este seria lo mejor que podrian conseguir. En lo personal fue el que me termino de empujar en este mundo.



Advanced ActionScript 3 with Design Patterns

Este libro es pequeno. Solo con eso te sube la moral para seguir leyendolo. Los primeros capitulos no son tan interesantes pero luego se convierte en un libro que TIENE que ser leido por cualquier programador que quiera tomar el AS3 en serio. El mes anterior lo lei casi 3 veces. Es impresionate. Cada vez que se lee se pueden aprender cosas nuevas. El material es para programadores avanzados especialmente si vienes de lenguajes Orientados a Objetos.




Essential ActionScript 3.0
Excelente libro para el que quiera ingresar al mundo de ActionScript 3.0. Es bastante grande y al inicio puede ser un poco decepcionante ver tantas paginas pero poco a poco se le va sacando el jugo a tan excelente libro. Tiene muchos secretos y detalles que no se encuentran en cualquier lugar.

martes, 11 de marzo de 2008

Data Binding

Update (2009-03-28): Una entrada mas reciente con un ejemplo

El data binding es una de las caracteristicas mas agradables que provee Flex.

Que es en realidad?

Es un mecanismo que permite que componentes y/o objetos escuchen a los cambios que ocurran en otra variable, objeto o funcion X.

Que permite?

Bueno, permite actualizar informacion en un objeto que escucha (y mostrar esa actualizacion si es necesario) en el momento en que una variable, objeto o funcion que es escuchada cambia su estado (osea alguna propiedad).

Como funciona?

La forma mas elemental ocupa de lo que se llaman Metadata, que es una sentencia especial reconocida por el compilador, que lo que hace es avisarle como debe tratar una cierta sentencia que sigue despues del tag. En el caso de binding se utiliza [Bindable] antes de una variable que se quiera 'bindear'. Los componentes en MXML bindean muchas de sus propiedades principales por default. Una vez que indicamos que una variable va ser bindeada, osea que otros objetos pueden llegar a escuchar cambios que se realicen en ella, procedemos a definir sus escuchas (que pueden ser cero, uno o muchos) Para reflejar esos cambios en MXML, se utiliza '{ variable_bindeada } '. En actionscript puro (no MXML) se usa otro tipo de forma como por ejemplo la clase BindingUtils que provee el framework de Flex.

Que es lo que pasa en realidad?

En realidad lo que es el binding en flex, es el patron Observer simplificado por el uso de Metadata [Bindable] y de { } o BindingUtils
El observer pattern indica una relacion entre dos objetos, en la cual uno notifica al otro u otros acerca de un cambio en su estado y los actualiza automaticamente.
Entonces explicando la teoria, el observador es la variable u objeto que definimos como Bindable

Ejemplos:

Base:

<Application>
<mx:TextInput id="texto1" x="50" y="20"/>
<mx:Label id="etiqueta1" x="50" y="40"/>
</Application>

MXML:
1. Reemplazo del Label:

<mx:Label id="etiqueta1" x="50" y="40" text="{texto1.text}"/>

2. Etiqueta mx:Binding

<mx:Binding source="ObjetoFuente.propiedadEscuchar" destination="ObjetoDestino.propiedad_actualizar" />

en este caso

<mx:Binding source="texto1.text" destination="etiqueta1.text" />

Actionscript:

 BindingUtils.bindProperty(ObjetoDestino, "propiedad_actualizar", ObjetoFuente, "propiedad_escuchar");

Ejm:
BindingUtils.bindProperty(etiqueta1, "text", texto1, "text");


Notas:

Aunque el codigo se vea tan sencillo, detras de todo esto de binding ocurren una gran cantidad de cosas que nosotros no vemos. El uso de binding genera muchisimos archivos y clases mas de lo que vemos y pueden ser vistas si compilamos la aplicacion con la opcion --keep-generated-actionscript que mantiene todos los archivos generados por el compilador que son abreviados por metadatas por ejemplo. Esto se genera debido a que se crean listeners y handlers de esos listeners para cada propiedad bindeada.

miércoles, 6 de febrero de 2008

Y no le gustaria algo mas...?

Quiere un mejor trabajo? Quiere tener mas posibilidades de conseguir uno? Quiere agregar mas a su curriculum? Quiere crear las aplicaciones mas completas para internet? Si es asi y estoy casi que seguro que si, siga leyendo hasta el final...

No soy quien para decirlo ni usted para escucharlo... pero 95% de las computadoras del mundo tienen el Flash Player instalado. Despues del boom que ha tenido AJAX, del cual mucha gente habla y habla de el y no sabe lo que es, las personas han cambiado completamente su perspectiva en cuanto a las aplicaciones web.

Ya se que quiere irse, pero siga leyendo mas abajo todavia...

Se ha empezado dar una orientacion a crear aplicaciones mas 'ricas' o completas donde el lado del cliente no sea un simple formulario vacio, esperando ser llenado o un banner color anaranjado gigantesco diciendo bienvenido, sino una interaccion mas rica y agradable por parte del cliente en cuanto a lo que es la interfaz grafica. Empezamos a ver aplicaciones como GMail (wow!!! se actualiza sin refrescar la pagina completamente), Google Maps (wow!! le puedo hacer zoom y si no estoy en dial-up unos segundos despues ver la imagen mas detallada) entre otras.

Un parrafo mas y llegamos a lo que a usted le sirve...

Estas aplicaciones estan creando un nuevo grupo de programadores, no son solamente disenhadores graficos los que se estan metiendo a hacer aplicaciones web bonitas, son programadores con muchos anhos de experiencia, que vienen de transfondos con lenguajes fuertes de programacion como Java o .Net. Son aplicaciones completas, donde se programa de verdad, se hace uso de patrones, de buenas practicas, etc. Sea Flex, sea Silverlight o la herramienta que usted quiera, la demanda por programadores de este tipo esta creciendo a nivel mundial y es necesario que se empiece a capacitar y preparar gente para que cuando esta ola de trabajo llegue a Costa Rica la demanda de recursos pueda ser satisfecha.

Es por esto que en la empresa donde trabajo han tenido la genial idea de dar algunas capacitaciones abiertas al publico en general sobre temas como Actionscript 3, Flex o Flash. Nosotros estamos incluidos entre esas empresas que estan buscando personal capacitado para cumplir con tareas orientadas a aplicaciones web ricas, como esta... Incluso se planea un evento importante con gente de Adobe para tener un dia campamento de inicio en la materia. Les aseguro que va a valer la pena y que sera pronto. Les aseguro que una vez que esten dentro de esto, no van a querer salirse...

Si usted es uno de los que dijo que si a las preguntas de arriba, pues mantengase informado por aqui o deje un comentario con su email para mantenerlo al tanto del asunto. Muchos no tienen nada de que hacer despues del trabajo mas que ir a sentarse y ver tele... Salga de la rutina, estimule su cerebro, agreguele mas conocimiento y aumente su curriculum. En unos meses vera como se le abriran mas puertas para mejores empleos...sino es que se le abren antes por aqui...