Quality Assurance en Mercadolibre

16/05/2017
Artículo original

Hola a todos, como hice en el pasado con el equipo de APIs de Mercadolibre, la idea hoy es contarles qué hacemos en el equipo de QA para ver si tiene ganas de trabajar con nosotros, ya que estamos en la búsqueda constante de talentos :)

Antes que nada, al equipo de QA en Mercadolibre lo llamamos Business Assurance (BA), ya que tiene una responsabilidad un poco más amplia que lo normal, es el equipo encargado de que el negocio funcione en su totalidad.

Como todos saben, hacer un sistema de forma poco profesional, es como decirle a un arquitecto que arme la “Cucha” para el perro o la “Casita del árbol”, no requiere demasiado control de calidad, metodología, métricas, certificaciones, etc. Ahora bien si le pedimos al mismo arquitecto hacer un puente o un “Empire State”, se complica la cosa y va a requerir de cálculos, planos, mediciones, certificaciones y equipos electrónicos para detectar todo tipo de posibles fallas.

image

En sistemas es lo mismo, hacer la página del kiosco es fácil, hacer el site de internet más grande de América Latina tiene un poco más de profesionalismo. No estamos al nivel del software de un Boeing 737 pero cerca :)

Dicho eso, en Mercadolibre creemos que un proyecto consta de un 50% de esfuerzo en programación y un 50% de “otras cosas” que lo vuelven profesional, que obviamente cuestan el doble de esfuerzo, pero a la larga, valen la pena.

¿Y que son esas cosas? Todo lo perteneciente a calidad:

image

Lo que hacemos en QA en ML es asegurarnos que todo ese bloque de cosas que dicen “Calidad” se cumplan en los proyectos. Somos un grupo de ingenieros en sistemas que en vez de tener un foco en desarrollar funcionalidades nuevas al producto, nos encargamos de hacer que ese producto se realice de la mejor forma (más profesional) posible.

image


Para eso, en el equipo nos dividimos en varios centros: Buenos Aires, Córdoba, San Luis, Santiago de Chile y Montevideo, Uruguay y en diferentes células que atacan diferentes problemáticas del desarrollo de software (Testing, SRE, Web Analytics, GIN, Seguridad). En total somos hoy 60 personas.

¿Qué hace cada célula?

Testing: El equipo de Testing, se encarga de asegurar que la aplicación esté probaba de inicio a fin. Para eso ayudan a los desarrolladores de los proyectos a definir la estrategia de testing, crear test unitarios, test de integración, test funcionales, test end to end, etc. Mantener la arquitectura de integración continua, miden la cobertura de código (en desarrollo y producción) y realizan análisis estático de código (Para encontrar malas prácticas de programación). El equipo de testing es clave para que el producto (la página de Mercadolibre o Mercadopago o sus aplicaciones de celulares) llegue a producción sin bugs, probado de punta a punta y muy fácil de modificar.

image

(Ingeniero testeando el telescopio Gaia antes del lanzamiento)

Resiliencia o SRE: El equipo de SRE es otra célula de BA y es la encargada de asegurar que la aplicación es “a prueba de fallos” a nivel tráfico, hardware, problemas con el cloud, etc. ¿Qué significa esto? Nuestra aplicación es tan pero tan grande, que consta de cientos de sistemas interconectados, estos sistemas corren sobre más de 30 mil servidores, procesan más de 40 millones de pedidos por segundo y a velocidades diferentes (desde 1 milisegundo hasta varios segundos, con mucha variación). Es muy normal que alguno de esos servidores o parte de la red, o parte de los discos falle. Cuando alguna parte falla, el resto de los sistemas tiene que soportar ese error, sino el sistema entero se vendría abajo, a esto es lo que llamamos “resiliencia” de una aplicación. Las aplicaciones tienen que poder soportar todos estos errores en tiempo real. Para eso los ingenieros de SRE se encargar de medir la aplicación por todos lados: CPU, tiempo de respuesta, memoria consumida, etc, Analizan la interconección de las mismas, detectan errores de tuning, promueven mejoras en las arquitectura, mejoran las alertas que el sistema genera, aseguran que cada parte que se puede romper esté monitoreada, analizan los problemas de escala en producción, etc. El equipo de resiliencia también es clave en Mercadolibre, gracias al  esfuerzo de este equipo, el sitio tiene cada vez más uptime.

image

(Nuestro meme por default en SRE)

Analytics: El equipo de Web Analytics se encarga de medir y entender el comportamiento de los usuarios que navegan el sitio. ¿Qué significa esto? Implementan distintas herramientas (Por lo general Google Analytics) para ver qué parte del sitio es el más usado, qué parte es el menos usado, qué parte no se entiende y hay que mejorar, qué parte del sitio tiene el mayor drop-out (cuando el usuario deja el sitio), etc. Se encarga de generar todo tipo de métricas para que el sponsor del proyecto (por ejemplo el gerente de marketing) entienda a la perfección en donde hay que poner más foco para hacer que la gente compre o venda más. Además de esto realizan A/B testings y capacitan al resto de las áreas de Mercadolibre para que todos puedan hacer uso de esta información super valiosa. Las áreas de negocio aman a este equipo, tener información detallada de cómo el cliente usa tu producto es clave para mejorarlo :)

image

GIN (Gestor de incidentes): El equipo de GIN tiene un rol clave en la empresa, es el puente de comunicación entre los usuarios del sitio y el equipo de ingeniería. ¿Cómo es esto?. Cuando un usuario tiene un problema, una duda, una queja, etc. Se comunica con nuestro call center. En el call center ayudan al usuario, pero muchas veces el call center detecta que lo que el usuario reporta es un error en la aplicación (un Bug). El equipo de GIN es el que se encarga de gestionar esos bugs reportados, para que los mismos se solucionen. ¿Cómo hace esto? El bug llega el equipo de GIN, los analistas del equipo lo reproducen, entienden del problema, lo asignan a un equipo de desarrollo y realizan el seguimiento del mismo hasta que el equipo de desarrollo lo corrija. Estiman cuánto dinero se pierde por día con este Bug, calculan cientos de métricas para saber cuál es el bug más importante a resolver, brinda visibilidad del problema a los gerentes del call center y de desarrollo y además capacitan al equipo de call center para que entienda a la perfección qué cosa es un error, que cosa no es un error y pueda bajar le carga operativa del área, todo esto contra reloj.

image

Web Security: El equipo de seguridad aplicativa, si bien no es parte de BA, lo consideramos como un equipo que da soporte para detección de vulnerabilidad en el sitio. Cualquier hacker podría dejarnos fuera de la copa si encuentra una vulnerabilidad que por ejemplo borre nuestra base de datos, el equipo de seguridad se encarga de analizar constantemente con ayuda de distintas consultoras de seguridad cuáles son nuestros puntos vulnerables y seguir junto al equipo de desarrollo la corrección de las mismas.

image


Todos los equipos además tienen un rol de programación, ¿Por qué?

En Mercadolibre pasan cosas que, por la cantidad de tráfico, no pasan en otras empresas, con lo cual nos vimos obligados a desarrollar nuestros propios sistemas de “Healing”, o dicho en criollo: Tuvimos que programar sistemas para detectar inconsistencias, medir nuestro propio Cloud, obtener métricas de deploys, verificar el historial de cambios, etc.. Esto también lo hizo el equipo de BA ayudando al equipo de desarrollo.

image

Todas las áreas realizan meetups para la comunidad regularmente, es parte de su rol estar a la vanguardia de las tecnologías y fomentarlas en la comunidad. 

