Importando el calendario de nuestro evento favorito

El próximo 27 y 28 de noviembre estaré un año más en el Codemotion, un evento que se celebra en Madrid reúne comunidades de todo tipo y del que hemos hablado en otros artículos de años anteriores.

En ellas desarrolladores de .NET, Java y la JVM, Ruby, Python, JavaScript, Objective-C, Swift, PHP y otros, se reunen para enseñarnos lo mejor de todos los mundos. Yo ya tengo mi entrada, si no tienes la tuya ya estás tardando

Sin embargo hay algo que sigo sin entender. Al igual que en otros eventos, tenemos disponible la agenda completa en la web, y probablemente el primer día nos entregarán una copia EN PAPEL que acabará en una papelera varios días después del evento, si no lo perdemos antes.

No sería mucho más conveniente poder tener el calendario oficial del evento en un formato que lo pudiera entender nuestro Google Calendar, Outlook, iCal o cliente que utilicemos, y poder usar nuestro móvil para orientarnos por el evento? Pues bien, eso es lo que he hecho, y es lo que veremos en este artículo:

Primer paso, obtener los datos

Para obtener los datos originales tenemos muchas maneras. Una de ellas es utilizar un servicio como Kimono que nos permite crear una API REST a partir de una página ya existente, lo cual nos puede resultar muy útil para extraer información.

Otra opción consiste en investigar un cómo, y qué datos carga la página. En el caso de Codemotion, la agenda se carga de manera asíncrona, así que tras investigar el panel de red de Chrome podemos ver un fichero en formato JSON que contiene, para nuestro disfrute, la agenda completa a nuestra disposición, así que, misión cumplida.

Segundo paso, comprender el formato de salida

Para poder generar un fichero que sea compatible con los diferentes clientes de email, una de las opciones es utilizar el formato icalendar, que define un evento de la siguiente manera:

BEGIN:VEVENT
SUMMARY:Document like a hero using Asciidoctor
DTSTART:20151127T160000Z
DTEND:20151127T164500Z
DESCRIPTION:In 2013, the Spring team decided to migrate the Starting Guides on spring.io ...
END:VEVENT

Analicemos los diferentes componentes, dejando de lado las cabeceras begin y end del evento:

  • Summary: Título que se mostrará en la cita del calendario
  • Dtstart: Fecha y hora de inicio de la cita en la zona horaria UTC, en el siguiente formato: Año Mes Día (T) Hora Minutos Segundos (Z)
  • Dtend: Fecha y hora de fin de la cita, en el mismo formato anteriormente comentado
  • Description: Detalles del evento

Si hemos utilizado el calendario de manera corporativa echaremos de menos temas como invitados, alarmas, etc, aunque todos ellos forman parte del estándar y podemos utilizarlos sin problemas. Para reunir varios eventos en un fichero iCalendar hemos de establecer unas cabeceras y un pie de página de la siguiente manera:

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
...
END:VCALENDAR

En este código, definimos nuestro fichero iCalendar, la versión del mismo, y el identificador del generador (que en este caso lo he tomado directamente del ejemplo de la wikipedia). Cerramos el fichero con el marcador End.

Con esta información, ya podemos generar nuestro calendario.

Tercer paso, generar el calendario

Para este ejemplo, como utilizaba un fichero en formato json, me pareció mucho más sencillo utilizar JavaScript y Node.js para generar el fichero ics.

var fs = require('fs');
var obj = JSON.parse(fs.readFileSync('data.json', 'utf8'));
var result = "";
var writer = {
log : function(params){
result += params + "\r\n";
console.log(params);
},
end: function(){
fs.writeFile('codemotion.ics',result);
}
}
function pad(num) {
var zero = 2 num.toString().length + 1;
return Array(+(zero > 0 && zero)).join("0") + num;
}
//var writer = console;
writer.log("BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//hacksw/handcal//NONSGML v1.0//EN")
obj.days.forEach(function(day) {
day.tracks.forEach(function(track) {
track.slots.forEach(function(slot) {
if(!slot.contents){
return;
}
if(!slot.contents.title){
return;
}
writer.log("BEGIN:VEVENT");
if(slot.contents.type == "BREAK"){
writer.log("SUMMARY:" + slot.contents.title);
} else {
writer.log("SUMMARY:" + "[" + track.name + "] " + slot.contents.title);
}
var dayName = day.name.substring(0,2);
writer.log("DTSTART:201511" + dayName + "T" + pad(parseInt(slot.start.substring(0,2)) 1) + slot.start.substring(3,5) + "00Z");
writer.log("DTEND:201511" + dayName + "T" + pad(parseInt(slot.end.substring(0,2)) 1) + slot.end.substring(3,5) + "00Z");
var description = "";
if(slot.contents.description){
description += "DESCRIPTION:" + slot.contents.description.replace(/(\r\n|\n|\r)/gm,"\\n");
}
if(slot.contents.authors){
for(var i = 0; i < slot.contents.authors.length; i++){
var author = slot.contents.authors[i];
description += "\\n\\nAutor: " + author.name + " (" + author.uuid + ") \\n:" + author.description.replace(/(\r\n|\n|\r)/gm,"");
}
}
if(slot.contents.description){
writer.log(description);
}
writer.log("END:VEVENT");
}, this);
}, this);
}, this);
writer.log("END:VCALENDAR");
if(writer.end){
writer.end();
}

