React.js: Mejorando la vista

Introducción

Desde hace un tiempo venia escuchando mucho revuelo sobre React.js, un framework desarrollado por la gente de Facebook e Instagram que, según palabras de sus adeptos, es la panacea en el manejo de las vistas de nuestra aplicación.

Hace poco, en la aplicación en la cual estoy trabajando, nos encontramos con un el problema de tener una gran lista de items, que se muestran en pantalla con una estructura compleja (Digamos, cada item implica mucho html). Esta lista ademas podía ser modificada de distintas maneras, mediante filtros, búsquedas, etc. Nada complejo, de base, pero cada actualización de la misma tenia un interesante impacto en el rendimiento de la aplicación. Especialmente en dispositivos móviles

Según lo que había leído y escuchado, esto parecía un buen trabajo para React, y de hecho, lo fue.

Haciendo que React se encargue de dichos items y filtros, mejoro considerablemente el rendimiento de esta sección. Y lo mejor es que no tuvimos que cambiar nada más que la parte especifica de la aplicación encargada de mostrar dichos items.

¿Y que hace, exactamente, React?

Veamos un poco más en detalle que es lo que permitio que React funcione tan bien.

En su presentación, el sitio web de React menciona tres items:

La V del MVC

React no hace más que tomar las riendas de nuestra UI. No le importa como estén estructurados nuestros datos, ni como los procesamos, ni como se comunica nuestra aplicación con su backend, ni nada más allá de la interfaz de usuario.
Esto implica que podemos, sin mucho esfuerzo, incorporarlo en nuestra aplicación, incluso si nos encontramos un estado avanzado en el desarrollo de la misma.
Solo hay que crear los componentes y hacer que se dibujen.

Alto rendimiento mediante el uso de un DOM virtual

El secreto del rendimiento de React, esta en lo que ellos llaman DOM virtual. En el caso de nuestra lista de Items anteriormente mencionada, React mantiene una representación virtual de la misma. Al intentar actualizarla, React compara que fue lo que cambio de la lista anterior respecto a la nueva y se encarga de actualizarla.

Un flujo de datos de una sola dirección más simple que el flujo de datos tradicional.

Los datos en React fluyen en una sola dirección. A diferencie de, por ejemplo, Angular donde actualizar el modelo afecta a la vista y actualizar la vista afecta al modelo.
Como vimos antes, React solo se encarga de la vista así que en realidad, no tiene integrado el manejo de modelos. Esto ayuda a que sea sencillo integrarlo con Angular, Ember, Backbone y casi cualquier framework js que anda dando vueltas.
La gente de Facebook, de hecho, implementa una arquitectura a la que llamaron Flux, para poder aislar la propagación de datos del modelo y los eventos que dispara la vista.

Uso de React

React nos provee una API para crear componentes. Un componente, básicamente, tiene esta forma:

var Hello = React.CreateClass({
  render: function() {
    return (
      <div>Hola Mundo!</div>
    )
  }
});

React.renderComponent(<Hello />, document.getElementById('container'));

Básicamente, estamos insertando el componente Hello dentro de un elemento con id “container”. El elemento se va a insertar como un div con el texto “Hola Mundo”.
Primero, notamos que la sintaxis no es 100% javascript (¿ves los tags dentro del código?), si no jsx. Usar jsx no es obligatorio, y de hecho podemos escribir lo mismo usando 100% js, en una sintaxis quizá no tan obvia ni natural:

var Hello = React.createClass({
  render: function() {
    return React.DOM.div(null, "Hola Mundo!");
  }
});
  
React.renderComponent(Hello(), document.getElementById('container'));

La magia de React, en realidad, entra en juego cuando alteramos el estado de nuestros componentes. Cada vez que cambiemos el mismo mediante el metodo setState, React redibujara nuestro/s componentes, optimizando todo el proceso.
La Api de componentes, nos permite interactuar con el estado, eventos de DOM, propiedades, etc.

  // reactComponents/List.js
  var List = React.createClass({
    getInitialState: function() {
      return {
        items: []
      }
    },
    
    updateItems: function(newItem) {
      this.setState({
        items: newItems
      }); 
    },

    render: function() {
      var itemsList = this.state.items.map(function(item) {
        return (<Item title="item.text" />);  
      });
      
      return (<ul> {itemsList} </ul>);
    }
  });

  var Item = React.createClass({
    render: function() {
      return (<li> {this.props.text} </li>);
    }
  });

  module.exports = List;
  // script.js

  var ListComponent = require('./react-components/List');

  var items = [{text: "Item 1"},{text: "Item 2"}, {text: "Item 3"}];

  var myListComponent = React.RenderComponent(<ListComponent />, document.getElementById('container'));

  items.push({text: "Item 4"});

  myListComponent.updateItems(items); // Se actualiza el DOM con el item 4

  myListComponent.updateItems(items); // No se actualiza nada

Cómo funciona

La magia de React se debe a su DOM Virtual. Todas las operaciones que hacemos sobre sus componentes no se insertan directamente en el DOM si no que se trabaja sobre una representación del mismo.
Mediante esta técnica, React nos ahorra la costosa manipulación del DOM, ya que ante cada posible actualización, React analizará primero qué es lo que cambio para finalmente actualizar el DOM real mediante una estrategia optima con el menor impacto posible, logrando así un rendimiento mucho mayor que el logrado mediante la manipulación directa.

En el ejemplo anterior, la segunda llamada a updateItems no cambia el estado del componente, por lo que no existe una actualización del DOM real. E incluso en el primer llamado, React crea una estrategia para actualizarlo que logra que únicamente, se actualice lo necesario para agregar el nuevo item

Integración con otros Frameworks

Como mencione anteriormente, una de las cualidades de React, es que solo se encarga de la vista, por lo que podemos, sin mucho esfuerzo, integrarlo con otros frameworks MV*, como Angular o Backbone.
Esto, ademas, permite que podamos probar React sin tener que hacer un gran replanteo en nuestra arquitectura (Salvo que queramos usar Flux) ya que podemos hacer una implementación sobre un componente especifico sin alterar ningún otro.

En Angular, por ejemplo, podemos crear una directiva que se encargue de hacer de proxy entre Angular y React.

  /**
   * myApp/angular-directives/reactList.js
   */
  
  // Asumimos que tenemos definido un componente listComponent en algun lado.
  var listComponent = require('../reactComponents/listComponent');

  myApp.directive('reactList', [function() {
    return {
      restrict: 'E',
      scope: {
        items: '='
      },
      link: function(scope, el, attrs) {
        var component = React.renderComponent(listComponent({
          items: scope.items
        }), el[0]);
      }
      
      scope.$watch('items', function(new, old) {
        component.updateItems(new);
      }, true);
    }
  }]);

Luego solo hace falta que usemos dicha directiva en algun template mediante <ReactList />

En Backbone, podríamos hacer algo parecido implementando el metodo View.render, asegurandonos que ante el evento ‘render’ del modelo, nuestra vista se encargue de actualizar el estado del componente.

Conclusión

Como siempre, la idea del post no es ser una guía a React. Primero, porque existen muchas cuestiones respecto a su uso e implementación que me faltan por resolver y ademas porque debido a su etapa de desarrollo, seguramente su API cambie en el corto plazo. Y ademas, la gente de Facebook hizo un excelente trabajo con la documentación del mismo como para que tenga algun sentido.
Tampoco recomiendo que sea implementado de la misma forma que mostre mediante el escueto ejemplo anterior, seguramente podes encontrar un workflow mucho mejor y consciso, pero preferí enfocarme en la simplicidad del mismo para integrarse a otras herramientas.

Por último, solo me queda mencionar que ya hay disponibles plugins de grunt y gulp para integrar jsx en nuestro workflow actual de construcción con poco esfuerzo :).

Links y referencias

Pequeño juego en (puro) CSS – Selectores, jerarquias y animaciones

Hace un tiempo, estaba jugando en codepen.io intentando hacer una cara en css.
Luego, decidí darle un poco màs de vida, respondiendo a ciertos eventos.

ghosts

Simplemente agregando estilos distintos al :active de la cara en cuestion.

Una vez hecho esto, intente darle un poco de interacción con otros elementos. Algo que se logra fácilmente con pseudo selectores y jerarquia.

Por ejemplo:


.face:hover + .ghost .eye.right {
  display: none;
}

Estoy ocultaría el elemento de clase eye y right que sean hijos de un elemento con clase ghost que sea hermano de un elemento con clase face que posea el pseudo-selector hover. Es decir, ocultaría el ojo izquierdo del fantasma cuando nos paremos, con el mouse, arriba en la cara.