Les dejo el link de la charla que di en el meetup de TestingAr sobre herramientas custom de testing que hicimos en la empresa.

En resumen,  entre todas las células, damos soporte a todo el ciclo de vida de desarrollo, para que el mismo sea lo más robusto y perfecto posible.

image

En todas estas células buscamos profesionales que quieran ayudarnos a mejorar la calidad del sitio, en todo sentido.

Los puestos que tenemos disponibles son (Entre paréntesis la experiencia estimada):

  • Ingeniero Junior            (Ninguno o 1 año de experiencia)
  • Ingeniero                       (Entre 1 y 3 años de experiencia)
  • Ingeniero Semi-Senior  (Entre 3 y 6 años de experiencia)
  • Ingeniero Senior            (Más de 6 años de experiencia)
  • Líder de Proyecto / Líder Técnico (Coordinadores de equipo o referentes técnicos)
  • Gerente / Experto Técnico (Coordinadores de varios equipos o referentes técnicos)

Dentro de los cuales, como puede verse,  hay puestos técnico especialistas, generalistas y de coordinación de equipos. Por lo general buscamos profesionales de sistemas, pero no es excluyente (depende la célula), sí,  tienen que tener conocimiento de programación, bases de datos, redes, etc. (También depende la célula, hay algunas más técnicas que otras).

image

Si tenés ganas de formar parte de alguno de los equipos de BA, te invito a que me envíes un mail a fersca@gmail.com así lo evaluamos y te invitamos a una entrevista de trabajo a alguna de nuestras oficinas.

Saludos,

Fer

FRIKADAS: la propuesta de matrimonio más "geek" de la historia

12/05/2017
Artículo original

Lo que os vamos a contar hoy no lo supera ni la más rebuscada escena de película romántica de Hollywood...

Lo más normal si alguien le pide matrimonio a su pareja es que, como mucho, se arrodille en plan hortera y le ofrezca una cajita abierta con el anillo y un buen pedrusco, mientras hace la pregunta del millón. Luego el resto de comensales del restaurante gritan "vivan los novios" y suena una música empalagosa... Lo dicho, Hollywood total ?

Sin embargo para David Hoskins, un desarrollador de UX de Reino Unido, algo tan convencional quedaba fuera de toda duda. Quería hacer algo mucho más espectacular, y sobre todo "friki". Así que estuvo preparando el gran momento durante casi un año y creó "The Box".

El dispositivo (creado usando Arduino como "cerebro") era una caja que, para que la prometida pudiera abrirla debía resolver una serie de desafíos y acertijos de diverso tipo: un puzle de imágenes, un acertijo con audio, una prueba de resistencia (con truco, aun encima) usando un bici conectada al chisme... incluso un juego de medir pesos utilizando jarras de agua que si eres fan de la saga "Jungla de Cristal" seguro que conoces.

El dispositivo hacía uso de una serie de tecnologías que usaban varios Arduino para conectar dispositivos físicos y detectores varios para guiar a la novia hasta la caja y poder abrirla al final, a medida que superaba cada una de las pruebas.

Aunque las pruebas eran rebuscadas, el "truco" estaba en que David estudiaba UX e interacción con el usuario en ese momento, por lo que se aseguró de que cada prueba estuviera "testeada" de cara al usuario antes de la proposición real, verificando que era usable, se entendía y se podía superar con un poco de habilidad.

En su blog de LinkedIn nos cuenta con todo lujo de detalles cómo llevó a cabo el proyecto, qué pruebas había, cómo montó todo el tinglado... Un friki de los de tomo y lomo, vamos. Asúmelo: nunca en tu vida vas a superar esto.

También es necesario decir que la buena de su prometida debe de ser alguien muy especial para no haberlo mandado a paseo, ya antes de llegar a la tercera prueba. Pero ya se sabe lo que dice el refranero popular: Dios los cría y ellos se juntan...?

Checklist para liberar un proyecto Open Source en Github

10/05/2017
Artículo original

Github Liberar Proyecto

Github nos permite liberar cualquier proyecto en el que hayamos estado trabajado en privado. En ocasiones, nuestra intención es simplemente compartirlo sin más pretensiones como un pet project o como ejemplo de alguna kata que hemos estado preparado. Pero cuando queremos comenzar un proyecto Open Source un poco más serio, como una librería que queramos compartir con el resto de desarrolladores, quizás debamos pararnos a pensar un poco más antes de publicar nuestro código en Github si cumple una serie de pasos previos.

Vamos a repasar una serie de puntos interesantes para cualquier proyecto Open Source. Un pequeño checklist de recomendaciones, desde la visión tanto de un maintainer de proyectos de software Open Source como de un desarrollador que se encuentra un proyecto en Github y quiere usarlo.

Razones por las que liberar tu código como Open Source

Hay muchas razones por qué un desarrollador u organización querría hacer Open Source un proyecto. Algunos ejemplos para ilustrar la situación sería:

  • Pura colaboración. Quizás estemos desarrollando un proyecto por nuestra cuenta, lo hayamos mencionado en algún grupo de slack o meetup de desarrolladores, y nos lancemos a hacerlo abierto para que el resto de desarrolladores sean contributors ayudándonos a avanzar.
  • De forma individual simplemente buscar hacer público alguno de tus pet project. De esta forma la gente verá cómo programas y encuentres futuras colaboraciones.
  • Transparencia: Existen muchas instituciones que ven el Open Source como la forma de hacer público en lo que están trabajando para que cualquiera pueda revisarlo sin problema.

Deja claro el objetivo, las expectativas y cómo utilizar/colaborar

Hacer público un proyecto open source es sólo el principio

“Release early, release often” es una de las frases más repetidas cuando pensamos en liberar un proyecto software. Hacer público un proyecto open source es sólo el principio. Por ello, lo primero que debemos hacer es dejar claras las expectativas a cualquier desarrollador que se encuentre con él.

Fundamentalmente necesitamos clarificar lo máximo posible los siguientes puntos:

  • El objetivo del proyecto. ¿Qué es? Por ejemplo: una kata, una librería, un framework en construcción, etc..
  • Las instrucciones y dependencias que necesita para ser ejecutado
  • Un changelog accesible sobre los cambios de versiones y las versiones disponibles.

Checklist de tareas antes de liberar un proyecto Open Source

El clásico README

Es el lugar principal y donde cualquier desarrollador irá a buscar información. Debe estar localizado como un fichero de texto markdown en la raíz del proyecto. Github hace especial énfasis de que cada proyecto cuente con su correspondiente README.

Revisa el nombre Quizás el nombre sea lo primero que creaste, al menos, cuando le dedicaste horas de trabajo en privado, pero ahora que va a ser público debes asegurate que antes de lanzarlo no entra en conflicto con ninguno ya existente y ni mucho menos con alguna marca registrada.

Añade una descripción al proyecto Debemos explicar el objetivo, las motivaciones por las que existe este proyecto. También debemos enumerar las características del proyecto, incluyendo sus funcionalidades.

Cómo debo usarlo o integrarlo Si nos encontramos con un nuevo proyecto, lo más razonables es poder ser capaces de instalarlo, hacerlo arrancar o integrar en nuestra aplicación. Así que es fundamental que buena parte del README se trate de explicar las dependencias y las instrucciones para poder usarlo/integrarlo. Y no te olvides de explicar los test de los que cuenta, seguro que alguien que quiera probar su integridad o colaborar le será de ayuda lanzar los tests antes de crear una build desde el código.

