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)

Leave the first comment

Mate

Me despierto temprano y me intentó levantar. El reto era no volverse a dormir, algo que de forma muy sencilla podía fallar.

Cargar la pava eléctrica con un poco de agua, poner el polvo del café en el tarro con filtro. Suena a mucho trabajo para estas horas de la mañana, podría decirse, mucho esfuerzo mental.

De la pava salía vapor, es una suerte que deje de calentar al hervir el agua, de otra forma, hubiese sido un desastre el momento que me volví a dormir por media hora. No fue mi culpa, del todo, mi cuerpo dejo de responderme cuando me senté en mi cama. Mi departamento es chico, no me puedo alejar de ella.
Tome la yerba de un tarro y la coloque dentro del mate. Es mucho trabajo usar la cuchara. Entonces había yerba en el piso, pero eso no sería un problema hasta más adelanté.por ahora, sólo quiero tomar mate.

Servir un poco de agua caliente, sobre la yerba, alrededor de la bombilla torpemente colocada. Sorber despacio la primer sebada. Sentir ese gusto amargó entrando en mi cuerpo, penetrando mis sentidos. Mi cabeza comienza a despejarse, mi estómago a calentarse. Mis ojos se abren mientras mi lengua siente ese gusto amargo, formado por una yerba de buena calidad, además de la madera del porongo, que a base de antiguos mates, fue adquiriendo un sabor particular.

Mi cuerpo lo pidió y mi mente asintió. Era hora de comenzar aquel día.

Leave the first comment

Lo vivido en el Mozilla Summit 2013, dese mí punto de vista

Durante la semana pasada, tuve la oportunidad de asistir al evento más importante de Mozilla en este año. El Mozilla Summit 2013. Evento que se realizo en simultaneo en las ciudades de Toronto, Brusselas y Santa Clara y al que asistieron directores, empleados, contribuyentes, miembros de la comunidad y otro público relacionado con todo lo que es Mozilla.

No voy a intentar hacer una crónica, si no más bien contar que fue y que me dejo este evento que fue, literalmente, una voladura de cabeza ;)

Todos en el mozfest

La previa

Decir que el evento comenzo el 4 de Octubre, seria dejar afuera todo el trabajo que hizo la gente de Mozilla para organizar el viaje y atender a todos los asistentes de cada una de las locaciones y tener todo preparado para que durante los 3 días ‘efectivos’ del evento se lleven a cabo de la mejor manera posible y que se le pueda sacar el mayor provecho.
Partimos desde Argentina el miercoles 2, junto con otros miembros de la comunidad de Argentina, rumbo a Sao Paolo, Brasil.

En aeroparque

Ahí nos encontramos con miembros de las diferentes comunidades de todo Latinoamerica y ya empezo a sentirse el lio de idiomas, que luego seria una moneda corriente. Sin embargo, mediante Ingles, Español, Portugues y diferentes mezclas de estos tres lenguajes podiamos entendernos y empazabamos a compartir algunas esperiencias y expectativas de lo que se serian los próximos días.

Recien llegados

Una vez en Canada, fuimos recibidos de una manera excelente, con personas designadas por Mozilla para dicha tarea, las cuales nos llevaron hasta el hotel en donde nos encontramos con más gente.
Como el Summit comenzaba al día siguiente, con algunos miembros de Mozilla Argentina, decidimos aprovechar y conocer las famosas cataratas del Nyagara.

Niagara

Una vez de vuelta, tuvimos una cena de bienvenida y ya pudimos empezar a intercambiar algunas ideas con personas de todo el mundo. Ya era comun sentarte un rato a hablar con un miembro de la comunidad de Taiwan que traducía Firefox en su idioma y al rato estar hablando con un empleado de Grecia que trabajaba en las Herramientas de desarrolladores o un japones que trabajaba en un colectivo que recorria las ciudades enseñando a los chicos a usar la web y/o ayudar brindando internet en lugares con desastres naturales.

variada

Día 1: Qué hace que Mozilla sea Mozilla

Al comenzar el evento Mitchell Baker, CEO de Mozilla realizo la primera de muchas charlas y quizá una de las principales, pues englobaba mucho de lo que vino despues. Una charla que dejo en claro todo lo que representa Mozilla y el rol que tiene en el mundo de hoy. Lo que representa la comunidad y la compañia que la soporta, a donde nos estamos dirigiendo y el trabajo que falta por hacer.

Mithcell Baker

