Adiós 2017... bienvenido 2018

Un año más, que se va,
un año más, cuántos se han ido.
Un año más, que más da,
cuántos se han ido ya…

Hernán Gallardo Pavéz

Esta canción es casi un himno patrio de fin de año y no hay fiesta donde no se toque esta canción, que dicho sea de paso, ha sido interpretada por varias bandas. Aquí les dejo un link para que lean acerca de la historia de ésta canción.

Symbiose SpA y Tecnología

Este año ha sido particularmente extraño en lo que a negocios y pega se refiere. Tuvimos elecciones presidenciales y que durante lo que dura la “incertidumbre”, los proyectos y las inversiones en tecnología se aletargar paralizan bastante. Una vez pasada la “incertidumbre” (para bien o para mal) se vuelven a activar los proyectos. En Symbiose SpA hemos sentidos esos embates del mundo económico y político aunque no tengamos que ver con ninguno de los dos.

En lo técnico quizás lo mas novedoso ha sido programar en nuevos frameworks y lenguajes. Uno de los nuevos frameworks con los que he tenido que sufrir lidiar ha sido Angular + TypeScript. Solo les puedo comentar que este último lenguaje ha sido vilipendiado de la peor forma en el trabajo y básicamente por lo odioso que es el “compilador” y los mensajes de error que salen en la consola de desarrollo del browser (sólo si es que salen). Hace mucho tiempo que no rabiaba tanto con algo que me gusta hacer.

En comparación, usando AngularJS como framework, es bastante mas legible y decente los errores que salen en la consola y los errores típicos son los dolores de cabeza que te da Javascript, que de alguna u otra forma, muchos developers tenemos interiorizados.

Sin lugar a duras en temas tecnológicos el uso de contenedores ha sido protagonista en el desarrollo de microservicios y la aceptación de esta arquitectura que viene de hace hace un par de años. En este ámbito Docker ha sido una de las plataformas que se mantiene en la pelea de la “containerización” junto a Kubernetes.

El uso que le damos a diario a estas herramientas van de la mano con Continuous Integration y Continuous Delivery evitando así HH preciadas de los desarrolladores peleando contra los servidores de aplicación, bases datos y cuanta aplicación ofrezca pelea. Para resumir este punto, que mejor que utilizar la palabra AUTOMATIZACIÓN.

Para finalizar lo técnico, sigo acumulando horas de vuelo SpringFramework y toda sus componentes orientados a crear microservicios y ambientes cloud. Cada release nueva de estos componentes traen un montón de nuevas funcionalidades que nos hace la vida mas fácil a la hora de pensar en soluciones Cloud. Kudos para los developers de SpringFramework.

Libros varios

Un hobby que había dejado totalmente en el olvido era el de leer. Tenía mi Kindle juntando polvo en algún rincón hasta que me puse la meta de leer al menos 1 libro al mes (empezando como en septiembre) y puedo decir que me fue bastante bien. Les dejo un listado de libros interesantes que pude leer o terminar de leer durante el año pasado:

Cabe destacar todos estos libros son de escritores Chilenos y que por cierto disfruté cada uno en su ámbito. El libro de Patricio Bañados es como estar tras bambalinas de TVN en los tiempos donde nuestro país paso por un periodo triste de su historia. Pero lo mas interesante es cuando superamos el periodo de la dictadura y las historias de codazos, volteretas y bajezas políticas se hacen presente en la vida del Relator.

Los libros de Ciencias de José Maza, Gabriel León y María Teresa Ruíz todos tienen la característica de un lenguaje muy simple y de fácil comprensión. Todos ellos muy entretenidos. Ciencia Pop tiene muchas anécdotas científicas y descubrimientos que se han hecho de casualidad (como la mayoría de los descubrimientos científicos). Somos polvo de estrellas y Hijos de las estrellas nos invitan a reflexionar sobre el origen del universo, sobre el origen de la vida y de qué estamos hechos, literalmente… Polvo de estrellas.

Sobre la Naturaleza del Software, también es un libro de fácil lectura con muchas anécdotas del mundo informático. También invita a reflexionar sobre la evolución de la Ingeniería Informática, los errores recurrentes en esta área, de lo joven que es esta rama de la ingeniería y las comparaciones odiosas con otras ramas. Destaca a grandes personajes que han participado en la evolución del cómo se construye software hasta el día de hoy.

En proceso de lectura aún:

Sobre “Contacto” de Carl Sagan, es un libro lleno de detalles y abundante en información de los personajes… muy muy descriptivo (a veces aburre un poco). Lo que me chocó es que uno espera una cierta similitud con la película Contacto y dicha similitud no es tal. La película la habré visto al menos una docena de veces y siempre emociona el momento en que empieza a escuchar los pulsos que provienen de la estrella Vega o al final cuando les habla apasionadamente a los niños sobre el universo. El libro es totalmente diferente o mejor dicho… la película es “basada” en la novela original de Carl Sagan.