view raw
gistfile1.js
hosted with ❤ by GitHub

Una de las cosas que nos aporta JavaScript, es que, al ser dinámicamente tipado, podemos abstraer la consola en un objeto creado por nosotros, y asignarlo o no a la consola en función de nuestra necesidad.

Como detalle a tener en cuenta está el uso de saltos de línea, ya que hemos de utilizar \n, de otra manera, se generará una nueva línea en el fichero de texto resultante y tendremos un error al importarlo.

Además, aunque parezca obvio, podemos tener más de un evento en un mismo fichero ics.

Cuarto paso, probarlo

Por último, y no por ello menos importante, es necesario confirmar que nuestro calendario se ha generado correctamente, para lo que podemos utilizar servicios como iCalendar validator. Finalmente recomiendo utilizar alguna aplicación de escritorio (como iCal en Mac) para hacer un par de importaciones y comprobar que todos los eventos se generan correctamente.

Conclusiones

Podemos generar un calendario utilizando el formato ics y teniendo una fuente de origen de datos. Si nuestra fuente está en formato json, podemos utilizar JavaScript de manera sencilla para movernos por el mismo, y generar nuestro fichero de resultado, que, por cierto, tienes disponible públicamente en Github.

Yo ya tengo mi calendario, y tú?

Enlaces adicionales:

Kanwal, mi propio Trello dentro del firewall

He de reconocer que soy un gran fan de Trello, un tablero de Kanban personalizable que me permite organizar mi agenda, mis objetivos personales, los viajes, las charlas, mis proyectos y los regalos de navidad, entre otros.

Sin embargo, para uso profesional he descubierto que muchas empresas que no permiten guardar información relacionada con proyectos en servicios en la nube, y para ello he creado un pequeño clon de Trello llamado Kanwal, para poderlo utilizar de manera segura dentro el firewall.

Para poder empezar a utilizarla necesitaba, como mínimo, las siguientes características:

  • Aregar listas
  • Agregar elementos a las listas
  • Borrar elementos de las listas

Características como mover un elemento de lista o editar elementos pueden ser muy chulas, aunque entrarán en la siguiente versión.

Con esa máxima tocaba escoger armas, y en mi caso fueron dos que ya había utilizado anteriormente:

  • Knockout.JS: Un framework MVVM muy sencillo y ligero que me permite realizar data-bindings de manera rápida y fácil
  • Bootstrap: Un framework CSS que me permite dar una estructura y un aspecto básicos a la web.
  • Yeoman: Una herramienta que nos permite crear proyectos con diferentes frameworks de manera rápida y sencilla.

Con las armas escogidas, tocaba ponerse manos a la obra, y un par de horas después la aplicación (si es que podemos llamarla aplicación) tenía este aspecto: Espartano, básico, pero es todo lo que necesito para empezar a trabajar:

kanwall-v1

La arquitectura es muy simple:

Una tarea:

  • Es una cadena de texto simple

Una lista:

  • Es un Viewmodel que contiene un título y una lista de tareas.
  • Contiene un método para agregar tareas, para borrarlas y para renombrar la lista, pasando a un sencillo “modo edición”.
  • Contiene una referencia al método guardar del viewmodel global.

El viemodel global:

  • Es una lista de listas.
  • Contiene Métodos para guardar y cargar los datos de local storage.

Como curiosidad, el nombre original era Kan-Wall (de Kanban firewall), aunque gracias a la corrección de Google descubrí que el nombre (con una L) correspondía a una región de Australia, así que así se ha quedado.

Le puedes echar un vistazo a la aplicación en rlbisbe.github.io/kanwal y ver el código fuente en github.
Si estás interesado en ayudar, envíame una pull request!

Have fun!

Explicando Promises de JavaScript con un ejemplo simple

Hace unos días tuve la oportunidad de ver, una vez más, explicado el concepto de promesas y de objetos asíncronos, cuyo objetivo es, entre otros, evitar el llamado “callback-hell” que surge cuando llamamos a una función asíncrona en JavaScript.