Apenas despues de esta charla (y del gracioso video de The Fox), Jay Sullivan, COO de Mozilla, nos presento la visión de la compañia a futuro, sus objetivos y planes a largo plazo, en un mundo donde aún más la mitad de la población no posee acceso a internet y donde muchas de estas personas Tienen su primer contacto con internet a través de dispositivos móviles.

5.6 billiones proyectados

La charla finalizo con Jonathan Nightingale (VP de Firefox) y una impactante demostración de lo que se esta haciendo con Asm.js y emscripten. Técnologias que permiten llevar juegos de cálidad AAA a la web. En realidad, fue más que una demo. Pero me quedo con la frase que dió su presentador: “Dijeron que Javascript nunca seria bueno y acá estamos.” – Obviamente un JS fan como yo la recibio con aplausos ;)

unreal

Finalizando la mañana, vino uno de los eventos más divertidos y a la vez interesantes. El “World Fair” o “Feria mundial”, en donde cada uno de los miembros de los países que asistieron, mostraron un poco de su cultura y sobre lo que estaban trabajando.
Durante la feria, pude aprender a escribir Firefox en Chino, disfrutar de algunos snacks de otros paises, conocer los problemas de traducir Firefox a idiomas distintos a los occidentales (particularmente, el Pakistaní que tiene orientaciones de escrituras y géneros medio raros).
Durante esta parte, conocí acerca del Mozbus. Un proyecto de la comunidad Japonesa, en el que tienen un autobús donde enseñan a niños a usar la web, los hacen jugar con algunas webapps en las que pueden imprimir su contenido en una impresora 3d y donde el autobús, ademas, puede ayudar en desastres naturales ya que posee equipamiento para tener internet y energía en cualquier lugar. Definitivamente los Japoneses son de otro mundo.

chino

Durante la tarde, pudimos asistir a las Open Sessions. Espacios en los que se trataba, entre todos los participantes, sobre un tema particular. Yo participe en una sobre el futuro de FirefoxOS estandarización y en otra sobre Enyo.js, donde ademas de conocer este interesante proyecto (nacido a partir del difunto WebOS) pude intercambiar experiencias sobre el desarrollo de webapps con personas de Brasil e Inglaterra desde el desarrollo de juegos hasta ux y enterarme de los proyectos personales de varios asistentes. Algunos, muy interesantes. Sin embargo, destaco más algunas otras sesiones más interactivas que se llevaron a cabo ese día.

Open Session sobre FirefoxOS

El día finalizo con una cena que incluyo una sesión de preguntas y respuestas por parte de varios representantes de Mozilla. Las preguntas fueron enviadas y votadas por los que asistimos. Despejaron muchas dudas respecto a la relación de Mozilla con sus comunidades, el futuro de FirefoxOS y de la fundación en general.

Preguntas

Finalmente, tuvimos Karaoke, un momento muy divertido que en un momento de desestructuro y terminamos todos cantando y saltando arriba del escenario principal. Esta vez, fue la música, aun con las extrañas variaciones de letras que se escuchaba lo que sirvio de puente para unirnos.

Firefox Hielo

Día 2: Crecimiento, colaboración e innovación

El día comenzó con una keynote de Jim Cook y John Jensen con datos muy interesantes sobre la penetración de internet a nivel mundial. Se volvió a hacer foco en el hecho de que muchas personas tienen su primer contacto con la web a través de un dispositivo móvil.

Luego, Johnatan Nithingale introdujo Australis, la nueva interfaz de usuario de Firefox, importantes avances sobre FirefoxOS y otros proyectos de Mozilla, como Shumway, que nos permite correr flash mediante js, Web Runtime, una increible mejora en las webapps para que podamos integrarlas aún más al sistema operativo en las que fueron instaladas, App Maker, para hacer aplicaciones de forma visual, mejoras en las devtools e integración con App Manager. Para más información sigan los links de cada tema ;)

Australis

Al medio día tuvimos la llamada “Innovation Fair”, donde se pudieron ver cosas increíbles tanto de Mozilla como de terceros. Quizá lo que más me llamo la atención fue ver a Banana Bread y juegos AAA funcionando enteramente en web y con multiplayer ‘directo’ mediante WebRTC y algunas implementaciones sobre el draft de HTTP 2 que realmente mejora y mucho todo el stack de las aplicaciones y sitios web.