Facilita la forma de descargar el artifact o la build Lo más habitual es que hayamos usado algun gestor de dependencias o un sistema de construcción del proyecto, ya sea con node, maven, gradle, makefile, etc… así como que el binario del proyecto se pueda descargar de algún lugar como maven central o con un sencillo npm.

Automatiza todo lo que puedas Es fundamental que a parte de que lo expliques en el README cuentes con un sencillo script que facilite la vida a los desarrolladores que quieran construir por ellos mismos la build. Usa bash, gradle, ant, maven, npm, etc.. para tu proyecto.

No te olvides del marketing Aprovecha para incluir algun logo o imagen que represente tu proyecto, nunca se sabe cuando alguien quiere hablar de él quizás, algún blog. Incluir un imagen representativa de tu librerías nunca es mala idea. Y si no lo tienes claro, piensa en los animales de la portadas de los libros de O’Really.

Añade una licencia

Liberar algo al público se debe hacer con cuidado. Revisa los componentes que utilizas y decide una libería acorde a tus intenciones y que cumpla los requisitos de tu proyecto. Entre las más populares se encuentran la Apache 2, MIT o GPL. Si te lías con los derechos y obligaciones que implican puedes consultar alguna recomendaciones de Github o alguna de estas webs: Choose a License o TLDR Legal.

¿Cómo contribuir?

Esta sección va indicada especialmente para tus futuros colaboradores, así que se claro indicando una serie de issues abiertas para ir empezando, así como un pequeño roadmap con las tareas a futuro del proyecto.

Y es fundamental que dejes a disposición de los contributors un checkstyle del código del proyecto y una serie de reglas para incorporar contribuciones como un codestyle o algun hook preparado. Así como los pasos a realizar una Pull Request, ahora que Github permite los template eso debería ser obligatorio para que no se les escape ningún apartado que explica en la PR. Es recomendable que lo expliques en un fichero CONTRIBUTING.

Changelog

Añade un listado con los cambios de cada versión. Es fundamental para tus usuarios conocer que se va incorporando progresivamente en cada “salto de versión”. Respeta el versionado estándar utilizando adecuadamente la numeración de MAJOR.MINOR.PATCH.

Intenta separar cada cambio del siguiente modo:

  • Nuevos componentes que has introducido, ya sean componentes, APIs nuevas, funcionalidades, etc..
  • Elementos deprecated, es decir, lo que en próximas versiones será eliminado y remplazado por otros elementos. No olvides indicar el que se debería usar o la estrategia de migración.
  • Elementos que han sido eliminados. Recuerda la retrocompatilidad. No borres nada en un cambio de versión que no haya sido anteriormente marcado como deprecated.
  • Y por fin, los bugs que se han ido resolviendo en cada nueva versión. Añade si es posible la issue correspondiente para poder hacer un mejor seguimiento del problema que originaba. Seguro que alguien que se haya dado cabezazos con él se sentirá reconfortado al ver que ya está solucionado.

También te recomendamos

Cómo debe ser el ratón gaming perfecto para subir de nivel

Celebremos la llegada del hombre a la Luna con el código fuente del Apollo XI

CoreCLR, el núcleo de ejecución de .NET Core se publica Open Source

-
La noticia Checklist para liberar un proyecto Open Source en Github fue publicada originalmente en Genbeta Dev por Txema Rodríguez .

Checklist para liberar un proyecto Open Source en Github

10/05/2017
Artículo original

Github Liberar Proyecto

Github nos permite liberar cualquier proyecto en el que hayamos estado trabajado en privado. En ocasiones, nuestra intención es simplemente compartirlo sin más pretensiones como un pet project o como ejemplo de alguna kata que hemos estado preparado. Pero cuando queremos comenzar un proyecto Open Source un poco más serio, como una librería que queramos compartir con el resto de desarrolladores, quizás debamos pararnos a pensar un poco más antes de publicar nuestro código en Github si cumple una serie de pasos previos.

Vamos a repasar una serie de puntos interesantes para cualquier proyecto Open Source. Un pequeño checklist de recomendaciones, desde la visión tanto de un maintainer de proyectos de software Open Source como de un desarrollador que se encuentra un proyecto en Github y quiere usarlo.

Razones por las que liberar tu código como Open Source

Hay muchas razones por qué un desarrollador u organización querría hacer Open Source un proyecto. Algunos ejemplos para ilustrar la situación sería:

  • Pura colaboración. Quizás estemos desarrollando un proyecto por nuestra cuenta, lo hayamos mencionado en algún grupo de slack o meetup de desarrolladores, y nos lancemos a hacerlo abierto para que el resto de desarrolladores sean contributors ayudándonos a avanzar.
  • De forma individual simplemente buscar hacer público alguno de tus pet project. De esta forma la gente verá cómo programas y encuentres futuras colaboraciones.
  • Transparencia: Existen muchas instituciones que ven el Open Source como la forma de hacer público en lo que están trabajando para que cualquiera pueda revisarlo sin problema.

Deja claro el objetivo, las expectativas y cómo utilizar/colaborar

Hacer público un proyecto open source es sólo el principio

“Release early, release often” es una de las frases más repetidas cuando pensamos en liberar un proyecto software. Hacer público un proyecto open source es sólo el principio. Por ello, lo primero que debemos hacer es dejar claras las expectativas a cualquier desarrollador que se encuentre con él.

Fundamentalmente necesitamos clarificar lo máximo posible los siguientes puntos:

  • El objetivo del proyecto. ¿Qué es? Por ejemplo: una kata, una librería, un framework en construcción, etc..
  • Las instrucciones y dependencias que necesita para ser ejecutado
  • Un changelog accesible sobre los cambios de versiones y las versiones disponibles.

Checklist de tareas antes de liberar un proyecto Open Source

El clásico README

Es el lugar principal y donde cualquier desarrollador irá a buscar información. Debe estar localizado como un fichero de texto markdown en la raíz del proyecto. Github hace especial énfasis de que cada proyecto cuente con su correspondiente README.

Revisa el nombre Quizás el nombre sea lo primero que creaste, al menos, cuando le dedicaste horas de trabajo en privado, pero ahora que va a ser público debes asegurate que antes de lanzarlo no entra en conflicto con ninguno ya existente y ni mucho menos con alguna marca registrada.

Añade una descripción al proyecto Debemos explicar el objetivo, las motivaciones por las que existe este proyecto. También debemos enumerar las características del proyecto, incluyendo sus funcionalidades.

Cómo debo usarlo o integrarlo Si nos encontramos con un nuevo proyecto, lo más razonables es poder ser capaces de instalarlo, hacerlo arrancar o integrar en nuestra aplicación. Así que es fundamental que buena parte del README se trate de explicar las dependencias y las instrucciones para poder usarlo/integrarlo. Y no te olvides de explicar los test de los que cuenta, seguro que alguien que quiera probar su integridad o colaborar le será de ayuda lanzar los tests antes de crear una build desde el código.

Facilita la forma de descargar el artifact o la build Lo más habitual es que hayamos usado algun gestor de dependencias o un sistema de construcción del proyecto, ya sea con node, maven, gradle, makefile, etc… así como que el binario del proyecto se pueda descargar de algún lugar como maven central o con un sencillo npm.

Automatiza todo lo que puedas Es fundamental que a parte de que lo expliques en el README cuentes con un sencillo script que facilite la vida a los desarrolladores que quieran construir por ellos mismos la build. Usa bash, gradle, ant, maven, npm, etc.. para tu proyecto.