En nuestro código frontend, es bastante habitual encontrarnos con funciones con este aspecto:

function myFunction(arguments,onSuccess,onError){
//Do things...
}

myFunction({val: 12}, function(){
    //Do things on success
}, function(){
    //Do things on error
});

El problema surge cuando encadenamos varias llamadas asíncronas, y ya no somos capaces de saber en qué función estamos ní cómo hemos llegado allí, además que el código se hace más difícil de leer.

Las promises o promesas, son objetos que nos permiten mejorar la legibilidad de nuestro código y evitar tener que pasar el contenido de las funciones directamente como argumentos a nuestra llamada.

En este artículo veremos una implementación muy simple de una promesa, para ver cómo funciona realmente, y comprobar que la base es un objeto simple con ciertas propiedades.

Nuestra clase Promise

Veamos por encima qué tenemos en nuestra clase Promise:

function Promise(){

    var self = this;
    var thenCallback = null;

    self.then = function(callback){
        thenCallback = callback;
    };

    self.complete = function(args){
        if (thenCallback &amp;&amp; typeof thenCallback === 'function'){
            thenCallback(args);
        }
    };
}

Esta clase define dos funciones, una función then, en la que especificamos la función a ejecutar al terminar la acción, y una función complete, que nos permite ejecutar la función que hayamos definido, pasandole los argumentos necesarios.

Veamos un ejemplo de uso:

function myFunction(){

    var p = new Promise();
    setTimeout(p.complete, 1000)
    return p;
}

var promise = myFunction()
promise.then(function(){
    console.log('done');
});

En este caso, por una parte simulamos una llamada asíncrona con la función setTimeout, y por otra parte devolvemos la promesa. En el código que llama a la función, nos suscribimos al resultado de esa promesa, y podemos separar la ejecución de la función del tratamiento del resultado de la misma.

Gestión de errores y encadenamiento de promesas

Además de ejecutar funciones cuando todo ha ido bien, hemos de ser capaces de ejecutar acciones cuando se ha producido un error.

Para ello solamente tenemos que extender nuestra clase, agregando dos funciones adicionales, una se suscriba al error, que llamaremos error, y otra que ejecute la acción de error, que llamaremos fail.

self.error = function(callback){
        failCallback = callback;
};

self.fail = function(args){
    if (failCallback &amp;&amp; typeof failCallback === 'function'){
        failCallback(args);
    }
}

Por otra parte, mediante un pequeño cambio podemos encadenar resultados:

self.error = function(callback){
        failCallback = callback;
        return self;
};

Este encadenamiento nos permite tener interfaces más fluidas, de tal manera que por una parte nos suscribimos al resultado de una función, y por otra parte al posible error:

promise.then(function(args){
    console.log('foo has happened ' + args);
}).error(function(args){
    console.log('error has happened');
});

Funciones “always”

Además de código que se ejecute cuando todo ha ido bien, o cuando todo ha ido mal, es posible que necesitemos código que se ejecute siempre, independientemente del resultado, lo que sería equivalente a la directiva “finally” de una función de C#.

Para ello solamente necesitamos agregar un nuevo callback a nuestra lista, que se ejecutará en caso de éxito o de fallo.

Conclusiones

Como vemos, las promesas no son “magia” que tienen algunas bibliotecas de JavaScript. Simplemente es otra sintaxis, otra manera de recuperar el control tras volver de una función asíncrona.

Si echamos un vistazo a lo que se propone para ECMAScript 6, lo que en la práctica será la próxima versión de JavaScript, veremos que las ideas son muy similares a lo que hemos visto en este artículo, aunque más extendido y detallado.

Tienes el código completo de la promesa en este gist

Enlaces adicionales

Diferentes tipos de “Promises”

Gracias a Antón Molleda (@molant) por los enlaces!

Vídeos y material de “Lecciones aprendidas creando una red social” con MadridJS

Este jueves he podido compartir con los chicos de MadridJS así como varios alumnos del programa Ironhack, nuestra experiencia con javascript desarrollando una red social enfocada al desarrollo científico. Durante poco menos de una hora (y luego durante las cañas) repasamos herramientas, metodologías, y pruebas que hacemos en nuestros sistemas, así como las lecciones que hemos aprendido en el camino. En este artículo podrás encontrar el vídeo del evento, las slides de slideshare así como enlaces adicionales de temas que surgieron durante el mismo.

El debate fue muy interesante y personalmente he descubierto un montón de cosas nuevas para estudiar, gracias a todos los asistentes.

Vídeo

Slides

Enlaces adicionales de temas que surgieron en la charla:

Evento para acabar el año: Lecciones aprendidas creando una red social

global_139815902