Para las animaciones, en principio había usado animations, pero luego lo cambie para usar, simplemente, transitions.
Lo importante a tener en cuenta con esto, es de tener cuidado de no animar atributos que modifiquen la caja del elemento que estamos animando (left, right, top, bottom, width, heigth, margin, padding). Cambiar, por ejemplo, el ancho (width) de un elemento, hace que el navegador tenga que recalcular la posición del elemento y de aquellos que se encuentran a su alrededor (reflow), lo cual es algo costoso y, normalmente, se nota una animación poco fluida.
Para estos casos, debemos valernos de la propiedad transform, la cual nos permite aplicar diferentes transformaciones a nuestro elemento, haciendo que el browser solo tenga que repintar el mismo, sin preocuparse por nada más.
Más información sobre reflows y repaints, pueden ver este articulo: http://www.stubbornella.org/content/2009/03/27/reflows-repaints-css-performance-making-your-javascript-slow/ o este, un poco más general sobre el funcionamiento del browser: http://www.html5rocks.com/en/tutorials/internals/howbrowserswork/

En fin, el ejemplo pueden verlo en este codepen: The Adventures of Mr. Ball
Es un simple juego en el que hay dos fantasmas escondidos en la pantalla. La cara reacciona a diferentes eventos (hover en los fantasmas, click en la cara y click en los fantasmas)

Introducción al TDD (con JS) y porque no hay que evitarlo

Desde hace un tiempo vengo leyendo y probando algunas cosas de TDD con Javascript. Pero hace relativamente poco tiempo pude implementar de manera eficiente.
Algo que resulta poco menos que ‘natural’ en Java o incluso en PHP, en Javascript parecia un poco más complicado. ¿Por qué? Porque estaba trabajando mal.

La teoria es bastante simple y obviamente, es la misma que en cualquier lenguaje.
Escribimos un pedazo de código que haga uso de la unidad que queremos probar antes de escribir la implementación de dicha unidad, luego escribimos el código necesario para que dicha prueba sea exitosa y finalmente, refactorizamos para hacer nuestra implementación más general.

Veamos una pequeña introducción (si ya tenes idea de que va el TDD, pasa a la siguiente sección)

Introducción rápida al TDD

Un ejemplo clásico de TDD y unit testing es el de la calculadora. Veamos solamente la suma para hacerlo rápido:

 function test_sum() {
   var calculadora = new Calculadora();
   
   if (calculadora.suma(1, 3) === 4) {
     console.log("Test ok!");
   } else {
    console.log("Test fail!");
   }
 }

 test_sum();

Como podemos ver a simple vista, al ejecutar este extracto recibiremos un error diciendo “Calculadora is not defined” y eso esta bien. Es lo esperable, despues de todo, todavia no implementamos nuestro objeto Calculadora.

 function test_sum() {
   var calculadora = new Calculadora();
   
   if (calculadora.suma(1, 3) === 4) {
     console.log("Test ok!");
   } else {
    console.log("Test fail!");
   }
 }

 function Calculadora() {}

  Calculadora.prototype.suma = function() {
    return 4;
  }

 test_sum();

¡Hurra! ¡Nuestro test funciona! ya podemos empaquetar nuestra “Calculadora”, subirla a Github y esperar llenarnos de estrellas y hasta un post en Hackernews.
Bueno, no tan rápido. Nuestra calculadora, efectivamente, puede sumar 1+3, 2+2, -3+7 y cualquier otro par de digitos cuya suma sea igual a 4. Pero en cualquier otro caso, sabemos que va a fallar. Es ahí en donde vamos a refactorizar nuestro test para hacerlo más “inteligente” y de esta forma, mejorar nuestro código.

 function test_sum() {
   var calculadora = new Calculadora();
   
   var a = Math.floor(Math.random() * 10);
   var b = Math.floor(Math.random() * 10);
   
   if (calculadora.suma(a, b) === a + b) {
     console.log("Test ok!");
   } else {
    console.log("Test fail!");
   }
 }

 function Calculadora() {}

  Calculadora.prototype.suma = function() {
    return 4;
  }

 test_sum();