No te olvides del marketing Aprovecha para incluir algun logo o imagen que represente tu proyecto, nunca se sabe cuando alguien quiere hablar de él quizás, algún blog. Incluir un imagen representativa de tu librerías nunca es mala idea. Y si no lo tienes claro, piensa en los animales de la portadas de los libros de O’Really.

Añade una licencia

Liberar algo al público se debe hacer con cuidado. Revisa los componentes que utilizas y decide una libería acorde a tus intenciones y que cumpla los requisitos de tu proyecto. Entre las más populares se encuentran la Apache 2, MIT o GPL. Si te lías con los derechos y obligaciones que implican puedes consultar alguna recomendaciones de Github o alguna de estas webs: Choose a License o TLDR Legal.

¿Cómo contribuir?

Esta sección va indicada especialmente para tus futuros colaboradores, así que se claro indicando una serie de issues abiertas para ir empezando, así como un pequeño roadmap con las tareas a futuro del proyecto.

Y es fundamental que dejes a disposición de los contributors un checkstyle del código del proyecto y una serie de reglas para incorporar contribuciones como un codestyle o algun hook preparado. Así como los pasos a realizar una Pull Request, ahora que Github permite los template eso debería ser obligatorio para que no se les escape ningún apartado que explica en la PR. Es recomendable que lo expliques en un fichero CONTRIBUTING.

Changelog

Añade un listado con los cambios de cada versión. Es fundamental para tus usuarios conocer que se va incorporando progresivamente en cada “salto de versión”. Respeta el versionado estándar utilizando adecuadamente la numeración de MAJOR.MINOR.PATCH.

Intenta separar cada cambio del siguiente modo:

  • Nuevos componentes que has introducido, ya sean componentes, APIs nuevas, funcionalidades, etc..
  • Elementos deprecated, es decir, lo que en próximas versiones será eliminado y remplazado por otros elementos. No olvides indicar el que se debería usar o la estrategia de migración.
  • Elementos que han sido eliminados. Recuerda la retrocompatilidad. No borres nada en un cambio de versión que no haya sido anteriormente marcado como deprecated.
  • Y por fin, los bugs que se han ido resolviendo en cada nueva versión. Añade si es posible la issue correspondiente para poder hacer un mejor seguimiento del problema que originaba. Seguro que alguien que se haya dado cabezazos con él se sentirá reconfortado al ver que ya está solucionado.

También te recomendamos

CoreCLR, el núcleo de ejecución de .NET Core se publica Open Source

Celebremos la llegada del hombre a la Luna con el código fuente del Apollo XI

Cómo debe ser el ratón gaming perfecto para subir de nivel

-
La noticia Checklist para liberar un proyecto Open Source en Github fue publicada originalmente en Genbeta Dev por Txema Rodríguez .

Las 10 principales diferencias entre AngularJS y Angular

10/05/2017
Artículo original

Antes de nada debes tener claro que, a pesar de compartir el nombre, AngularJS y Angular no tienen nada que ver. El mal llamado "Angular 2", que se llama solamente Angular, no es una nueva versión de AngularJS (también denominado Angular 1.x). Es un nuevo framework, escrito desde cero y con conceptos y formas de trabajar completamente distintos.

Angular utiliza un sistema de inyección de dependencias jerárquico impulsando su rendimiento de forma brutal. También implementa la detección de cambios basados en árboles unidireccionales, que también incrementa el rendimiento. Según algunos datos oficiales, Angular puede llegar a ser 5 veces más rápido que AngularJS.

Angular tiene una curva de aprendizaje bastante empinada para los desarrolladores. Está todo escrito en Typescript y cumple con la especificación ES6. como ya apuntábamos al principio, no se puede decir que sea una actualización de Angular 1.x. Se ha reescrito por completo e incluye muchas innovaciones que rompen con su predecesor.

A continuación vamos a intentar hacer una pequeña comparación entre cómo se hacen las cosas entre ambos frameworks para que, si ya conoces AngularJS puedas ver cómo cambian algunas cosas en Angular.

Hay muchas más diferencias de las que te contamos aquí, claro está, pero esto esperamos que te sirva para empezar a hacerte una idea del tipo de cambios que se han producido.

¡Empecemos!

1. Angular está orientado a móviles y tiene mejor rendimiento

Angular 1.x no se hizo para soportar móviles, mientras que Angular está orientado desde el principio a dar buen rendimiento y funcionar bien en dispositivos móviles.

AngularJS se diseñó para crear apps Web de tipo SPA, con enlazado a datos bidireccional. No había soporte para móviles, aunque sí existen otras bibliotecas que hacen que Angular 1.x se ejecute en móviles.

Angular se ha creado teniendo en cuenta una arquitectura orientada a móviles. Hay bibliotecas, por ejemplo NativeScript, que ayudan al desarrollo rápido para móviles con Angular. Además, renderiza el mismo código de forma distinta en navegadores web que en apps móviles.

(Gráfico obtenido de la documentación de NativeScript)

2. Angular ofrece más opciones a la hora de elegir lenguajes

Angular ofrece la posibilidad de elegir entre varios lenguajes a la hora de programar. Para escribir código Angular puedes usar cualquiera de los lenguajes: ECMAScript 5 de toda la vida, ES6, TypeScript o incluso Dart (de Google). Mientras que con Angular 1.x puedes usar ES5, ES6 y Dart.

Poder usar TypeScript es un gran avance ya que es una forma genial de escribir JavaScript. TypeScript es el lenguaje por defecto para desarrollar en Angular, y el que sin duda vas a querer utilizar. La mayor parte la documentación que encontrarás por ahí estará creada con TypeScript, así que debes aprenderlo.

3. Los controladores y el $scope de Angular 1.x han desaparecido

Podemos decir que en Angular los controladores se substituyen por componentes. Angular se basa en componentes web, con las ventajas que ello supone al adoptar un estándar de futuro, que cuando esté bien soportado por todos los navegadores ofrecerá más rendimiento todavía.

Por ejemplo:

Controlador Angular 1.x

En JavaScript:

var myApp = angular
.module("miModulo", [])
.controller("productoController", function($scope) {
         var prods = { name: "Prod1", quantity: 5 };
         $scope.products = prods;
});

Controlador Angular

En TypeScript:

import { Component } from '@angular/core';