El próximo jueves 18 a las 19:00 vuelvo a MadridJS en mi última charla del año, en la que veremos algunas lecciones aprendidas tras haber estado durante varios meses involucrado en el desarrollo de una red social.

En esta sesión veremos algunas tecnologías, frameworks y herramientas que hemos usado tanto para desarrollar, hacer pruebas tanto unitarias como de aceptación, y finalmente para temas relacionados con despliegue de la parte frontend de la plataforma, así como algunas anécdotas y problemas a los que nos enfrentamos en los diferentes procesos tanto de creación del portal como de puesta en producción.

Además, veremos herramientas y librerías como knockout, sammy, qunit, sinon y selenium.

Inscríbete en: http://www.meetup.com/madridjs/events/219137077/

Te espero allí!

Adding multiple languages to a Windows Store app with Javascript and Angular

Leer este artículo en castellano aqui

Last thursday I could attend a debate organized by MSCoders Madrid user group, related with localization of apps in a web enfironment.

After the event I got interested in frontend localization with Javascript. As Karmacracy for Windows is a Javascript app, I decided to do some experimentation on localizing the user interface in the context of a Windows Store app, to be able to distribute it for other markets.

Detecting the system language

For a Windows Store app the first thing to do is to detect the sustem language. This can be archieved with the following piece of code:

var culture = Windows.System.UserProfile.GlobalizationPreferences.languages[0];
var language = culture.substr(0, 2);

The culture is the language that is currently being used for the UI, in culture format. For example for Spanish of Spain would be es-ES, for US English would be en-US, and for British English would be en-GB. To be able to change this order and deploy our app, we must go to the control panel:

Captura de pantalla 2014-09-15 00.29.43

In this example we only need the language, not the culture, so we are going to get a substring of the culture getting en, es, de, etc.

Adding angular-translate

Angular-translate is a module that allows us to define key-value pairs for each language and perform the translation according to the configuration. For installing it, if we don’t use a package manager such as bower, we must download the last package from github and add it to our project.

Once installed, we must add it to the configuration of our app, in the section we define external modules (in this case the module is pascalprechtr.translate).

var karmacracyApp = angular.module('karmacracyApp', [
    'ngRoute',
    'karmacracyControllers',
    'pascalprecht.translate'
]);

Finally, we configure the different languages by using the code we defined previously for getting the OS display language:

karmacracyApp.config(['$translateProvider', function ($translateProvider) {
    $translateProvider.translations('en', {
        'LOGIN': 'Log in',
        'LOGIN_USERNAME': 'User name',
        'LOGIN_PASSWORD': 'Password'
    });

    $translateProvider.translations('es', {
        'LOGIN': 'Inicia sesión',
        'LOGIN_USERNAME': 'Nombre de usuario',
        'LOGIN_PASSWORD': 'Contraseña'
    });

    var culture = Windows.System.UserProfile.GlobalizationPreferences.languages[0];
    var language = culture.substr(0, 2);

     $translateProvider.preferredLanguage(language).fallbackLanguage('en');
}]);

Also, in case the current language is not available, we set English by default

#Usage

For accessing our keys we don’t need any aditional configuration on our controllers, we just need to modify our views so they can access the localized information

<span class="loginMessage">{{ 'LOGIN' | translate }}</span>

If the language is set to English or other language not controlled, the result will be the following:

en

If the language is set to spanish, the result will be the following:

es

As it shows, is an easy way to localize our javascript apps for the Windows Store.

Recap and next steps

Angular-translate provides a simple way of localizing texts in our views and Windows provides the information we need for setting the current language of an app.

As an aditional step, we may try to localize winjs controls such as buttons, which work in a very different way. Angular-translate also supports loading the translations from a json files, an option that may be useful if we want to distribute those files for translation by 3rd parties.

Links

Agregando múltiples idiomas a una aplicación de Windows Store con Javascript y Angular

**Read this article in English here

El pasado jueves tuve la ocasión de asistir a una mesa redonda organizada por el grupo MSCoders relacionada con la localización de aplicaciones en entornos web.

Tras el evento, uno de los temas que más llamó mi atención fue la localización en la parte Javascript, y como tenía una aplicación ya en la Windows Store que usaba ese lenguaje, me pareció interesante intentar localizarla para poder ofrecerla en otros mercados.

Detectando el idioma del sistema

Para una aplicación Windows 8 el primer paso es detectar el idioma del sistema, y eso lo podemos hacer de la siguiente manera:

var culture = Windows.System.UserProfile.GlobalizationPreferences.languages[0];
var language = culture.substr(0, 2);

En este caso tomaremos la lista de lenguajes preferentes, y de esa lista obtendremos el primer elemento. Para poder cambiar el orden de los elementos y probar los diferentes lenguajes, podemos cambiarlo en el panel de control:

Captura de pantalla 2014-09-15 00.29.43

El resultado se muestra en formato cultura, es decir, español de España se mostraría como es-ES, e inglés de EEUU se mostraría como en-US. Para nuestro ejemplo inicial, solamente necesitamos el idioma, con lo cual hacemos un substring y obtenemos en o es respectivamente.

Agregando angular-translate

Angular-translate es un módulo de angular que nos permite definir de manera las claves y los valores para cada lenguaje, y realizar la traducción en función de la configuración. Para instalarlo, si no contamos con gestores de paquetes como bower, es tan sencillo como descargar el último paquete de github y agregarlo a nuestro proyecto.

Una vez instalado, tendremos que agregarlo a la configuración de nuestra app, en el apartado en el que definimos módulos externos en este caso pascalprecht.translate:

var karmacracyApp = angular.module('karmacracyApp', [
    'ngRoute',
    'karmacracyControllers',
    'pascalprecht.translate'
]);

Finalmente, configuramos los diferentes idiomas usando el código que hemos visto anteriormente para seleccionar un idioma acorde con el sistema operativo:

karmacracyApp.config(['$translateProvider', function ($translateProvider) {
    $translateProvider.translations('en', {
        'LOGIN': 'Log in',
        'LOGIN_USERNAME': 'User name',
        'LOGIN_PASSWORD': 'Password'
    });

    $translateProvider.translations('es', {
        'LOGIN': 'Inicia sesión',
        'LOGIN_USERNAME': 'Nombre de usuario',
        'LOGIN_PASSWORD': 'Contraseña'
    });

    var culture = Windows.System.UserProfile.GlobalizationPreferences.languages[0];
    var language = culture.substr(0, 2);

    $translateProvider.preferredLanguage(language).fallbackLanguage('en');
}]);

Además, en caso de que el sistema tenga un idioma no controlado, estableceremos el inglés por defecto.

Uso

Para acceder a nuestras claves no necesitamos realizar ninguna configuración adicional en nuestros controladores, solamente necesitamos modificar nuestras vistas para que accedan a la información localizada:

<span class="loginMessage">{{ 'LOGIN' | translate }}</span>

En caso de que tengamos el idioma establecido a inglés (o a cualquier idioma no controlado), se mostrará el siguiente resultado:

en

En caso de que el idioma esté establecido a español, el resultado será diferente:

es

Como se ve, es una manera sencilla de poder localizar nuestras aplicaciones en javsacript para Windows Store

Conclusiones y pasos adicionales

Angular-translate proporciona una manera sencilla de localizar textos en nuestras vistas, por otra parte, Windows proporciona, a través de su API, la información que necesitamos para saber en qué idioma mostrar una aplicación.

Un paso adicional sería localizar controles winjs como los botones, que funcionan de manera diferente. Por otra parte se podría sacar un fichero de traducciones fuera de la configuración en formato json, útil si queremos distribuir esos ficheros para su procesamiento.

Enlaces adicionales

Artículo Invitado: ECMAScript 6 y la nueva era de JavaScript por @CKGrafico

Comenzamos con este artículo una nueva sección llamada “Artículos Invitados”, en este caso tengo la suerte de contar con Quique Fernandez Guerra, Microsoft Student Partner y desarrollador Javascript:

Quique Fdez GuerraQuique Fdez. Guerra
Desarrollador y amante de JavaScript
Twitter: @CKGrafico
Web: CKGrafico.com

Quique es un usuario muy activo de comunidades de desarrollo frontend, y le hemos visto en varios hangouts mostrando su experiencia, así que le he pedido que nos cuente sus impresiones de lo que está por venir en la nueva versión del estandar ECMAScript 6, en el cual se basarán las próximas versiones de Javascript. A continuación sus impresiones


Desde siempre se ha considerado a JavaScript cómo un lenguaje simplón, es seguramente uno de los lenguajes actuales más sencillos de aprender, pero además es conocido por no ser muy completo (ya sea por la manera de trabajar con las clases, o los artículos sobre ‘JavaScript the weird parts’).

Por otro lado, en los últimos años JavaScript a empezado a tener más importancia hasta el punto que se ha vuelto el único lenguaje universal, es decir, lo encontramos en web, servidor, hardware, móvil, etc, cómo ya comenté en un artículo hace un tiempo.

Aún así el lenguaje sigue igual, de hecho ha llegado un momento en que la gente sabe mucho más sobre frameworks del lenguaje que del propio lenguaje. Está lleno de ofertas de trabajo en las que se pide conocimientos en jQuery y Backbone o Angular y por supuesto hay mucha gente aprendiendo directamente estos frameworks (Aprender un framework antes de saber el propio lenguaje…).