Cuando volvemos a ejecutar, el test fallará (salvo que tengas la mala buena suerte de que la suma de los números elegidos de forma aleatoria sea igual a 4. Así que vamos a darle los últimos retoques para que nuestro test se ejecute de forma correcta.

 function test_sum() {
   var calculadora = new Calculadora();
   
   var a = Math.floor(Math.random() * 10);
   var b = Math.floor(Math.Random() * 10);
   
   if (calculadora.suma(a, b) === a + b) {
     console.log("Test ok!");
   } else {
    console.log("Test fail!");
   }
 }

 function Calculadora() {}

  Calculadora.prototype.suma = function(a, b) {
    return a + b;
  }

 test_sum();

Ahora sí, nuestra calculadora puede sumar, sin importar que números le pasemos como parametro. O al menos, debería.

Obviamente, en js ya tenemos herramientas más robustas y maduras para realizar unit testing que un par de if’s.

O sea que Ahora tengo que perder mi tiempo escribiendo tests…

Este es quizás el pensamiento más común a la hora de empezar a escribir tests. El patrón EVO (Escribir y Ver que Onda) parece mucho más tentador y sencillo.
Sin embargo, utilizar TDD nos permite no solo ahorrar tiempo, si no que también nos aporta las siguientes ventajas:

  • Al escribir primero el test, vamos a tener en claro como utilizar nuestra líbreria/objeto/función por lo que reducimos tiempo en el diseño y en los eventuales “imprevistos” que podemos tener al “programar sobre la marcha”.
  • Si aparece un bug en nuestra aplicación, es mucho más fácil detectar de donde vino ya que podemos, por ejemplo, escribir tests que hagan uso de los valores que creemos que estan arrojando resultados incorrectos. Con esto podemos ver que nuestros tests pueden no ser perfectos, pero nos ayudaran a aislar el problema que tengamos.
  • Nos ayuda a pensar correctamente. A veces parece que olvidamos que los sistemas son Conjunto de partes interrelacionadas entre sí, aplicar TDD nos obliga a pensar en componentes y a tener en claro la entrada y la salida de cada uno de ellos llevando a disminuir el acoplamiento de los módulos que estemos desarrollando y la posibilidad de reutilizarlos.
  • Estamos forzados a simplificar nuestra aplicación. Divide y venceras.

Seguramente existen muchas otras ventajas, pero estas son las que pude rescatar en el tiempo que llevo usando TDD.

No puedo escribir Tests para lo que estoy haciendo, mís módulos dependen del DOM

Por alguna razón, el DOM nos asusta (Bueno, la razón es obvia, es horrible).

Sí, esta claro, nuestros módulos deben ser independientes del DOM. Sin embargo, tarde o temprano tenemos que hacer uso del mismo si queremos que el usuario vea algo de todo aquello que estuvimos escribiendo.

Por suerte, hoy en día proliferan los frameworks como Marionette que nos permite dividir nuestra aplicación y poder cumplir con los principios de TDD.
La mayoría de estos frameworks, solucionan muchos problemas comunes a la hora de desarrollar applicaciones y uno de ellos, es la posibilidad de pensar nuestras vistas como únidades átomicas y, por tanto, las hace ideales para TDD.

Por ejemplo, si utilizamos Marionette, podemos ‘renderizar’ nuestra vista, sin incluirla dentro de la estructura de nuestro sitio, pero aún así, hacer uso del DOM generado por la misma.

  var PersonaItemView = Marionette.ItemView.extend({
    template: "#persona"
  });

  function test_persona() {
    var personaMock = new Backbone.Model({
      nombre: "Pablo",
      edad: 26
    });
    personaItemView = new PersonaItemView({
      model: personaMock
    })

    personaItemView.render();

    if (personaItemView.$el.find('.name').text() === personaMock.get('nombre')) {
      console.log("Test ok!");
    } else {
      console.log("Test fail!");
    }
  }

Marionette nos permite acceder, mediante el atributo “$el” al elemento de jquery que genera nuestra vista. Permitiendo de esta forma poder probar su funcionamiento antes de insertarlo al documento real

Obviamente, podemos pensar esto de una forma agnóstica al framework. O bien adaptarlo al framework que estemos utilizando.
Podría darse el caso de que nuestra vista no posea un template. En esos casos, siempre podemos hacer un pequeño mock de la estructura real.
Si finalmente nos encontramos con que dicho mock resultaría terriblemente engorrosso o nos vemos en la necesidad de cargar un gran número de dependencias a fin de poder probar el módulo o unidad que estamos probando, entonces lo estamos haciendo mal.

Tener nuestra aplicación correctamente dividida, es escencial para poder mantenerla o incluso para poder desarrollarla. Javascript es particularmente propenso a crear código spagetti gracias a su versatilidad. Y sobre este punto hago la recomendación de utilizar un framework que nos fuerce a utilizar un patrón conocido o, al menos, una organización que nos pueda resultar facil de entender. No me interesa, particularmente, que SuperFramework2000 me permita hacer en dos líneas de código que mi navegador me cocine una milanesa Me interesa saber donde tengo que mirar si quiero cambiar mi aplicación para que la milanesa este cocinada al horno en lugar de frita.

Planear una aplicación “en papel” y apegarnos 100% a esos hermosos diagramas de relaciones y de flujo que garabateamos resulta muy útil, pero muchas veces nos abstrae a un nivel en el aue dejamos muchas cosas afuera. TDD nos ayuda a identificar rapidamente estos problemas.

¿Y cómo escribo Tests en JS?

Bueno, ya mostre lo de crear una función que imprima algo en consola. Pero todos queremos juguetes lindos.

Actualmente, podemos nombrar tres frameworks de testing populares: Qunit, Jasmine y Mocha.

En lo personal, prefiero los dos últimos ya que los considero los más completos. Como siempre, es una cuestión de gustos. Jasmine posee muchas herramientas integradas y lo considero una muy buena opción para comenzar. Mocha, por otra parte, depende de otras herramientas, lo cual lejos de ser una desventaja, permite hacer cosas muy interesantes utilizando cosas como Sinon.js.

Independientemente del framework que elijamos, es importante destacar el uso de herramientas como Phantomjs y SlimerJS, que nos permiten correr un motor web desde la consola, de forma que resulte muy fácil incorporar nuestra suite de tests a un proceso de construcción mediante herramientas como Grunt. De hecho, en el caso de Jasmine,Grunt posee un modulo contrib muy completo para manejarlo.

No es mi intención, con este árticulo, enseñar alguna de estas herramientas. Pero si estas interesado, te recomiendo comenzar con Jasmine, ya que al poseer todas las herramientas integradas, es más sencillo para comenzar.

Pongo, a modo de ejemplo, como seria el test para la aplicación de la calculadora que escribí en la introducción utilizando Jasmine:

  describe('La clase Calculadora', function() {
    it('Puede sumar 1 y 3', function() {
      expect(calculadora.sum(1, 3)).toBe(4);  
    });

    it('Puede sumar cualquier par de numeros', function() {
      var a = Math.random();
      var b = Math.random();

      expect(calculadora.sum(a, b)).toBe(a + b);
    });
  });

Por último, en FernetJS tienen una buena introducción al uso de Mocha con expectjs.

expect(me.volverAEscribir()).toBe(‘pronto’);

Mi primer webapp (En FirefoxOS)

Este post es un resumen de la charla, introductoria a FirefoxOS, que dí en el evento Hackaton Express.

Pueden ver los slides de la misma desde: http://tehsis.github.io/miPrimerWebapp/

El título, posee FirefoxOS entre parentesís, debido a que, en realidad, las cosas que vamos a ver deberían funcionar en distintos browsers y/o tecnologías. FirefoxOS, como plataforma, es el medio por el cual Mozilla provee un stack completo para poder desarrollar este tipo de apps basadas en tecnologías web, asegurando la implementación de los estandares propuestos por las llamadas WebAPI.
Esto es lo que más me atrae de esta plataforma, pero vamos a dejar de lado esto y vamos a ver que es lo nuevo (y no tan nuevo) que nos ofrece.

Web…¿Apps?

Este concepto no es, para nada, nuevo. De hecho, desde la primer versión del iPhone (antes, quizá) podiamos tener sitios web que se guardaban como si fuesen una aplicación y su experiencia de usuario intentaba simular a las aplicaciónes nativas. Sin embargo, tanto iOS, Android y el resto de los dispositivos (Sacando, problablemente, algunas excepciones no muy populares) ofrecián una API limitada en comparación con la ofrecida por el SDK nátivo de la plataforma.
Ahora, vamos a llevar el concepto de webapp un paso más allá del simple hecho de tener “un sitio web con un acceso directo y que se vea sin los botones del navegador” a una aplicación que el usuario puede instalar, es independiente y puede funcionar offline.

Instalables

El usuario, puede instalar las webapps como cualquier otra. Para esto, la aplicación debe contar con un archivo denominado “manifest”, el cual le indica a nuestro “sistema operativo” algunos datos de la aplicación, como ser, el nombre, la descripción, los iconos, los permisos que requiere y algunos más.

Acá, podemos diferenciar 3 tipos de apps de acuerdo a los permisos que poseen.
Las primeras, que pueden ser “hosteadas”, es decir, servidas a través de un servidor web (valga la redundancia) o empaquetadas, en donde todo el contenido se encuentra en un “paquete” (un archivo zip, en el caso de FirefoxOS), pueden acceder a un numero limitado de recursos, como ser, la vibración del teléfono o las notificaciones.
El segundo tipo, son las privilegiadas. Que poseen acceso a recursos más “peligrosos” como la conexión de red o el Bluetooth y requieren estar aprobadas por el MarketPlace para funcionar.

Por último, tenemos las certificadas, las cuales vienen preinstaladas en el dispositivo, por ejemplo la aplicación para realizar llamadas.

Independientes

Cada app es su propio mundo. Esto quiere decir, entre otras cosas, que la aplicación A no puede acceder a las cookies de la aplicación B. Aún si estas cookies comparten el mismo dominio.

Para un ejemplo más claro, pensemos en una app que se identifique con Facebook. Por más que otra app también lo requiera, deberá hacerlo de forma independiente ya que no puede leer las cookies (y ningún otro recurso) de la otra (Mención aparte merecen las denominadas web activities).

Devices API

Esta es la parte que más me emociona de las webapps. Ya que gracias a ellas podemos interactuar de forma más cercana con nuestro dispositivo. Podemos, por ejemplo, hacer vibrar nuestro celular, usar las notificaciones del sistema, reaccionar a los cambios de luz, conocer nuestro nivel de bateria ó si el dispositivo esta enchufado y un largo etcetera. Cuestiones que antes se encontraban relegadas únicamente a las aplicaciones “nativas”.

Para un pequeño ejemplo, si tenes una notebook o un celular con sensor de luz, probá tapar la cámara frontal (o bien, apaga la luz)

En fin, podríamos estar un buen rato viendo ejemplos de webAPIs. Son fáciles de usar y, por la novedad que implica que nuestro browser sea “consciente del entorno” siempre resulta interesante verlos. Pero para eso, mejor veamos la documentación oficial y pasemos a la acción.

Desarrollando mi primer webapp

Para dejar las cosas un poco más en claro vamos a hacer, paso a paso, una pequeña webapp.

La idea, sera hacer una sencilla app que nos avise una vez transcurra una x cantidad de segundos.

Como dijimos desde un principio, no necesitamos otra cosa distinta a lo que usualmente manejamos en desarrollo web. De modo que, para empezar, vamos a crear tres archivios: index.html, alarm.js y alarm.css

Empecemos por index.html. Nuestra app va a contar de un elemento input para colocar los segundos y un boton que pondrá la alarma a sonar.

Como vemos, no hay nada extraño en este archivo. Quizá, haga falta prestar atención al atributo type del input, el cual es de tipo “number”, esto hara que ademas de permitir validaciones, si accedemos desde un celular, solo veremos un teclado númerico en vez de un teclado completo

Pasemos ahora al javascript, en el que nuevamente no veremos muchas sorpresas:

Simplemente, escuchamos el click al boton, el cual genera un timeout que muestra una alerta pasado el tiempo que ingresamos en el input.

Ahora bien, esto no tiene nada de novedoso. De hecho, casi todo esto podría funcionar, incluso, en Internet Explorer 6 (Bueno, en realidad no, ya que no teniamos addEventListener) y no hace uso de nada que haga que nuestro browser use el dispositivo sobre el cual esta funcionando.

Vamos entonces a hacer que, al pasar el tiempo en lugar de mostrar el alert, muestre una notifiación (lo cual hara uso de las notificaciones del sistema operativo sobre el cual esta funcionando) y vibre.

Nuestra, en extremo sencilla, aplicación ya va tomando forma. Pero para cumplir con la definición de webapp que vimos al principio, necesitamos que pueda instalarse. Para eso, lo primero que debemos hacer es crear un archivo manifest para nuestra app. Este archivo, escrito en JSON, le dara al sistema operativo, información sobre la aplicación, tal como el nombre de la misma, la descripción, datos del desarrollador, los permisos que necesita y otra serie de parametros. Un posible manifest para nuestra app podría ser:

Para instalarlo, vamos a hacer uso del objeto mozApp, el cual nos provee lo necesario para instalar la aplicación, reaccionar ente errores, etc. Como notaran por el prefijo moz, este solo funciona en Firefox.

Para hacer aún más facil esto, vamos a usar una pequeña libreria que arme. La misma se encargara de controlar si la aplicación puede, o no, ser instalada sin problemas o si ya se encuentra instalada en el sistema. La pueden conseguir de https://github.com/tehsis/webinstaller/archive/master.zip y la forma de usarla es bastante sencilla:


La libreria, ademas de manejar la instalación en sí, se encarga de colocar clases en el body de acuerdo al estado de la aplicación, forma que podamos decidir si mostrar o no el boton para instalarla o cualquier otro mensaje que se nos ocurra (más info en: https://github.com/tehsis/webinstaller).

Como ven, dentro del manifest, estoy especificando un ícono (de 64×64), el mismo lo podemos crear siguiendo estos guidelines: http://www.mozilla.org/en-US/styleguide/products/firefoxos/icons/
Este sera usado para acceder a nuestra aplicación, una vez instalada.

Si vamos ahora a nuestra aplicación y hacemos click en el botón de Instalar, Firefox nos preguntara si deseamos hacerlo. Si confirmamos, podremos acceder a la aplicación como si se tratase de una más (Vale aclarar que esto funcionará en Firefox ya sea para desktop, Android y/o FirefoxOS)

Por último, solo queda agregar algo de estilo a nuestra aplicación. ¡Y listo! Ya tenemos nuestra primer webapp que, ademas, podemos instalar.

Alarm

Pueden bajar el ejemplo completo desde https://github.com/tehsis/alarmexpress

Herramientas para desarrolladores

Seguramente, en el desarrollo de nuestra aplicación, especialmente si es una un poco más complicada que esta, necesitemos realizar pruebas y/o resolver bugs. Para ello, Mozilla ofrece diferentes herramientas que vamos a mencionar sin entrar en mayores detalles:

La primera, son las Herramientas de desarrollo de Firefox las cuales podemos acceder presionando “Ctrl + shift + I” en Linux y Windows ó “⌘ + shift + I” en OSX,

Estas herramientas, cuentan con la clasica consola Javascript, en la cual podemos ejecutar comandos, un depurador (debugger, para los amigos), visor de red (A partir de Firefox 23), editor de estilos y profiler.

Mediante el debugger, podemos deternos el algún punto especifico de nuestra aplicación, examinar las variables, así como el contexto, ejecutar paso a paso, etc.

Firefox Devtools

Algo interesante de Firefox, es que podemos conectar el debugger con Firefox para Android o bien con un dispositivo con FirefoxOS y hacer uso del mismo de forma remota. Es bastante sencillo y funciona muy bien. Solo debemos ir a about:config (desde la barra de direcciones) y activar el flag devtools.debugger.remote-enabled. Esto hara que se nos habilite la opción “connect” dentro de “Herramientas -> Herramientas de desarrollo” en Firefox (La úbicación puede variar, según el sistema operativo) luego debemos activar esta posibilidad en nuestro dispositivo. Para más información, les dejo un árticulo al respecto: Desarrollo web móvil – Inspeccionando webs en dispositivos moviles.

Segundo, vamos a nombrar al emulador de FirefoxOS, el cual se instala mediante una extensión de Firefox

Esta extensión, nos permite instalar nuestra app, indicandole el manifest, o bien cargandola como una app empaquetada a través del navegador de FirefoxOS o bien mediante el Marketplace ya que, en definitiva, se trata de un emulador de este sistema y podemos usarlo completamente.

Firefox OS Emulator

En resumen:

  • Una webapp es una app, que hace uso de las tecnologías web, pueden ser instalada por el usario y funcionar offline
  • Gracias a las Devices API, las aplicaciones web ahora pueden ser “conscientes” del dispositivo en el que funcionan y acceder a sus recursos.
  • Para poder dar un empuje a este ecosistema, Mozilla ofrece FirefoxOS como plataforma 100% web. Sin embargo, esperamos que las novedades que incluye en cuanto a programación, esten disponibles en todas las platadormas
  • Para más información, ya sea de FirefoxOS o cualquier tema relacionado al desarrollo web, no dejen de visitar el Mozilla Developer Network ó MDN

Deployd: Cómo tener una API REST en 15 minutos

El sábado pasado tuve la oportunidad de asistir a una hackaton organizada por Hacks/Hackers en Buenos Aires. En el equipo que estuve anotado, necesitabamos cargar datos y poder consumirlos desde Javascript para usarlo junto con Popcornjs (Otro día cuento un poco de esto).

La semana pasada, había leido sobre Deployd en GenbetaDev y aproveche para darle una oportunidad.

Los resultados, geniales. En minutos, tuvimos no solo una base de datos para lo que queriamos cargar, si no tambien una interfaz para hacerlo de forma visual, una API REST y una API en javascript que permitio que nos desentendamos por completo del tema.
La página web de Deployd es bastante completa en cuanto a documentación, ademas, la interfaz que posee es completamente intuitiva, una vez que lo tengamos andando, basta que hagamos un par de clicks en su interfaz para que veamos el poder que tiene. Sin embargo, debido a lo temprano de su desarrollo, hay ciertos errores que tenemos que resolver por nuestra cuenta, ya que de momento al menos, no es muy “habladora” que digamos y en caso de fallos simplemente no funcionara.
Por eso, van los pasos para tenerlo andando, a partir de su código fuente, probado en Archlinux, Ubuntu 13.04 y OS X Montain Lion.

  1. Tenemos que asegurarnos de tener instalado Mongodb (apt-get install mongo, pacman -S mongodb, brew install mondodb o lo que corresponda)
  2. Descargamos el código fuente de su página oficial y lo descomprimimos en cualquier lugar (vamos a suponer que lo hacemos en un directorio llamada deployd).
  3. Nos aseguramos que el archivo dpd, dentro de la carpeta bin, se pueda acceder globalmente. Para esto podemos agregar deployd/bin/ a nuestro PATH o bien, desde el directio deployd, “alias dpd=`pwd`/bin/dpd”
  4. Desde el directorio donde queremos crear nuestro proyecto, hacemos “dpd create miApp“. Esto nos creara una carpeta llamada “miApp
  5. Dentro de la carpeta “miAppejecutamos “dpd -d. Si todo anduvo bien, tenedremos la consola de Deployd y se abrira un browser con el dashboad (En caso de no hacerlo, solo debemos ir a localhost:2403/dashboard), desde donde podremos comenzar a usarlo.

Desde el dashboard de Deployd, podemos crear nuevas colecciones, especificando cada uno de sus campos. Cargar datos a estas colecciones, consultar los metodos REST que nos creo y especificar acciones ante los eventos CRUD haciendo uso de javascript.

Lo bueno de Deployd, es que todo es muy intuitivo. Si creamos una colección llamada “productos”, podemos hacer un GET a “localhost:2403/productos” y obtendremos una respuesta JSON con todos los productos que hayamos creado. Así tambien, “localhost:2403/productos/” Nos traera el producto que tengan esa . Tambien podemos hacer request POST, UPDATE o DELETE. Cada una hara la acción correspondiente, ejecutando primero lo que hayamos especificado en la pestaña Events del Dashboard (Si lo hicimos).

Si vamos ahora a la carpeta de nuestro proyecto, dentro de ‘public‘, vamos a tener un archivo index.html listo para usar que cargara la libreria js de dpd que pone a nuestra dispocisión, un objeto global llamado dpd, mediante el cual podemos acceder a nuestras colecciones. Por ejemplo, para acceder a los productos que creamos, lo hacemos mediante “dpd.get(function () { … })

En conclusión, Deployd nos permite tener, no solo una API REST, si no tambien una completa interfaz para manipular datos y accederlos ya sea mediante REST o su libreria Javascript. Ideal para hackatones cuando no contamos con una fuente de datos ya creada. Habría que ver como se comporta con un stress mayor.
De momento, recomiendo visitar su página oficial y colaborar con el proyecto a través de su repositiorio en github.

Asm.js: Compilando a javascript

El contenido de este post no es mío. Es una traducción (libre) que me tome la libertad de hacer de lo que escribió  Jhon Resig en su blog acerca de Asm.js.El articulo me pareció muy interesante y enriquecedor y creí que seria muy bueno que este disponible en castellano, especialmente para aquellos que todavía no están convencidos del potencial de JavaScript. De más esta decir que recomiendo completamente que lean el articulo original en lugar de este si pueden leer ingles sin problemas.

El árticulo continene una muy buena explicación de como funciona asm.js, ademas de una estupenda entrevista a David Herman contandonos un poco los objetivos y lo que podemos esperar de asm.js en el futuro. Sin más, el articulo:

Link al árticulo original: http://ejohn.org/blog/asmjs-javascript-compile-target

Igual que muchos desarrolladores, estaba muy entusiasmado con lo que promete Asm.js. Enterarme que Asm.js esta disponible en Firefox Nightly hizo que mi interés aumente. Mucha gente también lo hizo, de hecho, cuando Mozilla y Epic anunciaron (mirror) que habían portado el motor Unreal 3 – y que funcionaba muy bien.

Hacer que el motor de un juego escrito en C++ corra en javascript, usando WebGL para sus gráficos, es un logro realmente increíble y se debe en parte al conjunto de herramientas desarrolladas por la gente de Mozilla.

Desde la salida del motor de Unreal 3 en javascript, comencé a seguir la recepción de esta noticia por twitter, blogs, etc y ademas de ver que muchos desarrolladores comenzaron a mostrar interés por las tecnologías abiertas que hicieron esto posible, también ví mucha confusión: ¿Asm.js es un plugin? ¿Mi código javascript sera más rápido si uso Asm.js? ¿Funciona en todos los browsers? Siento que Asm.js y las otras tecnologías relacionadas, son muy importantes y me gustaría explicar como funciona, así los desarrolladores saben que es lo que esta pasando y como se verán beneficiados.

¿Que es Asm.js?

Para entender Asm.js y donde se ubica dentro del browser, es necesario saber de donde viene y para que fue creado.

Asm.js viene de un nuevo tipo de aplicación js: aplicaciones C/C++ que fueron compiladas en JavaScript. Es un nuevo tipo de aplicaciones que surgieron a partir del proyecto de Mozilla Emscripten.

Emscripten toma código C/C++, lo pasa a través de LLVM y convierte el bytecode generado a JavaScript. (Asm.js es, concretamente, un subset de JavaScript).

Si el código Asm.js compilado hace algún tipo de renderizado, entonces seguramente sera manejado por WebGL (usando OpenGL para ello). De esta manera, todo el trabajo es llevado a cabo haciendo uso del browser y JavaScript pero esquivando, prácticamente, todo el camino normal de ejecución y renderizado que tienen las aplicaciones Javascript-en-el-browser normales..

Asm.js es un subset de JavaScript altamente limitado en cuanto a lo que puede hacer y sobre lo que puede operar. De esta forma, el código compilado a Asm.js puede ejecutarse rápidamente haciendo las menores suposiciones posibles, convirtiendo el código JavaScript directamente a ensamblador. Es importante tener en cuenta que Asm.js es simplemente JavaScript – Osea, no necesitamos ningún plugin especial para ejecutarlo en el browser (Aunque un browser capaz de detectar el código compilado en Asm.js puede hacerlo mucho más rápido). Es un subset especial de JavaScript optimizado para que sea más “performante”, especialmente cuando se trata de código compilado a JavaScript.

La mejor forma de entender como funciona, es mirar un poco el código compilado a Asm.js. Vamos a ver una función extraída de una aplicación real compilada a Asm.js (De la demostración BananaBread). Le dí un poco de formato a este código para que sea más fácil de digerir, pero normalmente es un montón de código JavaScript minificado.

Técnicamente, es código JavaScript, pero podemos ver que difiere bastante de lo que estamos acostumbrados a ver en aplicaciones normales que hacen uso del DOM.

Algunas cosas de las que podemos darnos cuentas simplemente mirando este código:

  • Este código en particular, solo trabaja con números. De hecho, todo el código compilado a Asm.js hace esto. Asm.js solo puede trabajar con un grupo selecto de tipos numéricos y ninguna otra estructura de datos (Esto incluye strings, booleanos y objetos).
  • Todo dato externo, es almacenado y referenciado desde un único objeto, denominado pila. Esencialmente, esta pila es un array gigante (Que intenta ser un array tipado,  altamente optimizado para mejorar su rendimiento). Todos los datos son almacenados dentro de este array reemplazando efectivamente a las variables globales, estructuras de datos, closures y cualquier otra forma de almacenamiento de datos.
  • Cuando se accede o se asigna algún dato, su valor es forzado a un tipo especifico, siempre. Por ejemplo f = e | 0; asigna a la variable f el valor de e pero también asegura que este valor va a ser un entero (| 0 justamente, convierte un valor a entero). También vemos esto con los números flotantes – fijate el uso de 0.0 y g[...] = +(...);.
  • Mirando los valores que entran y sale de las estructuras de datos, pareciera como si el dato estructurado representado por la variable c es un Int32Array (almacenando enteros de 32 bits. Los valores son siempre convertidos hacia o desde un entero usando| 0) y g es un Float32Array (almacenando flotantes de 32 bits. Los valores son siempre convertidos a un flotante encerrando el valor con +(...)).

Haciendo esto, el resultado esta altamente optimizado y puede ser convertido directamente desde esta sintaxis Asm.js hacia ensamblador sin tener que interpretarlo como tendría que hacerlo con JavaScript. Esto recorta muchas cosas que pueden hacer que un lenguaje dinámico, como Javascript, sea lento: Como la necesidad de un recolector de basura y tipos dinámicos.

Como ejemplo de un código Asm.js más “explicativo” vamos a ver uno sacado de la especificación de Asm.js:

function DiagModule(stdlib, foreign, heap) {
    "use asm";

    // Variable Declarations
    var sqrt = stdlib.Math.sqrt;

    // Function Declarations
    function square(x) {
        x = +x;
        return +(x*x);
    }

    function diag(x, y) {
        x = +x;
        y = +y;
        return +sqrt(square(x) + square(y));
    }

    return { diag: diag };
}

Este código es un poco más claro y podemos ver mejor como funciona Asm.js. Cada modulo está contenido dentro de una función y comienza con la directiva"use asm";. Esto le dice al interprete, que todo lo que se encuentra dentro de esta función debe ser tratado como Asm.js y ser compilado directamente a ensamblador.

Hay que prestar atención a los parámetros de la función: stdlib, foreign, and heap. El objeto stdLib tiene referencias a varias funciones matemáticas nativas. foreign proveé funcionalidades definidas por el usuario (Como podría ser, dibujar una figura en WebGL). Por último heap es un ArrayBuffer que puede ser visto, según el caso, como distintos tipos tales como Int32Array y Float32Array.

El resto se divide en tres partes: declaración de variables, declaración de funciones y por último, un objeto para exportar las funciones que serán expuestas al usuario.

La última parte, la que exporta las funciones, es muy importante, ya que permite que todo el código dentro del modulo pueda ser tratado como Asm.js y a la vez ser usado por código JavaScript normal.

De esta forma, podrías tener algo así usando el mencionado DiagModule:

document.body.onclick = function() {
    function DiagModule(stdlib){"use asm"; ... return { ... };}

    var diag = DiagModule({ Math: Math }).diag;
    alert(diag(10, 100));
};

Esto nos daría a DiagModule en Asm.js que sera tratado de manera especial por el interprete de JavaScript pero aún así estará disponible para otro código JavaScript (Esto quiere decir que podremos usarlo dentro de un evento onClick, por ejemplo)

¿Que tal es el rendimiento?

Actualmente, la única implementación que existe es en las versiones nightly de Firefox (y solo para un par de plataformas). Dicho esto, las primeras pruebas mostraron resultados muy, muy, buenos. En aplicaciones complejas (como los juegos mencionados) el rendimiento es solo 2 veces menor que el del código nativo compilado desde C++ (Lo que es comparable a otros lenguajes como Java o C#). Esto es enormemente más rápido que lo que logran los browsers actualmente, alrededor de 4 a 10 veces más que las ultimas versiones de Firefox y Chrome.

Esto es una enorme mejora sobre lo que tenemos actualmente. Considerando lo temprano de su desarrollo, podemos incluso pensar un rendimiento mucho mejor en las próximas releases de Asm.js

Es interesante ver la enorme diferencia entre Asm.js y los motores actuales en Firefox y Chrome. Una mejora de rendimiento de 4 a 10 veces es enorme (Es como comparar a los browsers actuales con el rendimiento de IE6).
Algo interesante, es que incluso con esta diferencia de rendimiento, muchos de los demos en Asm.js funcionan bien en las versiones actuales de Chrome y Firefox, lo que nos da un buen indicador del estado actual de los motores JavaScript. Sin embargo, su rendimiento no es tan bueno como el ofrecido por un browser capaz de optimizar código Asm.js.

Casos de uso

Hay que tener en cuenta que casi todas las aplicaciones que se usan con Asm.js actualmente son aplicaciones C/C++ compiladas usando Emscripten. Teniendo esto en cuenta, el tipo de aplicaciones que van a compilar a Asm.js, en el futuro cercano, son aquellas que se pueden beneficiar de la portabilidad de un browser, pero que son muy complejas como para ser hechas directamente en JavaScript.

Hasta ahora, la mayoría de los casos de uso se centraron en código donde el rendimiento es muy importante: Tales como juegos, manejo de gráficos, interpretes de lenguajes de programación y bibliotecas. Un vistazo rápido en la lista de proyectos de Emscripten muestra muchos proyectos que serán de uso instantáneo para muchos desarrolladores.

Soporte para Asm.js

Como vimos al principio la versión nightly de Firefox es el único browser que soporta la optimización de Asm.js.

Sin embargo, es importante destacar que el código formateado para Asm.js es ni más ni menos que código Javascript, con un importante set de restricciones. Por esta razón, el código compilado a Asm.js puede correr en otros browsers al igual que cualquier otro código JavaScript, incluso si el browser no lo soporta.

La parte crítica del rompecabezas es el rendimiento de ese código: Si el browser no soporta arrays tipados o no compila especialmente el código Asm.js el rendimiento sera mucho menor.

Asm.js y el desarrollo web

Como seguramente te habrás dado cuenta, el código Asm.js no esta pensado para que lo escribamos a mano. Sera necesario alguna herramienta para escribirlo y van a ser necesarios algunos cambios en como escribiríamos código JavaScript normal para poder usarlo. El caso de uso más común para Asm.js en este momento es con aplicaciones compiladas desde C/C++ a JavaScript. Casi ninguna de estas aplicaciones interactuan con el DOM de forma significativa, mas allá de usar WebGL y demas.

Para que esto pueda ser usado por desarrolladores normales es necesario tener lenguajes más “accesibles” que puedan compilar a Asm.js. El mejor candidato, hasta el momento, es LLJS que esta comenzando a lograr compilar hacia Asm.js. Es importante notar que un lenguaje como LLJS va a seguir siendo un poco diferente de lo que seria un código “normal” escrito en Javascript y seguramente confundira a muchos usuarios de JavaScript. Incluso con un lenguaje más “amigable” cómo LLJS seguramente seguirá siendo usando únicamente por desarrolladores avanzados que necesitan optimizar al máximo su código.

Incluso con LLJS, o cualquier otro lenguaje, que pueda permitir escribir código Asm.js “a mano” no habría un DOM igualmente optimizado sobre el cual trabajar. El entorno ideal seria uno donde podamos compilar LLJS y el DOM juntos para crear un único “bloque” en  Asm.js para que corran de forma simultanea. No estoy seguro cual seria el rendimiento de algo así, pero ¡Me encantaría verlo!

Preguntas y respuestas con David Herman

Le mandé algunas preguntas a David Herman (Investigador senior en Mozilla Research) para intentar obtener un poco más de claridad en como funcionan juntas todas estas piezas de Asm.js y como deberíamos esperar beneficiarnos de ellas. Amablemente se tomo el tiempo de responderme en profundidad y darme respuestas excelentes. Espero que las encuentren tan iluminadoras como yo.

¿Cual es el objetivo de Asm.js? ¿A que publico apunta?

Nuestro objetivo es hacer que la web abierta sea una máquina virtual completa, sobre la cual compilar otros lenguajes y plataformas. En esta primer realease, estamos enfocados en compilar código de bajo nivel como C y C++. Más adelante esperamos darle soporte a constructores de más alto nivel como objectos estructurados y recolectores de basura. De esta forma nos gustaría soportar aplicaciones de otras plataformas como la máquina virtual de Java o .NET.

Ya que asm.js esta pensado, en realidad, para expandir las bases de la web, hay un rango muy amplio de público potencial. Pensamos que un grupo que pueden sacar gran provecho de esto son los desarrolladores de juegos que necesitan acceder a todo el poder computacional que puedan. Pero los desarrolladores web son ingeniosos y siempre encuentran formas de usar todas las herramientas que tienen disponible en formas que no habíamos planeado, así que lo que más deseo es que asm.js sea una tecnología que permita todo tipo de aplicaciones innovadoras que no puedo imaginar actualmente.

¿Tiene sentido crear una versión más “amigable” de Asm.js, como una versión actualizada de LLJS? ¿Se planea expandir el proyecto a ser algo más que algo sobre lo cual compilar?

Totalmente. De hecho, mi colega James Long anuncio recientemente que hizo un fork de LLJS que compila a asm.js. Mi equipo en Mozilla Research quiere incorporar el trabajo de James y hacer que LLJS ofrezca soporte oficial para asm.js.

En mi oponion, normalmente vas a querer escribir asm.js a mano en un par de casos muy limitados, como en cualquier lenguaje ensamblador. Normalmente, vas a querer usar lenguajes más expresivos que compilen eficientemente a él. Por supuesto, cuando los lenguajes, como JavaScript, se vuelven muy expresivos, perdes predictivilidad sobre el rendimiento. (Mi amigo Slava Egorov escribio un post muy bueno explicando los retos de escribir código de alto rendimiento en lenguajes de alto nivel) LLJS esta pensado para un puesto intermedio, como un ensamble de C a asm.js que es más facil de escribir que código asm.js crúdo pero que es más predecible en cuanto a optimización que el código JS normal. Pero a diferencia de C, tiene una buena interoperatibilidad con el JS común. De forma que puedas escribir la mayor parte de tu aplicación en código de forma más flexible en JS y concentrarte en escribir solamente las partes más criticas en LLJS.


Hay un nuevo debate entre los browsers que soportan Asm.js y los que no, similar al que ocurrió durante la última carrera sobre rendimiento de JavaScript en 2008/2009. A pesar de que técnicamente el código Asm.js pueda ejecutarse en cualquier lugar, la diferencia de rendimiento va a ser demasiado grande en muchos casos. Dada esta división, ¿por que elijieron compilar a JavaScript? ¿Por que JavaScript en vez de un lenguaje especial o un plugin?

Para empezar, no creo que la división sea tan horrible como vos la menciones: Creamos demos sorprendentes que funcionan muy bien en navegadores actuales pero que se benefician enormemente usando la optimización ofrecida por asm.js

Es cierto que podes crear aplicaciones que van a depender completamente de la fuerte optimizacion de asm.js para que sean usbales. Al mismo tiempo, como cualquier feature nueva de la plataforma web, las aplicaciones pueden decidir tener un comportamiento distinto con algún fallback menos “costoso”. Hay una gran diferencia en aquellas aplicaciones que funcionan con un rendimiento diferente que aquellas que directamente no funcionan.

Tene en cuenta que la carrera por el rendimiento en los browsers que comenzo a finales de la decada del 2000 fue muy buena para la web y las aplicaciones evolucionaron mucho junto con los browsers. Creo que va a ocurrir lo mismo con asm.js.


¿Cómo compararias Asm.js con el Cliente Nativo de Google? Parece tener objetivos similares a pesar de que Asm.js tiene la ventaja de “simplemente funcionar” en cualquier lugar que pueda correr JavaSCript. ¿Han hecho comparaciones en cuanto a rendimiento?

Bueno, el Cliente Nativo es un poco diferente, ya que implica distribuir código ensamlador especifico de cada plataforma; No creo que Google haya pensado en eso como una tecnologia para contenido web (Si no más bien para contenido disponible en el Web Store de Chrome o extensiones de Chrome), o al menos no en el último tiempo.

El Cliente Nativo Portable (PNaCl, Portable Native Client) tiene un objetivo más similar, usando bitcode LLVM independiente de la plataforma en vez de ensamblador puro. Como dijiste, la primer ventaja de asm.js es la compatibilidad con los browsers existentes. Incluso evitamos tener que crear una sistema de interfaz y repetir el trabajo ya realizado para  las web API como lo hace la Pepper API, ya que asm.js tiene acceso a la API existente usando JavaScript directamente. Por último, tenemos la ventaja de que es muy facil de  implementar: Luke Wagner tuvo nuestra primera implementacion de OdinMonkey en Firefox en tan solo un par de meses, trabajando mayormente solo. Dado que asm.js no tiene un gran numero de llamadas al sistema y API y porque esta hecho usando la sintaxis de JavaScript, podes reusar un monton de lo que ya existe para los motores JavaScript y el runtime de la web.

Podemos hacer comparaciones de rendimiento con PNaCl pero llevaria algo de trabajo y estamos más enfocados en achicar la brecha que existe con el rendimiento nativo. Esperamos poder configurar ciertos benchmarks automaticos así podemos mostrar nuestro progreso comparado con los compiladores nativos de C/C++.


Emscripten, otro proyecto de Mozilla, parece ser el principal productor de código compatible con Asm.js. ¿Cuanto de Asm.js es conducido por las necesidades del proyecto Emscripten? ¿Que beneficios obtuvo Emscripten ahora que las mejoras fueron hechas al nivel del motor?

Usamos Emscripten como nuestro primer test case para asm.js como una forma de asegurarnos que tiene lo necesario para ser usado por aplicaciones nativas reales. Y por supuesto que que los beneficios de Emscripten benefician a cualquiera que tenga aplicaciones nativas y quieran portarlas tal como Epic Games, con quienes nos unimos para portar el engine Unreal 3 a la web en tan solo un par de días usando Emscripten y asm.js.

Pero asm.js puede beneficiar a cualquiera que quiera compilar a un conjunto de bajo-nivel de JavaScript. Por ejemplo, hemos hablado con los muchachos que construyeron el compilador Mandreel, que funciona similar a como lo hace Emscripten. Creemos que se pueden beneficiar al compilar a am.js como empezo haciendolo Emscripten.

Alon Zakai Estubo recompilando benchmarks que generalmente corren 2 veces más lentos que los nativos, donde antes veiamos resultados de 5 a 10 o 20 veces. Esto tan solo en nuestra primer release de OdinMonkey, el backend para asm.js del motor JavaScript SpiderMonkey de Mozilla. Espero ver más mejoras en los próximos meses.


¿Que tan fluida es la especificación de Asm.js? ¿Estan dispuestos a agregar features adicionales (como ser, estructuas de dato más avanzadas) a medida que más autores de compiladores apunten a el?

Podes estar seguro. Luke Wagner escribio un roadmap para asm.js y OdinMonkey en la wiki de Mozilla, en donde se discute algunos de los próximos planes. Tengo que decirte que ninguna es fija todavía, pero te puede dar una idea sobre lo que vamos a trabajar más adelante. Estoy muy emocionado por agregar soporte para los objetos estructurados de ES6. Esto podria proveer recoleción de basura ademas de estructuras de datos tipadas que podrian ayudar a compiladores como JSIL que compilan a lenguajes como C# o Java a JavaScript. Tambien esperamos usar algunos de los tipos de valores propuestos para ES7 para proveer soporte para numeros flotantes de 32 bits, enteros de 64 bits e incluso vectores de longitud fija para soportar SIMD.

¿Sera posible, o práctico, tener un transcompilador JavaScript-a-Asm.js?

Seguramente, sí, pero ¿práctico? No estoy seguro. ¿Te acordas en Inception, cada vez que metes un sueño-dentro-de-un-sueño, el tiempo se hacia más lento? Seguramente pasará lo mismo cada vez que quieras intentar correr un motor de JS dentro de sí mismo. Haciendo un calculo rapido, si asm.js ejecuta código nativo a la mitad del tiempo normal, entonces ejecutar un motor de JS en asm.js va a ejecutar código a la mitad de la velocidad normal de ese motor.

Claro que, vas a poder intentar ejecutar un motor de JS en otro distinto y ¿Quien sabe? el rendimiento en realidad nunca es algo tan claro como lo es en la teoria. ¡Agradeceria que algunos hackers intrepidos lo prueben! De hecho, Alex Tatiyants, estudiante de Stanford, ya compilo el motor SpiderMonkey de Mozilla a JS usando Emscripten; Todo lo que tenes que hacer es usar los flags para el compilador de Emscripten para generar asm.js. Alguien con más tiempo disponible deberia intentarlo.


Actualmente, todo el código del DOM o especifico del browser se maneja por fuera de Asm.js. ¿Hay intenciones de hacer una versión del DOM Emscripten-a-Asm.js-compilado (Algo así como DOM.js)?

Esta es una idea estupenda. Quizá sea un poco complicado con la versión preliminar de asm.js que no tiene soporte para objetos. ¡A medida que hagamos crecer asm.js para incluir soporte para los objetos tipados de ES6 algo como esto puede ser feasible y bastante eficiente!

Una buena aplicación de esto puede ser ver que tanto de la plataforma web puede ser autocontenida con un buen rendimiento. Una de las motivaciones detras de DOM.js fue ver si una implementación del DOM escrita puramente en JS puede resolver el problema tracional del manejo de referencias y de memoria entre la pila de JS y el conteo de referencias de los objetos DOM de C++. Con el soporte a asm.js, DOM.js puede obtener estas mejoras de rendimientos más los beneficios de estructuras de dato más optimizadas. Es algo que vale la pena investigar.


Dado que es bastante dificil de escribir Asm.js, en comparación con código JavaScript normal, ¿que tipo de herramientas les gustaria tener para poder ayudar a desarrolladores o autores de compiladores?

Lo primero y principal, necesitamos lenguajes como LLJS, como ya mencionaste, que compilen a asm.js. Y tendremos algunos de los retos comunes de compilar a la web, como mapear el código generado de nuevo al código original en las herramientas para desarrolladores del browser, usando tecnologias como source maps. Me encantaria ver que se mejoren los source maps para incorporar más información de debugging, aunque seguramente habrá una relación costo/beneficio a la que ajustarse entre la información minima que se obtiene de los source maps y la información super compleja de los formatos de metadatos tales como DWARF.

Para asm.js, me parece que me voy a concentrar en LLJS por ahora, pero siempre agradesco ideas de los desarrolladores sobre como mejorar su experiencia.


Supongo que estan abiertos a trabajar con otros fabricantes de browsers ¿Que discución o colaboración a habido hasta ahora?

Por supuesto. Hemos tenido un par de discuciones informales y se han mostrado predispuestos, seguramente tendremos más. Soy muy optimista en que podamos trabajar con varios fabricantes de browsers para tener asm.js en cualquier lugar que podamos implementarlo verdaderamente sin mucho esfuerzo o cambios de arquitectura. Como dije, el hecho de que Luke haya podido implementar OdinMonkey en cuestion de unos pocos meses es muy alentador. Estaria feliz de ver un bug para soportar asm.js en V8.

Pero más interesa que los desarrolladores puedan hechar un vistazo a asm.js y ver que opinan y nos provean su feedback, tanto a nosotros como a otros fabricantes.

Desarrollo web móvil – Inspeccionando webs en dispositivos moviles

Creo que no hace falta aclarar que desde hace, relativamente, poco tiempo los dispositivos móviles (smartphones, tablets) se volvieron una de las principales fuentes de tráfico a sitios web.
Trabajar con los mismos suele ser engorroso, debido a que no contamos con las facilidades que tenemos en los entornos de escritorio.
Sin embargo, en la mayoría de los browsers modernos, es posible utilizar el inspector web de forma remota para poder debuggear nuestra aplicación en tiempo real.
A continuación, voy a recopilar los métodos para activar esta funcionalidad en los browsers más conocidos e iré actualizando el post en caso de encontrar otro browser.

Safari – iOS 6+

Para poder utilizar el inspector web remoto de Safari, necesitamos la última versión de este browser para escritorio, la cual no esta disponible para ninguna otra plataforma ademas de OSX (que novedad ¿no?)

Activar el inspector en iOS

Debemos dirigirnos a Settings -> Safari -> Advance y habilitar la opción Web Inspector

Activar la inspección remota en Safari

Abrimos las settings de Safari (cmd + ,) vamos a la pestaña Advance y marcamos Show develop menu in menu bar.

Ahora vamos a ver un nuevo menú en la barra superior llamado Develop.  Abrimos el sitio que queremos inspeccionar en el dispositivo iOS con Safari, hacemos click en ese menú y vamos a ver una opción con el nombre del mismo. Dentro veremos una lista de los sitios inspeccionables que tenemos abiertos. Clickeamos en él y tendremos el inspector abierto, pudiendo hacer (casi) todo lo que hacemos con el inspector web de Safari en el escritorio.

Firefox – Android

Para hacer esto, necesitamos Firefox 15+ (Tanto en nuestro escritorio como en Android)

Activar el inspector en Android

Abrimos Firefox , vamos a about:config y cambiamos las siguientes settings:

devtools.debugger.force-local -> false

devtools.debugger.remote-enabled -> true

Reiniciamos el browser (normalmente basta con apretar Home en nuestro dispositivo, pero puede que necesitemos Matar la aplicación usando algún task manager.

Activar el debugging remoto

Abrimos Firefox, en el dispositivo Android, vamos nuevamente a about:config, y cambiamos:

devtools.debugger.remote-enabled -> true.

Reiniciamos el browser y ahora podemos activar el debugger remoto desde el menu  Web developer.

Tenemos que indicar la ip de nuestro teléfono y el puerto (por defecto, 6000.  Se puede cambiar mediante la opción devtools.debugger.remote-port en about:config, desde el dispositivo.)

Chrome – Android

Para esto, necesitamos descargar el SDK de Android.

Habilitar el debugging web

Abrimos Chrome en nuestro dispositivo Android, vamos a Settings -> Developer Tools y marcamos Enable USB web debugging.

Forwardear las conexiones al puerto del debugger

Conectamos mediante USB nuestro dispositivo y nos aseguramos de tener activada la opción USB debugging dentro de las Developer options.

En nuestro escritorio, dentro de la carpeta que contiene al SDK de Android, vamos a ver otra llamada platform-tools y dentro un programa abd.

Ejecutamos: adb forward tcp:9222 localabstract:chrome_devtools_remote

Inspeccionar

Abrimos Chrome en nuestro escritorio y vamos a http://localhost:9222 ahí veremos una lista de las pestañas abiertas en el dispositivo.  Al hacer click en una de ellas se abrirá la ventana del inspector y podremos comenzar a trabajar.

Opera Mobile

Activar DragonFly en el escritorio

Abrimos Opera y vamos a Tools -> Advance -> Opera dragonFly en el menú superior.   Luego buscamos el icono de Remote debugging configuration en el panel de DragonFly, seleccionamos el puerto y hacemos click en apply.

Conectar el dispositivo

Abrimos Opera Mobile e introducimos opera:debug en la barra de direcciones. Luego debemos ingresar la ip del escritorio donde tenemos corriendo Dragonfly y el puerto. Una vez hecho veremos la confirmación de que la conexión se realizo de forma exitosa.

Hecho esto, podemos abrir cualquier url y seleccionarla mediante el icono de debugging context en Dragonfly.

Fuentes:

Curiosidades de javascript: Valores primitivos, null y undefined

Es normal escuchar a muchos desarrolladores decir que en javascript todo es un objeto. Esto en realidad es un malentendido, puesto que existen los llamados valores primitivos, strings, números y booleanos, además de dos valores especiales null y undefined

Veamos los valores primitivos. En principio, uno pensaría que son objetos, ya que podemos sin ningún problema acceder a algunos métodos de los mismos.

A primera vista, la variable foo (y por tanto, el string “bar”) es un objeto. Sin embargo, esto no es cierto. Lo que ocurre es que javascript envuelve los valores primitivos con objetos cada vez que queremos acceder a algún método y/o propiedad de los mismos. Dicho objeto, es destruido luego de la operación.

Intentar asignar 5 a la propiedad num de foo no arroja ningún tipo de error, puesto que al intentar acceder a dicha propiedad foo es envuelto en un objeto, pero luego este es destruido, por lo tanto, foo.num toma el valor undefined.

El tipo de objeto usado para envolver los valores primitivos, depende del tipo de valor. Así, los strings son envueltos por objetos String(), los numéricos por Number() y booleanos por Boolean().

Por último, no hay que confundir un valor primitivo string con un objeto del tipo String (creado mediante new String()), a pesar que puedan comportarse de forma similar (lo mismo ocurre para otros tipos de valores)

Veamos ahora que ocurre con los otros dos tipos de valores que no son objetos, undefined y null.

Cuando declaramos una variable (y no le asignamos ningún valor) esta posee el valor undefined. También es el valor que devuelve una función que no devuelve ningún valor explícito.

De acuerdo al standard Ecmascript 5, undefined es un valor primitivo de tipo undefined. Es decir, así como {false, true} son los posibles valores del tipo booleano, undefined es el único valor posible del tipo undefined.

Algo similar ocurre con null, ya que es el único valor posible para el tipo de datos null. Se utiliza para representar la ausencia intencionada de un valor. Es decir. Una variable va a valer null únicamente si es asignado de forma explícita.

Es importante tener en cuenta que ocurre al momento de comparar null o undefined con otros valores, ya sea porque utilizamos el operador == (en lugar de ===) o bien porque intentamos operar con valores de distinto tipo (Ej: 3 + null).

Cuando es evaluado como booleano, ambos devuelven false.

Al momento de intentar evaluarlos como número, undefined es evaluado como NaN

null, en cambio, es evaluado como 0+.

Por último, al intentar evaluarlos como string, cada uno equivale al string “undefined” o “null” respectivamente.

Hay que destacar que undefined es, también, una propiedad del objeto global (window, en los browsers) cuyo valor es undefined. De acuerdo al estandard Ecma, undefined es una variable que no puede ser escrita.
Sin embargo, en browsers antiguos (Ej: Firefox anterior a la versión 4) esto no era así y podíamos asignar cualquier valor a dicha propiedad, por lo que debemos tener esto en cuenta si pretendemos soportar dichos browsers.

Como última mención, podemos ver que si aplicamos el operador typeof, ocurre lo siguiente:

Es importante notar que null es tomado como de tipo object a pesar que si intentamos acceder a una propiedad de una variable null o undefined recibiremos un error de tipos.

Bitacora #2: Tile.js generator

Dejando los posts sobre cosas curiosas de javascript para más adelante, cuento un poco sobre una pequeña utilidad que arme para usar en el port del gorillas.

Se trata de un simple generador de tiles para usar sobre un contexto 2d.
Dado que el juego original no utilizaba imágenes, me pareció que no seria correcto hacer un clon que sí las use, por lo que pensé en dibujar los elementos del juego (gorilas, edificios, bananas y el sol) con primitivas del contexto 2d.

Como seria bastante engorroso imaginarme donde tendría que poner cada punto, se me ocurrió hacer una ‘pizarra’ en la que se dibuje cada punto que selecciono. Estos se van guardando en memoria para luego obtener una función con el código para dibujar dichos puntos.

Para manejar de forma ‘elegante’ la orientación a objetos en javascript, use la libreria Base.js. Esta provee de una serie de objetos y métodos que hacen que la herencia y la creación de ‘clases’ sea más llevadero.
El resto del código, consiste en una clase con un ‘canvas virtual’ que lleva registro de los puntos que fueron dibujados para luego obtener el código de cada uno (tanto la clase ‘canvas’ como la clase ‘dot’ saben como obtener su código).
Ademas, al momento de obtener las funciones, se puede especificar un ‘multiplicador’ para reducir el tamaño de los puntos, de esta forma se puede dibujar en grande y de forma comoda, para luego disminuir el tamaño.

Ejemplo:

Tile Generator

Dibujamos esto...

 

 

Drawed gorilla

y obtenemos la función para dibujar esto...

El script es bastante sencillo y carece de buenas prácticas, pero es útil para lo que necesito en este momento.

Para verlo en acción: http://tehsis.com.ar/tilegen/
Repo en github: https://github.com/tehsis/Tile.js-Generator

En el futuro espero hacerlo extensible a primitivas distinta a los puntos (rectángulos en realidad) y poder dibujar otras cosas. No seria complicado, pero ahora la prioridad es el gorillas :D.

Dejo un par de links interesantes,

Base.js – Mini librería para trabajar con objetos, clases, herencia, etc de forma ‘clasica’
Load.js – Mini librería para ‘importar’ scripts js mediante código.
10 Things I learned from jQuery source – Video de Paul Irish contando 10 técnicas interesantes que estan presentes en el código de jQuery.
Tutorial del elemento Canvas (MDC) – Lindo y llevadero tutorial del MDC sobre la etiqueta canvas y el contexto 2d.