Lo mismo me pasó con “Yo, Robot”, la película es también una de mis favoritas y con el libro no pega ni junta, aunque la trama del libro es la misma que se trata en la película y tiene que ver con el conflicto que hay con las 3 leyes de la robótica, pero en muchas situaciones diferentes a la película. El libro contiene un conjunto historias cortas que hablan de la forma en que los robots interactúan con los humanos en situaciones límite exigiendo al máximo las 3 leyes de la robótica. Interesante libro!

Alguna sugerencia de lectura para este año? déjenlo en los comentarios.

Palabras al cierre

Feliz 2018 para todos! Bienvenido 2018!

y si… voy a escribir mas este año :D

TodoList Con Node.js Y MongoDB - Parte II

Lo prometido es deuda, aquí vamos con la segunda parte donde integraremos Passport para poder validar los request y contronlar sesiones de usuarios.

Primero debemos agregar los siguientes imports al archivo app.js y la estrategia (plugin de autenticación) a utilizar. Además se agregan los archivos UserModel.js y security.js extensión del modelo de User y métodos de validación del request respectivamente:

1
2
3
4
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var security = require('./config/security');
var User = require('./model/UserModel');

Ahora configuramos Express para que pueda utilizar Passport como administrador de sesiones de usuario. Es necesario que express use su propio administrador de sesiones y además debe ser inicializado antes que el de passport.

1
2
3
4
5
6
app.use(express.cookieParser('your secret here'));
app.use(express.session());

// passport initialize
app.use(passport.initialize());
app.use(passport.session());

Luego agregamos mecanismos de autenticación, serialización y deserialización a passport:

1
2
3
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());

Model

Ahora extendemos el modelo de usuario para agregar nuestros atributos (si es es necesario, por ahora lo dejaremos vacío):

1
2
3
4
5
6
7
8
9
10
var mongoose = require('mongoose');
var passportLocalMongoose = require('passport-local-mongoose');

var UserSchema = new mongoose.Schema({});

UserSchema.plugin(passportLocalMongoose);

var UserModel = mongoose.model('User', UserSchema);

module.exports = UserModel;

Seguridad

Hay un archivo que se llama security.js que contiene una función que valida si el request solicitado está autenticado por passport, si está autenticado lo “deja pasar” (next), de lo contrario lo redirecciona al template de login.

1
2
3
4
5
6
exports.ensureAuthenticated = function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/login');
};

Nos queda asegurar las urls o recursos que necesitemos con la función ensureAuthenticated en el archivo app.js. La idea es que sea lo menos intrusivo posible. Hay dos formas de hacerlo, la primera es intrusiva (y no recomendada aunque puede utilizarse con fines específicos) y se debe realizar por cada request en los archivos que contienen los Controllers:

1
2
3
4
5
6
7
exports.authenticationExample = function(req, res) {
if (req.isAuthenticated()) {
// Do something
} else {
res.redirect('/login');
}
}

La segunda es interceptando los request y validando según algún patrón, que es nuestro caso. Esta configuración esta en app.js donde se declaran las rutas a los Controllers:

1
2
app.all('/api/*', security.ensureAuthenticated);
app.all('/todos', security.ensureAuthenticated);

Con esto interceptamos todos los request que van a la API y los que van a /todos y los hacemos pasar por la función de autenticación de request. Con esto evitamos poner dichas líneas de autenticación en cada controller.

Login y Logout

Finalmente nos queda la última parte respecto de la autenticación y es configurar el login y el logout. Para el login usamos la API de passport y delegamos el trabajo de autenticación de la siguiente forma (configuración):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* Funcion sin autenticación que permite desplegar el template de Login
*/
app.get('/login', function(req, res) {
res.render('login', {});
});

/**
* Función de login que permite delegar la autenticacion en la API de
* passport, se configura además cuando la autenticación es exitosa a que url
* lo debe redireccinar y lo mismo en caso de error.
*/
app.post('/login', passport.authenticate('local', {
successRedirect: '/todos',
failureRedirect: '/login'
}));

El logout es más sencillo y lo único que hay que hacer es invalidar el request, destruir la sesión del usuario y redireccionar al login.

1
2
3
4
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/login');
});

Me queda pendiente en la próxima parte del tutorial explicar cómo consumir estos servicios usando angular y desplegar los templates.

TodoList con Node.js y MongoDB - Parte I

Llevo un tiempo estudiando y haciendo algunas cosas con Node.js y me he llevado una grata impresión con esta plataforma. Al principio cuesta un poco entender el cómo funciona ya que el paradigma es muy distinto del que he venido usando durante este último tiempo.

Me animé y empece a usar Node.js para hacer algo simple y así tratar de entender el cómo funciona. Para hacer algo mas sabrosa la experiencia agregué algunos ingredientes adicionales, un framework para desarrollo web llamado Express, Mongoose para modelar los documentos que van a ir a parar a MongoDB, Passport para autenticar los request (control de usuarios y permisos), uso de templates con EJS y finalmente para la vista usamos el framework AngularJS. Como podrán ver es un stack de tecnologías basadas en Javascript.