Por suerte, parece que con la nueva versión del estándar ECMAScript vamos a poder tomar más en serio JavaScript, aunque cómo siempre vamos a tener que esperar que todos los navegadores lo soporten. A continuación voy a explicar las partes que considero más importantes de esta nueva versión.

Declaración let

Ahora podemos declarar variables que existan solo en un bloque de código, entendiendo por bloque de código desde una función hasta un bucle o una condición.


if(1) {
var a = 5;
let b = 6;
console.log(a,b); // 5 6
}

console.log(a,b); // b is not defined

Constantes, ¡¡Sí constantes!!

Ya era hora de poder utilizar constantes en nuestro apreciado JavaScript, muy sencillas de utilizar igual que en otros lenguajes.

const PI = 3.14;
console.log(PI); // 3.14

function test() {
 console.log('test', PI); // test 3.14
}

test();

PI = 6; // Error!!

Arrow functions

Si trabajas con lenguajes cómo C# que tienen lambda verás que es algo parecido, que se ha traído a JavaScript.

let simple = a => a / 2;
console.log(simple(8)); // 4

let complex = (a, b) => {
 if (a < b) {
 return a;
 }
 return b;
}

console.log(complex(3,6)); // 3

Valores por defecto en parámetros

Otro ejemplo más de algo que tienen casi todos los lenguajes y JavaScript aún no lo tenía, pero ya está aquí.

function test(a, b = 10) {
 return a + b;
}

console.log(test(1)); // 11
console.log(test(1,2)); // 3

Rest parameters

Nos va a ser muy útil cuando no sepamos el número de parámetros exactos, muchas veces usábamos arguments para eso, pero ahora vamos a tenerlo mucho más fácil.

function test(a, b = 1, ...c) {
 return a + b + c.length || 0;
}

console.log(test(1)); // 2
console.log(test(1,10,1,1,1,1)); // 15

Pero no solo eso, también lo vamos a poder utilizar en un array o al llamar a una función.

let arr = [4, 5, 6];
let numbers = [1, 2, 3, ...arr, 7, 8];

console.log(numbers); // [1, 2, 3, 4, 5, 6, 7, 8]

Object literals

Simplificaremos los objetos, de manera que no haya que poner información irrelevante.

// ECMA 5
var world = 'world';
var obj = {
 world: world,
 hello: function() {
 console.log('hello', this.world);
 }
};

obj.hello(); // hello world

// ECMA 6
let world6 = 'world';
let obj6 = {
 world6,
 hello() {
 console.log('hello6', this.world6);
 }
};

obj6.hello(); // hello6 world

for..of

La evolución lógica del for..in

// ECMA 5
var arr = ['a', 'b', 'c'];
for(var i in arr) {
 console.log(arr[i]); // a, b, c
}

// ECMA 6
let arr6 = ['a', 'b', 'c'];
for(let i of arr6) {
 console.log(i); // a, b, c
}

Generadores

Un nuevo tipo de función que nos ayuda a crear un iterador de manera fácil, utilizan yield en vez de return que es una nueva palabra reservada.

function* range(start, end) {
 for (let i = start; i <= end; i++) {
 yield i;
 }
}

var ranger = range(1,10);

var res = {
 value: null,
 done: false
};

while(!res.done){
 res = ranger.next();
 console.log(res.value, res.done);
}

Symbol

symbol es un nuevo tipo de dato y Symbol() nos devuelve un objeto único de tipo symbol, pensado para tener objetos o métodos que son distintos de los demás, sería un sustituto a usar cadenas para los nombres de los métodos por ejemplo.

let myMethod = Symbol();
let obj = {
 [myMethod]() {
 console.log('Soy único e irrepetible');
 }
};

obj[myMethod](); // Soy único e irrepetible
console.log(typeof myMethod); // symbol

Map

El objeto Map  es un objeto de clave / valor, la mejor manera de entenderlo es ver un ejemplo.

let map = new Map();
let arr = [];
map.set('string', 'Ola k ase');
map.set(arr, [1, 2, 3, 4]);
map.set(typeof 8, 'I\'m a number');

console.log(map.size); // 4

console.log(map.get('string')); // Ola k ase
console.log(map.get(typeof 1)); // I'm a number
console.log(map.get([])); // undefined -> arr !== []
console.log(map.get(arr)); // [1, 2, 3, 4]

Set

Sirve para poder crear algo parecido a las listas en otros lenguajes, aunque aún bastante simple.

let set = new Set();
set.add('test');
set.add(8);
set.add('Quique');

console.log(set.size); // 3
console.log(set.has(8)); // true

set.delete('Quique');

set.forEach(function(value) {
 console.log(value); // test 8
});

Clases