La cantidad de proyectos que ahí se presentaban era muy interesante y de todos tipos, algunos orientados al desarrollo, otros al periodismo, a la asistencia para personas con discapacidad, FirefoxOS en computadoras “todo en uno”, etc. Supongo que cada asistente habrá encontrado distintas cosas que le llamaran la atención.
En lo personal, me llevo una charla que tuve con uno de las ingenieros de las Herramientas para desarrolladores de Firefox. Una de las features a la que más empuje le están metiendo últimamente y que más me apasionan.

innovation

Durante la tarde, nuevamente en las sesiones abiertas, participe de una relacionada al Mozilla Developer Network, o MDN. Lugar en el que colaboro actualmente. En esta sesión vimos distintas formas de colaborar, ya sea escribiendo artículos, editandolos o haciendo revisiones técnicas y/o editoriales. Durante la misma hicimos “trabajo de verdad” y no solo que encontramos algunos problemas si no que tambien solucionamos otros. Sin duda, una muy buena experiencia al lado de gente muy grosa como Chris Mills.
Tambien asisti a otra sobre Servo, ún motor web multihilo y realmente prometedor. Dejando en claro que estábamos asistiendo al futuro de la web durante el evento.

Servo

La actividad social de la noche fue una visita a la torre CN, una de las más altas del mundo y compartir algunos tragos en diversos pubs de Canada, supongo que a los transeuntes que nos cruzabamos en el camino les habrá resultado raro ver tanta gente “disfrazada” de Mozilla y hablando, a la vez, en varios idiomas.

cntower

Día 3: El futuro

El último día ocupamos la mañana dividiéndonos en distintas áreas (yo participe en la de Cloud) en donde trabajamos para lograr nuevas ideas que mejoren distintos proyectos de Mozilla. Nuevamente me encontré en un grupo muy heterogéneo, en donde cada uno pudo aportar disntas cuestiones que le interesaban de ‘la nube’. Seguridad, estandarización, integración con otras plataformas, etc.

Cloud

En las sesiones abiertas participe en una sobre videojuegos. En donde pude aprender algunas cosas sobre el proyecto Shumway, que como ya mencione, es un runtime de flash desarrollado en js e integrado al browser. Lo bueno, pudieron hacer andar, sin modificaciones, importantes juegos populares desarrollados en esta plataforma y dan soporte a una comunidad de desarrolladores de video juegos tan grande como la de Flash. Lo malo, Flash.
Personalmente, en este tema me interesaron más los avances obtenidos en la dupla emscripten y asm.js. Es increible lo que se gano en performance en el último tiempo. Logrando velocidades por debajo de Java y no tan alejadas de las logradas mediante implementaciones “nátivas” en C++.
Ademas de la performance, asm.js ya funciona en dispositivos móviles, por lo que se pudo ver a Banana Bread y otros juegos funcionando en tablets.

Juegos

A la noche, las clásicas palabras emotivas, repasos de lo que fue el summit y fiesta de despedida.

Conclusión

La comunidad de Mozilla es enorme y muy diversa, esto quedo muy reflejado en este evento. Y es increible lo que todo este equipo puede lograr, aún cuando todos puedan tener objetivos “finales” diferentes.
La web esta creciendo cada día, una plataforma nacida desde lo abierto y que se supo imponer a otras soluciones y perdurar gracias a esto. Hoy la web es todo, un medio de comunicación abierto y plural, una plataforma excelente para desarrollar aplicaciones y con competidores que logran cosas increibles como permitir el desarrollo de video juegos complejos y de alta calidad en la misma.
Este mounstro sin duda todavía no esta exprimido del todo, sigue creciendo y espero que pueda imponerse definitivamente y espero poder seguir dando mi granito de arena para que pueda mantenerse abierto y sin ataduras como lo es hasta ahora.

Imagine

Leave the first comment

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’);

4 comments so far, add yours

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
2 comments so far, add yours

Corto: Tener un server para archivos estáticos en 1 minuto

  1. Asegurarnos de tener nodejs y npm instalados
  2. Crear un archivo index.js con el siguiente contenido:
  3. Ejecutar npm install express
  4. Ejecutar node index.js
  5. ¡Listo! Podemos probar poner un archivo index.html en la misma carpeta y luego ir con un browser a http://localhost:3000 o cualquier archivo.ext y traerlo mediante http://localhost:3000/archivo.ext.
5 comments so far, add yours

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.

Leave the first comment

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.

One comment so far, add another

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:

5 comments so far, add yours

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.

One comment so far, add another