Para iniciar voy a explicar algunas partes del código que personalmente me costó entender e implementar. Algunos de esos puntos fueron la integración con passport para la autenticación de los request, control de usuario y uso de datos en sesión.

Configuración de node.js

Cuando utilizamos nodejs siempre hay un archivo principal donde se configura toda la plataforma, en este caso el archivo es llamado app.js. Voy a ir mostrando ciertas partes del código (si quieren ver el código, esta disponible en github):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var express = require('express');

var indexController = require('./routes/IndexController');
var todosController = require('./routes/TodosController');
var registerController = require('./routes/RegisterController');

var http = require('http');
var path = require('path');
var app = express();
var db = require('./config/database');


var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;

var security = require('./config/security');
var User = require('./model/UserModel');

Controllers

Lo primero es incluir el módulo de express y luego los Controllers de la aplicación. Veamos el código de IndexController

1
2
3
4
5
exports.index = function(req, res) {
res.render('todos', {
user: req.user
});
};

Este es el Controller mas simple de la aplicación, lo único que hace es exponer mediante exports la función index cuya responsabilidad es desplegar la página principal de la aplicación. Lo demás está en el controlador de la API que será llamada desde dicha página (usando ajax).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
var Todo = require('../model/TodosModel');

/**
* Busca todos los todos para el usuario registrado
* @param {Object} req request
* @param {Object} res response
*/
function findAllTodosByUser(req, res) {
var userId = req.user.id;

Todo.find()
.where('creator')
.equals(userId)
.sort('date')
.exec(function(err, todos) {
if (err) {
res.send(err);
}
res.json(todos);
});
}

exports.allTodos = findAllTodosByUser;

/**
* Crea un todo para el usuario
* @param {Object} req request
* @param {Object} res response
* @return {Object} Lista de todos
*/
exports.createTodo = function(req, res) {
var userId = req.user.id;
var textTodo = req.body.text;

Todo.create({
text: textTodo,
done: false,
creator: userId
}, function(error, todo) {
if (error) {
res.send(error);
}
findAllTodosByUser(req, res);
});
}

/**
* Elimina un Todo por su ID
* @param {Object} req request
* @param {Object} res response
* @return {Object} Lista de todos
*/
exports.deleteTodo = function(req, res) {
Todo.remove({
_id: req.params.todo_id
}, function(error, todo) {
if (error) {
res.send(error);
}
findAllTodosByUser(req, res);
});
}

Este controlador expone la API REST con la que se comunicará la pagina principal, haciendo llamadas ajax a los distintos métodos. En esta pieza se hace un require de otro script que representa el Model, en este caso es un document para MongoDB.

Model con mongoose

Aquí mostraré como se modeló el documento principal de la aplicación Todo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var mongoose = require('mongoose');

var TodoSchema = new mongoose.Schema({
text: String,
date: {
type: Date,
default: Date.now
},
done: {
type: Boolean,
default: false
},
creator: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
});

var TodoModel = mongoose.model('Todo', TodoSchema);

module.exports = TodoModel;

Primero se incluye el módulo de mongoose que nos permitirá modelar los documentos para MongoDB. Luego se crea un schema para modelar y se le agregan los atributos que va a poseer y sus respectivas validaciones. Por ejemplo, el atributo date es de tipo Date y valor por omisión la fecha de hoy.

Además este schema contiene una referencia a otra Collection para dejar relacionado el usuario creador en sus Todos.

Route y manejo de URLs

Finalmente para que la aplicación funcioné, hay que indicarle a node.js que las urls que se soliciten hay que enviarlas a alguien que las atienda, en este caso, los controladores y sus funciones.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
app.get('/login', function(req, res) {
res.render('login', {});
});

app.post('/login', passport.authenticate('local', {
successRedirect: '/todos',
failureRedirect: '/login'
}));

app.get('/logout', function(req, res) {
req.logout();
res.redirect('/login');
});

app.get('/', function(req, res) {
res.redirect('/login')
})

app.get('/register', registerController.index);
app.post('/register', registerController.registerUser);

app.all('/api/*', security.ensureAuthenticated);
app.all('/todos', security.ensureAuthenticated);

app.get('/todos', indexController.index);
app.get('/api/todos', todosController.allTodos);
app.post('/api/todos', todosController.createTodo);
app.delete('/api/todos/:todo_id', todosController.deleteTodo);

No hay mucho que explicar, a buen programador pocas lineas de código, las urls que ahi aparecen son ruteadas a los controladores o se implementa el callback inline, como por ejemplo las urls de login y logout. Los controller que digan security o passport, serán materia del próximo post.

Quedan algunos temas sin tocar en este capítulo, falta que revisemos la integración con AngularJS, el despliegue de los templates con EJS y la integración con passport para autenticar y autorizar los request.

Si tienen preguntas, bienvenidas sean.