Vamos a tener clases en condiciones, más o menos van a hacer lo mismo que hasta ahora pero vamos a tener una sintaxis más sencilla para implementarlas.

class Human {
 constructor(name = 'anonymous') {
 this.name = name;
 }

 hello() {
 console.log('Welcome to the world ' + this.name);
 }
}

class Male extends Human {
 constructor(name) {
 super(name);
 this.sex = 'male';
 }

 get age() {
 return this._age;
 }

 set age(age) {
 this._age = age;
 }
}

let me = new Male('Quique');
me.hello();
me.age = 1;
console.log(me.age); // 1

Módulos

Ha llegado la hora de poder crear partes de nuestro código por separado e importarlas cuando nos sea conveniente, para no cargarlo todo de golpe y trabajar de una manera ordenada.

// number.js
module 'number' {
 let num = 8;
 export class Number {
     constructor() {
         console.log('The number is: ' + num);
     }
 }

}

// app.js
module number from '/number.js';
import Number from 'number';

var n = new Number(); // The number is 8

Templates

Una de las cosas que más he usado este último año en JavaScript han sido los templates, sobretodo trabajando Handlebars, pues ahora mismo se convierten en algo propio de este lenguaje.

let name = 'Quique', twitter = 'CKGrafico';
let template = `Hello, this is ${name}, find my on ${twitter}`;
// Nota, fíjate en las ` que no es lo mismo que '
console.log(template); // Hello, this is Quique, find my on CKGrafico

Estas son las cosas más destacables que trae la nueva versión, puedes encontrar la lista entera en su especificación.

Mientras esperas a que sea compatible en los navegadores puedes trabajar con ECMA6 en ES6 fiddle (un sandbox) o utilizar un pequeño transpiler llamado Traceur que te permite trabajar en ECMA6 y compilar a ECMA5

 


Si tienes preguntas o comentarios no dudes en dejarlas en la sección de comentarios, y si tienes más información sobre Quique, aquí tienes algunos datos de contacto:

Quique Fdez GuerraQuique Fdez. Guerra
Desarrollador y amante de JavaScript
Twitter: @CKGrafico
Web: CKGrafico.com

Cacheando con Varnish un proyecto ASP.net MVC5

Una caché, por definición, es un almacenamiento a corto plazo de información y con una altísima velocidad de acceso, permitiéndonos mejorar el rendimiento de nuestros sistemas. En el caso de la web podemos diferenciar dos tipos:

  • Caché de cliente, que se hace en el navegador y que nos permite no tener que traer de internet imágenes o ficheros de estilo una vez hemos obtenido una copia.
  • Caché de servidor, que guarda una copia de manera temporal para evitar sobrecarga de nuestro servidor de aplicaciones.

Esto último tiene una justificación, y es que el acceso a las aplicaciones (PHP, ASP.net, Ruby) es un proceso relativamente lento que suele estar acompañado de un acceso a una base de datos, una aplicación de la lógica de negocio y la composición final de la página.

Existen diferentes sistemas y tipos de caché, como Memcached o Redis. En este artículo hablaremos de Varnish, un proyecto open-source que se instala sobre sistemas UNIX (aunque tiene soporte para Windows mediante Cygwin).

La principal peculiaridad que tiene este sistema, además de sus casi-infinitas opciones de configuración, es que permite dividir nuestra página en trozos y cachearlos de manera independiente, en función del intervalo de actualización de los mismos, un proceso conocido como Edge Side Includes (ESI) y que veremos a lo largo del artículo.

Instalación y configuración

La instalación de Varnish es un proceso tan simple como brew install varnish si usamos homebrew en mac. Una vez instalado, para ejecutarlo usamos el siguiente comando:

sudo /usr/local/opt/varnish/sbin/varnishd -n /usr/local/var/varnish -f /usr/local/etc/varnish/default.vcl -s malloc,1G -T 127.0.0.1:2000 -a 0.0.0.0:8082

pasando como parámetros las siguientes opciones:

  • Ruta del fichero de configuración
  • Puerto de registro de log
  • Máximo consumo de RAM
  • Puerto de escucha (en nuestro caso el 8082)

El fichero de configuración default.vcl, para nuestro ejemplo, contiene las siguientes directivas:

backend default {
    .host = "127.0.0.1";
    .port = "8087";
}

sub vcl_recv {
	if (req.http.cookie) {
		unset req.http.cookie;
	}
}

sub vcl_fetch {
	
	if (req.url == "/layout/*") {
       set beresp.ttl = 2m;      /* Sets a one minute TTL on        */
    } else {
       set beresp.do_esi = true; /* Do ESI processing               */
       set beresp.ttl = 30s;     /* Sets the TTL on the HTML above  */
    }
    unset beresp.http.set-cookie;
}