@Component({
    selector: 'prodsdata',
    template: '<h3>{{prods?.name}}</h3>'
})`

export class ProductoComponent {
    prods = {name: 'Prod1', quantity: 5 };
}

Fíjate en cómo, además, hemos usado una interrogación después de prods para indicar que el objeto podría ser nulo (es un "anulable"), en cuyo caso no se produciría un error y solo se mostraría el nombre en caso de que el producto tenga algún dato. Ventajas de usar TypeScript.

4. La sintaxis de las directivas estructurales ha cambiado

En Angular, la sintaxis de las directivas estructurales ha cambiado, ng-repeat se sustituye por *ngFor, por ejemplo.

Directivas estructurales Angular 1.x:

<ul>
   <li ng-repeat="prod in productos">
     {{prod.name}}
   </li>
</ul>

Directivas estructurales Angular:

<ul>
  <li *ngFor="prod of productos">
    {{prod.name}}
  </li>
</ul>

El signo Asterico(*) se usa como prefijo para directivas estructurales, in se sustituye por of y se usa la sintaxis camelCase. Hay muchos más detalles de esta nueva sintaxis, pero de momento quédate con esto.

5. Angular usa directamente las propiedades de los elementos y los eventos estándar del DOM

Uno de los mayores cambios en Angular es, que usa directamente las propiedades de los elementos y los eventos estándar del DOM.

Por ello, muchas de las directivas integradas disponibles en Angular 1.x ya no se necesitan, como por ejemplo: ng-href, ng-src, ng-show o ng-hide. Angular usa directamente href, src y propiedades hidden para obtener el mismo resultado.

Y lo mismo se puede decir de las directivas basadas en eventos como ng-click o ng-blur.

En AngularJS:

<button ng-click="doSomething()">

En Angular simplemente tomas el evento estándar y lo envuelves entre paréntesis:

<button (click)="doSomething()">

Nuevamente aquí hay muchos otros detalles a tener en cuenta, pero quédate con esta idea principal.

6. La directiva de datos enlazados en una sola dirección (one-way data binding) se sustituye por [property]

En Angular 1.x, ng-bind se usa para enlazar datos en una sola dirección (one-way data binding), lo que quiere decir que sólo se modifica el enlace desde el código hacia la vista, pero no al revés, lo que permite un mayor control de flujo dentro de la aplicación.

Con Angular esto se reemplaza por [property], siendo "property" una propiedad válida del elemento del DOM sobre el que actuamos.

Por ejemplo, en Angular 1.x escribíamos:

<input ng-bind="prod.name"></input>

En Angular se utilizan simplemente corchetes sobre la propiedad estándar:

<input [value]="prod.name"></input>

Aunque existen otras variantes para lograr lo mismo.

7. Enlaces de datos de doble dirección (two-way data binding): ng-model se sustituye por [(ngModel)]

Este es el enlazado que todo el mundo conoce y usa en AngularJS. En Angular se retira esta sintaxis para lograr mayor seguridad, control y mejora del rendimiento.

En Angular 1.x hacíamos esto para tener un enlazado en dos direcciones:

<input ng-model="prod.name"></input>

En Angular la sintaxis equivalente sería:

<input [(ngModel)]="prod.name"></input>

Este doble-binding ofrece ventajas relevantes en la gestión avanzada de formularios.

8. Ha cambiado la sintaxis de la inyección de dependencias

Una de las grandes ventajas de Angular es la inyección de dependencias. Con Angular hay una manera distinta de llevar a cabo esto. Como en Angular todo son "clases", la inyección de dependencias se consigue mediante constructores.

En Angular 1.x:

var myApp = angular
   .module("miModulo", [])
   .controller("productoController", function($scope, $http) {
        var prods = { name: "Queso", quantity: 5 };
        $scope.productos = prods;
    });

En Angular:

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Producto } from 'app/shared/Producto.ts';

@Injectable()

export class ProductosService {
    constructor(private _http: Http) { }
    getProductos() {
        return [new Producto(1, 'Queso'),
            new Producto(2, 'Pan',
            new Producto(3, 'Verdura')
        ];
    }
}

@Injectable() es la anotación de Angular que permite definir clases como servicios, importándolos a posteriori dentro de los módulos de Angular. Esto tiene enormes beneficios en lo que respecta al rendimiento, ya que es el propio Angular quien maneja la carga de entidades a través del bootstrapping.

9. Ha cambiado la sintaxis para hacer routing

En Angular 1.x, usamos $routeProvider.when() para configurar el enrutamiento. Sin embargo, en Angular se usa @RouteConfig{(...}). El ng-view que está presente en Angular 1.x se susitituye por <router-outlet>.

En Angular 1.x y JavaScript:

var app = angular
        .module("miModulo", ["ngRoute"])
        .config(function ($routeProvider) {
            $routeProvider
            .when("/inicio", { templateUrl: "inicio.html", controller: "inicioController" })
            .when("/Productos", { templateUrl: "productos.html", controller: "productosController" })
        })
       .controller("inicioController", function ($scope) {
            $scope.message = "Página de inicio";
        })   
       .controller("productosController", function ($scope) {
             $scope.prods = ["Queso", "Pan", "Verdura"];
       })

En Angular y TypeScript:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { InicioComponent } from './inicio/inicio.component';
import { ProductoComponent } from './productos/producto.component';

const appRoutes: Routes = [
    {
        path: 'inicio', 
        component: InicioComponent,
    },
    {
        path: 'productos', 
        component: ProductoComponent,
    },
];

@NgModule({
    imports: [
        RouterModule.forRoot(appRoutes)
    ]
})
export class AppRoutingModule { }

Y en la página HTML:

<ul>
  <li><a routerLink="/inicio">Página de inicio</a></li>
  <li><a routerLink="/productos">Productos</a></li>
</ul>

10. La forma de arrancar una Aplicación Angular ha cambiado:

Angular 1.x tiene dos formas de arrancar. Una usando el atributo ng-app y la otra vía código:

<script>
   angular.element(document).ready(function() {
       angular.bootstrap(document, ['myApp']);
   });
</script>

En Angular la única forma de arrancar es vía código, en TypeScript:

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';

platformBrowserDynamic().bootstrapModule(AppModule);

En resumen

Como vemos, aunque siempre hay cosas en común, AngularJS y Angular son muy diferentes tanto en lo que se refiere a la forma de trabajar como a los conceptos que subyacen a ambas tecnologías.

En los puntos anteriores solo hemos tocado la superficie, pero esperamos que te haya ayudado a ver la manera tan distinta de trabajar que tienen ambas plataformas JavaScript.

Por eso no se puede hablar de una nueva versión, sino de un nuevo framework, que es necesario aprender prácticamente desde cero.

En campusMVP tenemos un curso de Angular estupendo que te servirá tanto si ya conoces AngularJS y quieres actualizarte, como si partes de cero y quieres aprender a dominar el nuevo framework. Incluye el aprendizaje de TypeScript.

Cómo iterar sobre varias colecciones en Scala

08/05/2017
Artículo original

Cuando empecé a trabajar con scala me encontré con que me resultaba difícil resolver problemas triviales, fáciles de resolver en lenguajes que ya conocía. Supongo que esa es la parte más frustrante de aprender un lenguaje nuevo, al menos en mi opinión.

Iterar sobre varias colecciones a la vez en python

Uno de esos problemas triviales es iterar sobre dos colecciones al mismo tiempo. La forma más “pythonic” es simple:

collection1 = (1,2,3,4,5)
collection2 = ('a','b','c','d','e')

for i,j in zip(collection1, collection2):
     print i,j

que resulta en:

1 a
2 b
3 c
4 d
5 e

Iterar sobre varias colecciones a la vez en scala

Ahora bien, ¿cual es la forma idiomática de hacerlo en scala?. En mi caso concreto necesitaba iterar sobre la colección y además disponer del índice del elemento actual, esto se puede conseguir con el método zipWithIndex, y luego llamar a zipped para convertirlos en tuplas junto a las demás colecciones sobre las que queramos iterar:

private val tree: Vector[Node] = {
  val indexedWords = words.zipWithIndex

  (indexedWords, tags, dep).zipped.map {
    (w, t, d) =>
      new Node(w._1, w._2, t, d)
  }
}

En el ejemplo de arriba estoy juntando tres colecciones a la vez (indexedWords, tags, dep), que son del tipo ((String, Int), String, Int).

Antes de conocer la forma idiomática estaba iterando de este modo bastante feo:

/** Constituent tree of this sentence; includes head words */
private val tree: Vector[Node] = words.map(w => {
   val i = words.indexOf(w)
   new Node(w, i, tags.head, 0)
})

Estas porciones de código son parte de mi trabajo de fin de Grado, el proyecto consistía en crear un Parseo de Dependencias para el Castellano, puedes ver el proyecto completo en GitHub: NLP_Dependency_Parsing

Referencias

¿Qué son los filtros de excepciones en el lenguaje C#?

08/05/2017
Artículo original

Los filtros de excepciones son una característica de la gestión de errores de .NET que han estado disponibles en el framework desde siempre. Los programadores de VB.NET han tenido acceso a ellos también desde el origen de los tiempos, pero los "sufridos" programadores de C# se tenían que conformar con simularlos de manera chapucera. No fue hasta la aparición de C# 6.0, allá por el verano de 2015, que los programadores de C# le pudieron sacar partido a esta útil característica por primera vez.

Un filtro de excepciones lo que nos permite es establecer una cláusula catch específica no solo para un tipo de excepción concreta, sino también filtrando la excepción según algunas condiciones adicionales sobre la misma.

Vamos a verlo con un ejemplo concreto.

Imagínate que estás haciendo una pequeña rutina que llama a una página web para obtener su contenido. Si todo va bien devuelve el contenido de la página, pero si se produce algún fallo devuelve un texto corto descriptivo de lo que ha pasado. Cosas como, por ejemplo, "Página no encontrada" si no la encuentra y por lo tanto se devuelve un estatus HTTP 404, "Permisos de acceso denegado" si  se obtiene un 403, o "Se ha producido un error interno" en caso de un código de estado 500, etc...

En un código C# normal anterior a C# 6.0, lo que debería escribir es algo similar a esto (un poco más cuidado, pero así se "pilla" la idea):

public static string DescargaPagina(string url)
{
    try
    {
        WebClient wc = new WebClient();
        return wc.DownloadString(url);
    }
    catch(WebException wex)
    {
        if (wex.Message.Contains("(404)"))
            return "Página no encontrada";
        else if (wex.Message.Contains("(403)"))
            return "Permiso denegado";
        else if (wex.Message.Contains("(500)"))
            return "Se ha producido un error interno en la web solicitada";
        else
            return "Se ha producido un error: " + wex.Message;
    }
    catch(Exception ex)
    {
        return "Se ha producido un error: " + ex.Message;
    }
}

Fíjate en cómo puedo especificar un gestor de excepciones distinto según el tipo de excepción, pero que luego tengo que estar con un montón de condicionales para devolver un mensaje diferente según el código de error que viene en el mensaje. Por supuesto podría haber usado un switch y una expresión regular, o cualquier otra técnica un poco más elaborada para conseguir lo mismo, pero la idea es que tengo que hacerlo dentro del gestor de la excepción.

¿Cómo podría mejorarlo usando filtros de excepciones?

Pues gracias a la palabra clave when que me permite generar diferentes elementos catch con condiciones adicionales de filtro. Lo mejor es verlo en acción porque se entiende muy fácilmente.

El código equivalente al anterior, pero con filtros de excepciones sería el siguiente:

public static string DescargaPagina(string url)
{
    try
    {
        WebClient wc = new WebClient();
        return wc.DownloadString(url);
    }
    catch (WebException wex) when (wex.Message.Contains("(404)"))
    {
        return "Página no encontrada";
    }
    catch (WebException wex) when (wex.Message.Contains("(403)"))
    {
        return "Permiso denegado";
    }
    catch (WebException wex) when (wex.Message.Contains("(500)"))
    {
        return "Se ha producido un error interno en la web solicitada";
    }
    catch (Exception ex)
    {
        return ex.Message;
    }
}

Fíjate que ahora el código es mucho más claro y directo. Gracias a when podemos especificar condiciones más o menos complejas que nos interesen para filtrar cada excepción. Ahora para capturarla en un catch concreto no solo llega con que el tipo de excepción sea el que indicamos, sino que además debe cumplirse la condición que establezcamos en el when.

De este modo podemos tener código más claro y mejor gestionado. No deja de ser "azúcar sintáctico" pero la gente de VB.NET lleva disfrutándolo desde hace 3 lustros, e incluso los de F# lo tenían desde su versión 1.0. Ya era hora de que estuviese disponible en C# también :-)

Te puedes descargar el código de ejemplo para Visual Studio 2015 o posterior desde aquí (ZIP, 4KB)

¡Espero que te resulte útil!

Construyendo proyectos con Gradle (instalación con SDKMAN!)

08/05/2017
Artículo original


En el post pasado hablé sobre SDKMAN! , una herramienta que nos permite instalar lenguajes de programación como Ceylon, Java, Groovy, etc. Tambien nos permite instalar herramientas como Gradle, la cual nos permite construir y administrar proyectos.

Antes de empezar deberías dar un vistazo al anterior post .

Tan sencillo como teclear desde la terminal (cmd o linux shell) lo siguiente:
$sdk install gradle

Comprobar la versión instalada:
$gradle --version
$gradle -v

Debería salir algo como esto:

------------------------------------------------------------
Gradle 3.5
------------------------------------------------------------

Build time: 2017-04-10 13:37:25 UTC

leer más

15 cosas que todo desarrollador debería saber pero que quizá no sepas

04/05/2017
Artículo original


(Crédito de la imagen: Anderson Mancini)

Este post recoge las quince respuestas que hemos considerado más interesantes de entre las decenas que podéis encontrar en el artículo original de Quora (en inglés). Nos han parecido que transmiten mucha sabiduría y que os pueden ayudar :-)

  1. Tu ingenio es directamente proporcional a la sencillez de tus soluciones.

  2. Ya puedes añadir todas las funcionalidades que quieras, en el lenguaje que te apetezca, siguiendo la tendencia que te plazca, que si vuestro equipo de ventas no encuentra a un comprador, todo dará igual.

  3. El mundo del desarrollo es tribal. No esperes poder cambiar la mentalidad de los desarrolladores de otras tribus (Sistemas Operativos, lenguajes, frameworks, etc...).

  4. En relación con lo anterior, es importante recordar que cualquier problema normalmente puede resolverse de muchas formas, no hay una "única forma mejor", así que es mejor ahorrarse las discusiones.

  5. Las demás personas no pueden leer tu mente. Si eres un desarrollador reservado y pensativo, da la impresión de que no estás trabajando. Subsánalo comentando cosas de forma proactiva de vez en cuando.

  6. Un bloque de código bastante grande sin una documentación que lo acompañe es como una caja negra. A pesar de lo que digan los demás, entender a fondo el código de terceros es difícil, jodidamente difícil.

  7. Las personas normales son bastantes imprecisas con las palabras. Así que los programadores tenemos que hacer muchísimas preguntas para asegurarnos de saber realmente qué quiere el usuario.

  8. Tus jefes/ clientes/... agradecen pequeños resúmenes explicados en un idioma que puedan entender.

  9. Leyendo los puntos anteriores se evidencia la importancia de la comunicación en este trabajo. Así que empieza a mejorar tus aptitudes a la hora de escribir emails convincentes, de redactar actualizaciones de estado, de describir un bug, de hablar delante de 10 personas y de hablar delante de 100 personas. Sí, todas estas destrezas son muy diferentes entre sí. ¡Echemos abajo el mito de que los techies son malos comunicadores!

  10. Recuerda que no eres Superman o Superwoman. Pasarse la noche en vela picando código suele traducirse en una semana de corrección de errores y rescritura del programa. ¿Crees que merece la pena? Olvídate de la largas noches, piensa en tu salud (física y mental) y de paso en el bien del proyecto.

  11. Cualquier bloque de código grande tiene errores (¡asúmelo, aunque lo hayas escrito tú, también tiene errores!). Súmale los errores latentes (nadie sabe que están ahí). Y de repente a la hora de añadirle alguna funcionalidad o corregir un error existente conocido, es probable que actives uno de esos errores latentes y entonces tu vida se convierte en un infierno.

  12. Se nos paga por los beneficios obtenidos en ventas. No tenemos derecho a tener un trabajo, tenemos que asegurarnos de que estamos programando algo digno de que alguien quiera pagar por ello. Proyectos financiados por Capital Riesgo/Business Angel y el sector público quizás ignoren esto en cierta medida.

  13. Una persona realmente competente que haga bien las pruebas es casi tan raro como un unicornio. Si tienes a una trabajando contigo, date con un canto en los dientes. Tales perfiles pueden hacer trizas tu software, sacando a la luz muchos errores. Ayúdales a que te ayuden a descubrir tus bugs y localizarlos y arreglarlos antes de que los encuentren los clientes y te tengas que pasar noches en vela corrigiéndolos.

  14. No importa cuánto creas que entiendes un problema, alguna remota y extraña combinación de sucesos improbable se dará después de que pienses que has terminado. A veces hará aparición como un error crítico dos noches antes de lanzarlo en producción.

  15. Por último, recuerda que la mayoría de las dificultades se deben a que tienes que tratar con personas y también a procesos y decisiones del pasado.

Exportando tablas a Excel, CSV y otros formatos desde una página HTML en JavaScript puro

03/05/2017
Artículo original

Una necesidad muy habitual en todo tipo de desarrollos Web es la de poder exportar información que tenemos en la página a archivos descargables que el usuario pueda utilizar.

Para solucionar este problema, muchas veces se recurre a que, cuando el usuario pulsa el botón de exportar, lanzamos una nueva petición al servidor, y el documento descargable se genera al vuelo en el backend, siendo devuelto al usuario a través de Internet.

Esto está bien y de hecho es indispensable a veces, según el tipo de información y el formato del archivo que nos interese. Sin embargo, lo que muchos programadores Front-End no saben, es que es posible generar archivos para descarga directamente desde el navegador, usando tan solo JavaScript.

Y eso precisamente es lo que voy a explicar hoy en este artículo... Los formatos que voy a usar son sencillos (Excel, Word, CSV y HTML) pero nos vale para ver cómo se lleva a cabo esta técnica. Más adelante comento más sobre otros formatos y las "pegas" de estos.

El protocolo "data:"

Los navegadores modernos soportan un tipo especial de URI (identificador único de recurso) de tipo data: que nos permite definir los datos exactos que queremos visualizar de manera directa. Así, por ejemplo, es frecuente encontrar este tipo de URL con imágenes que van embebidas en los documentos, en lugar de descargadas de manera independiente. Pero también se puede utilizar para simular la descarga de otro tipo de archivos. Esto es lo que vamos a hacer para el caso que nos ocupa.

Lo primero que debe aparecer tras el prefijo data: es el tipo MIME del archivo que vamos a querer descargar, seguido de la codificación del mismo en caso de ser necesaria.

Estos son algunos de estos tipos MIME puestos a continuación de data: para algunos tipos de archivo:

  • .html: data:text/html
  • .doc: data:application/vnd.ms-word
  • .csv: data:text/plain
  • .xls: data:application/vnd.ms-excel;base64

En el caso de Excel, además, hay que codificar el resultado en Base64 para que la pueda interpretar adecuadamente, por eso lleva la codificación indicada al final. El resto son en texto plano.

A continuación se le pone una coma (,) y se coloca la información que va a ir dentro del archivo. Esta información debe ir codificada como Base64 o bien como texto plano, pero en este último caso debe ir adecuadamente codificada para formar parte de un URL, es decir, no vale escribir <h1>Hola Mundo</h1> como contenido, sino que deberá ir escrito como %3Ch1%3EHola%2C%20Mundo%3C%2Fh1%3E

Si te interesa, aquí tienes un Codificador/Decodificador en formato URL. Todos los lenguajes de programación de servidor tienen un par de métodos para hacer esto, y en JavaScript esto se consigue con el método encodeURIComponent.

Así, por ejemplo, un URI de este tipo válido sería:

data:text/html,%3Ch1%3EHola%2C%20Mundo%3C%2Fh1%3E

que si lo copias y lo pegas en la barra de direcciones de tu navegador descargará un archivo HTML con la cabecera "Hola mundo" escrita.

Hay que tener cuidado porque este tipo de URL puede que tenga limitaciones de tamaño máximo según el navegador. En las pruebas que he hecho se pueden crear documentos muy grandes sin problema, pero eso no quita que puedas crear uno tan grande que el navegador lo rechace o lo trunque, así que siempre debes tenerlo en cuenta.

La especificación completa de este tipo de URIs se puede leer en el IETF en el documento The "data" URL scheme, si te interesa conocerla a fondo, y data nada menos que de 1998, ¡hace casi 20 años!.

Información extra

En el caso de archivos Excel podemos simplemente mandar el HTML de una tabla y Excel sabrá cómo interpretarlo, aunque no es lo más ideal.

Queda mucho mejor si rodeamos los datos tabulares con un HTML especial que Excel sabe interpretar y que permite indentificar más claramente a la tabla y además asignarle un nombre a la hoja correspondiente.

La constante es muy larga, no la voy a poner aquí, pero la tienes en el código fuente que he creado (ver más abajo).

Base64

Para algunos archivos, como los de Excel, es necesario codificar en Base64 los datos antes de generar el URI correspondiente.

Esto en JavaScript, por suerte, es muy fácil de conseguir.gracias a la función btoa del ámbito global (vale tanto paa navegadores como para NodeJS) y que sirve precisamente para eso.

Cómo descargar un archivo con una URI de tipo "data:"

Vale, ahora que ya sabemos cómo "crear" archivos en el navegador simulando URLs como los que acabo de explicar, vamos a ver qué más necesitamos.

Aparte de codificar adecuadamente cada formato y montar el URI como acabo de enseñar, lo único que necesitamos para poder hacer la descarga es que el usuario pulse algún enlace o botón para poder provocar la descarga. No serviría hacerlo solo por código (a partir de un evento o de un temporizador) ya que los navegadores anulan las acciones que no son provocadas por los usuarios y que pueden suponer un problema de seguridad.

Cuando el usuario pulse sobre el enlace en cuestión, para poder provocar la descarga lo que podemos hacer es lo siguiente:

  1. Creamos un enlace en memoria
  2. Le asignamos como href el URI que hemos creado antes, así "navegará" a él cuando pulsemos.
  3. Asignamos en su propiedad download el nombre que le queremos dar al archivo que pretendemos generar. Esta propiedad vale precisamente para esto, aunque no está soportada por Internet Explorer (más sobre esto luego).
  4. Simulamos una pulsación llamando al método click del enlace. Esto funcionará porque este código lo estamos llamando desde una acción del usuario, y por lo tanto está provocado por él también y el navegador no lo bloquea.

Esto provocará la descarga del archivo con el nombre que queramos y el contenido construido en el punto anterior.

Nota: en Firefox si no metemos el enlace dentro del DOM y solo lo tenemos en memoria, la pulsación simulada no funciona. Por ello debemos hacer tres pasos extra (que servirán en los demás navegadores aunque no sean necesarios), a saber:

  1. Colocarle un estilo diplay:none para que no se vea.
  2. Añadir el enlace al DOM.
  3. Simular la pulsación.
  4. Retirar el enlace del DOM para dejarlo como estaba.

Un poco lioso pero con esto funciona en todos los navegadores modernos (menos Edge).

Esto funciona en los navegadores modernos, pero no así en Internet Explorer. En este navegador antiguo, pero todavía muy utilizado por mucha gente, lo que debemos hacer es muy distinto y más lioso y nos complica la vida al tener que darle soporte, pero básicamente es:

  1. Crear un iframe en memoria.
  2. ocultarlo con display:none;.
  3. Agregarlo al DOM.
  4. Inicializar el documento del iframe como si fuera a contener HTML, con open.
  5. Escribir el contenido de nuestro archivo sin la cabecera del tipo MIME, ni data: ni codificando nada: "a pelo", los datos "limpios".
  6. Cerrar el documento del iframe y colocar el foco en éste.
  7. LLamar al método execCommand.aspx) de Internet Explorer para pasarle el comando "SaveAs" y forzar el guardado del documento con el nombre que queramos.
  8. Retirar el iframe, que ya no necesitamos, tras la descarga.

Buff!, un rollo, pero no queda más remedio. Con esto lograremos que funcione en IE incluso en versiones antiguas.

Lo que no he conseguido de ninguna manera es que funciona con Microsoft Edge. Este navegador va "a su bola" completamente. De hecho la técnica usada para los demás navegadores parece funcionar, pero no logro que salga el diálogo de descarga. Es decir, aunque la descarga parece que se inicia y no da ningún error, no aparece por ningún lado preguntando dónde quieres guardar el archivo, y cuando vas a cerrar el navegador te dice que hay descargas pendientes. Pero no paso de ahí por más vueltas que le he dado. Si se te ocurre cómo solucionarlo mándame un Pull Request en GitHub (ver más abajo)

Codificación de caracteres no-ingleses

Vale, ya tenemos todo más o menos planteado. Pero cuando vas a probarlo con datos que tienen eñes, tildes y cosas así (caracteres no-ingleses) verás que se ven mal en todos los archivos...

El motivo es que si no lo indicas explícitamente tanto Excel, como Word, etc... interpretan el archivo como ANSI aunque esté codificado como UTF-8, y por lo tanto trastoca la codificación, viéndose todos estos caracteres mal.

Para solucionar este problema hay que actuar de manera diferente según el formato de archivo.

En el caso de archivos que llevan HTML, como Excel, Word o el propio formato HTML basta con incluir, como parte del HTML que enviamos codificado, la siguiente cabecera que indica la codificación que se usa:

<meta charset="UTF-8">

Simplemente metiendo esto ya lo saben interpretar y se ve perfectamente.

En el caso de formatos textuales, como CSV, es más complicado porque no podemos meter ningún tipo de cabecera que puedan interpretar, y dependiendo del programa que uses para abrirlo, lo interpretará bien o no. Por ejemplo Excel interpreta de manera errónea los archivos .csv aunque estén en UTF-8 y se ven mal los caracteres no-ingleses. Para solucionarlo, lo que he hecho es forzar que se detecten los archivos como UTF-8 al abrirlos metiéndole delante los tres caracteres del Byte Order Mark o BOM.aspx).

Haciendo esto Excel los interpreta correctamente cuando los importamos desde el menú Datos·Desde texto y las tildes y demás se ven perfectamente.

Una biblioteca lista para utilizar

Lo anterior era la teoría. En la práctica he implementado todo esto en una biblioteca Open Source llamada exporter.js que puedes encontrar en GitHub lista para ser utilizada, también incluso minimizada (ocupa en este caso tan solo 2,17KB)

Esta biblioteca, al agregarla a una página, crea un objeto global llamado Exporter el cual cuenta con un método llamado export que sirve exportar cualquier elemento de la página que le pasemos a los formatos soportados, que son:

  • Excel (.xls)
  • CSV (.csv)
  • Word (.doc)
  • HTML (.html)

El método tiene eta firma:

Exporter.export(DOMElmt, fileName, dataName);

y toma como parámetros el elemento del DOM cuyo contenido completo queremos descargar en un archivo, el nombre del archivo y opcionalmente el nombre que le queremos dar a la hoja interior en caso de exportarlo a Excel.

Para determinar el tipo del archivo y por lo tanto formatearlo adecuadamente se utiliza la extensión de éste.

Por ejemplo, para descargar una tabla en formato Excel escribiríamos en el click de un enlace lo siguiente:

var datos = document.GetElementById('TablaDatos);
Exporter.export(datos, 'cursos.xls', 'Cursos')

y ya se lanzaría el diálogo para guardar la Excel a disco con el nombre indicado.

Si quisiésemos un archivo de Word, sería casi igual, pero sin el último parámetro:

var datos = document.GetElementById('TablaDatos);
Exporter.export(datos, 'cursos.doc')

Fíjate que en el caso de Excel o CSV el elemento debe ser una tabla o lanzará una excepción o para indicarlo, ya que se trata de formatos tabulares. En el caso de Word o HTML puede ser cualquier elemento o incluso la página completa si quisiésemos, y funcionará sin problemas.

En el caso de CSV he implementado un método para recorrer la tala por filas y celdas y generar los datos en el formato delimitado por comas.

En Github tienes el código fuente completo con un montón de comentarios (aunque en inglés, es lo que hay: hace tiempo que decidí que todos los proyectos Open Source lo hago en este idioma). Si quieres puedes echarle un vistazo para entender mejor todo lo que he explicado antes, y las dificultades que hay.

Tienes un archivo .html de prueba con una tabla (de cursos) y enlaces para descargarla en todos los formatos.

Otros formatos (PDF, XLSX, DOCX...)

Aunque esta exportación a Excel y Word funciona perfectamente, debemos saber que no es el formato nativo de estos programas, sino que es simple HTML por debajo.

En el caso de Word no hay diferencia en el sentido de que los abre sin "quejarse". Pero en el caso de Excel es más problemático porque al intentar abrir el archivo generado nos avisa con este mensaje:

Este mensaje lo que dice es que el formato del archivo (que es HTML en realidad) y la extensión no coinciden, y si queremos abrirlo. Basta con decir que sí y lo abre perfectamente, mostrando incluso las celdas con colores y formatos:

Por defecto, como todo archivo bajado de Internet, lo abre en modo de solo lectura, por seguridad.

El caso es que el formato de Excel o Word nativos (.xlsx o .docx) son formatos binarios que deben cumplir una serie de convenciones y normas. En realidad son archivos comprimidos con ZIP con una serie de archivos y carpetas dentro. Del mismo modo otros tipos de archivo habituales, como los PDF por ejemplo, son también archivos más complejos y binarios.

Es posible generarlos desde JavaScript puro, pero requieren muchas más cosas de las que he explicado aquí, y necesitan mucho más código y una enorme complejidad. Con la biblioteca que he creado y la explicación de este artículo podrás crear archivos sencillos como los mencionados, que pueden resultar muy útiles y demuestran la potencia de JavaScript y los navegadores modernos.

La creación de los otros tipos de archivos usan técnicas más avanzadas que, de momento, no tengo capacidad de explicar en el blog. Para que te hagas una idea, crear esta biblioteca de ejemplo y este artículo me ha llevado unas 8 horas. Lo otro me llevaría mucho más, así que no lo voy a hacer, sorry :-S

De todos modos espero que esta explicación y la biblioteca exporter.js te resulten útiles. Si quieres contribuir a la misma ampliando sus capacidades, te doy la bienvenida desde ahora mismo :-)

Y ya sabes, si quieres aprender JavaScript (y ECMAScript) a fondo conmigo para responder a todas tus dudas tienes este curso o mejor aún este otro curso que además explica a fondo jQuery, APIs de HTML5, y muchas otras cosas interesantes :-)

¡Saludos!

Página Anterior Página Siguiente