sub vcl_deliver {

    if (obj.hits > 0) {
            set resp.http.X-Cache = "HIT";
    } else {
            set resp.http.X-Cache = "MISS";
    }
}

Los comandos que hemos implementado son:

  • backend: Permite especificar qué servidores estarán funcionando al otro lado, se puede especificar una IP o un nombre DNS.

  • vcl_recv: En el caso de ASP.net, se genera una cookie de sesión al acceder al sitio, lo cual no siempre es lo deseable. En este ejemplo se borran todas las que provienen del servidor, de manera que se pueda cachear la página.

  • vcl_fetch: Se ejecuta cuando obtenemos un elemento desde el servidor, y en este caso especificamos que si estamos solicitando algún elemento de “layout” como el menú o la cabecera, ha de cachearlo durante 2 minutos, en caso contrario configuramos para que haga el procesamiento ESI (es decir, que intente unir los pedazos) y cachee el conjunto durante 30 segundos.

  • vcl_deliver: Nos permite editar la cabecera HTTP para saber si ha podido resolver el elemento en la caché o si ha tenido que acceder al servidor de aplicaciones.

Cacheando voy, cacheando vengo:

En este ejemplo hemos usado una plantilla de bootstrap que tiene el siguiente aspecto dentro de una aplicación prácticamente vacía en MVC5:

goal

Lo primero que podemos apreciar son tres zonas claramente diferenciadas, una cabecera, una barra lateral, y, finalmente, un área de contenido principal.

Estructura

Para mostrar la página, empleamos un controlador muy sencillo que genera una espera de 3 segundos para simular carga del servidor y almacena la fecha de generación en el ViewData:

public class HomeController : Controller
{
	public ActionResult Index ()
	{
		ViewData ["now"] = String.Format ("{0:HH:mm:ss}", DateTime.Now);
		System.Threading.Thread.Sleep (3000);
		return View ("Index");
	}
}

De manera adicional y para poder aplicar ESI, necesitaremos dividir nuestra vista en tres vistas diferentes que correspondan a acciones diferentes del controlador, que serán:

  • / <- que genera el contenido de la página
  • /layout/header <- que genera la cabecera
  • /layout/sidebar <- que genera la barra lateral

Las dos acciones del controlador Layout son idénticas, como muestra el código:

public class LayoutController : Controller
{
    public ActionResult Sidebar()
    {
		ViewData ["now"] = String.Format ("{0:HH:mm:ss}", DateTime.Now);
		System.Threading.Thread.Sleep (3000);
        return View ("Sidebar");
    }

	public ActionResult Header()
	{
		ViewData ["now"] = String.Format ("{0:HH:mm:ss}", DateTime.Now);
		System.Threading.Thread.Sleep (3000);
		return View ("Header");
	}
}

Nótese que por cada acción hemos agregado otros 3 segundos de retraso, teniendo un total de 9 segundos en el caso peor.

Para poder activar el ESI en las vistas, usamos etiquetas HTML que tienen el siguiente formato:

<esi:include src="/layout/sidebar" onerror="continue"/>

Además, a modo de prueba, podemos agregar algo de código javascript que se ejecute una vez cargada la página para apreciar la diferencia entre hora de generación y hora de renderización. Si todo ha ido bien, cuando carguemos por primera vez nuestra caché, se encontrará vacía, y sufriremos la espera de los 9 segundos.

En la imagen, G muestra la hora de generación en el servidor y R la hora de renderización en el cliente:

miss

Si volvemos a acceder, comprobaremos que el contenido de la página ya se ha cacheado, que las fechas de generación y de ejecución distan más de tres segundos, y que el inspector nos muestra el tiempo total de acceso a la página (700 milisegundos aprox):

hit

Conclusiones

Ha sido una prueba de concepto muy interesante, el hecho de descubrir que podemos tener nuestra web dividida en secciones con cachés diferentes nos da mucha movilidad al hacer portales con información dinámica. Varnish es una herramienta suficientemente compleja para ser tomada en serio y requiere que estudiemos a fondo sus características antes aplicarla a un sistema en producción.

Lecturas adicionales y enlaces

Del escritorio a la web: Mi charla en Madrid JS

Actualizacion: Vídeo de la charla ya disponible:

http://vimeo.com/92602677

El pasado 10 de abril tuve mi primera experiencia como ponente en el grupo de MadridJS en la sala CAMON de Moncloa, Madrid, donde estuvimos hablando de nuestra evolución desde el escritorio a la web desarrollando el Web Workspace. Este artículo contiene un comentario de los ejemplos usados y las slides empleadas.

Bk4F638IMAEWxPq

Leer más “Del escritorio a la web: Mi charla en Madrid JS”