Etiqueta: web

Organizar los ficheros de routes en nodejs – expressjs

Una de las tecnologías que estamos probando en Cartolab para aplicaciones web es nodejs con express como framework. Hay un montón de tutoriales de como empezar a usarlos, pero a poco que escribas empiezas a preguntarte como organizar el código, y ahí empiezan los problemas. express es un framework no opinativo, es decir proporciona un montón de utilidades pero da liberar total al usuario sobre como mezclarlas, así que se van desarrollando distintos modos de hacerlo.

La primera pregunta en mi casa sobre organizar el código fue acerca de los ficheros bajo el directorio routes. Podemos entender las routes de express como el equivalente al controlador en ese patrón llamado MVC que cada framework implementa como quiere, o viéndolo de otro modo como el mapeo entre una url y una función.

Vamos a ver cuatro estrategias distintas, cada una con sus ventajas e incovenientes.

Todo en app.js

La versión que se suele emplear en los tutoriales de iniciación. Escribimos en un único fichero todo el código de la aplicación.

  • Poco código boilerplate
  • Añadir una nueva url implica tocar un sólo fichero
  • Nada reusable
  • Sólo válido para proyectos pequeños

Es tan sencillo como escribir el mapeo antes de crear el servidor y usar funciones anónimas para la lógica


app.get('/', function(){res.send('root page'});

Mapear en app y la lógica en ficheros distintos

Este es el segundo ejemplo más habitual. Las url se definen en el fichero principal y las funcionalidades se agrupan en distintos ficheros bajo el directorio routes.

  • Añadir una nueva url implica tocar como mínimo dos ficheros
  • Favorece la reutilización, pero siempre debemos colocar las url a mano
  • Implica escribir más código que en el anterior y perder legibilidad

A pesar de que es muy habitual ver esto no me gusta porque no ganamos demasiado, y tener que hacer cambios en dos ficheros acaba introduciendo errores.


// app.js
var routes = require('./routes');  // Coje el fichero ./routes/index.js por defecto
var user = require('./routes/user');

app.get('/', routes.index);
app.get('/users', user.list);


// routes/user.js
exports.list = function(req, res){
res.send("respond with a resource");
};


// routes/index.js
exports.index = function(req, res){
res.send("root page");
};

Hacer el objeto app global y derivar todo hacia los ficheros de routes

Evitamos declarar app como variable local, para poder usarla en el resto de ficheros sin tener que preocuparnos de pasar parámetros. El código queda muy limpio pero se dificulta el testing y se pueden introducir bugs difíciles de detectar.

A mi me gusta esta aproximación cuando tenemos poco código y queremos hacer algo rápido, pero hay que ser consciente de los problemas que tiene.

  • No es una muy buena práctica hacer app global, en el siguiente punto vemos una mejora. Pero al hacerlo así obtenemos código más legible
  • Es bastante modular (excepto por hacer app global)
  • Es bastante legible
  • Hay separación de conceptos, cada fichero se encarga de unas determinadas url y funcionalidades

Referencias

Veamos como quedaría la implementación


// app.js
app = express(); //IMPORTANT! define the global app variable prior to requiring routes!
require('./routes');


// routes/index.js
require('./main');
require('./users');


// routes/main.js
app.get('/', function(req, res) {
res.send("root page");
});


// routes/users.js. list() could be an anonymous function, this is only for showing it in another way.

function list(req, res) {
res.send("user list");
};

app.get("/users", list);

Inyectar app en los ficheros de routes

Es similar al ejemplo anterior, pero el objeto principal es inyectado en los controladores en lugar de usarlo como una variable global. Sacrificamos un poco de legibilidad (hay que meter bastante código «inútil») pero a cambio ganamos en modularidad y testabilidad.

Veamos una posible implementación, teniendo en cuenta que este código no lo he visto en ningún sitio, lo he escrito a partir del artículo de dailyjs y podría tener algún otro problema.

A mi esta es la aproximación que más me gusta, cuando el código aumenta y no nos queremos ir a soluciones más complicadas.


// app.js
var app = express();
// ...
app.use(express.json());
require('./routes')(app); // Must be called after app.use(express.json()) and urlencoded;


// routes/index.js
module.exports = function(app) {
require('./main')(app);
require('./users')(app);
};


// routes/main.js
module.exports = function(app) {
function index(req, res) {
res.send("root page");
};
app.get('/', index);
};

Otras estrategias

Hay estrategias más complejas, que por ahora no me ha hecho falta probar.

Montar un firefox independiente para desarrollo web

Firefox_ScreenshotEn Cartolab llevamos ya una temporada investigando en uso de tecnologías web en el ámbito de la ingeniería cvil.

Una de las cosas que me incomodaron durante los primeros experimentos, era no tener un entorno de desarrollo específico. Al margen del IDE, en desarrollo web son fundamentales las herramientas que proporciona el navegador que usas para el testeo. En este caso, me molesta el mezclar plugins de desarrollo, con plugins normales que uso para la navegación. Tengo la sensación que se me descontrola el entorno de trabajo.

La solución es configurar un navegador específico para desarrollo. Lo cual, al menos en el caso de firefox, es más sencillo de lo que parece:

  1. Le echamos un ojo a las instrucciones de mozilla de como instalar firefox a mano. En resumen: descargar y descomprimir. Yo lo descargue en /usr/local/development
  2. Si ahora simplemente ejecutamos el fichero binario firefox veremos que no hemos ganado nada, aún tendremos nuestros marcadores, plugins, etc… Esto es porque firefox, guarda esta información en perfiles y usa por defecto el perfil indicado en el fichero $HOME/.mozilla/firefox/profiles.ini
  3. Debemos por tanto crear un nuevo perfil, pero antes haremos una copia de profiles.ini
  4. Creamos el perfil como recomiendan desde mozilla, ejecutando firefox -P. Yo cree el perfil dentro de la propia carpeta del firefox descargado a mano, para poder tener un sistema autocontenido.
  5. El paso anterior habrá modificado el fichero profiles.ini, añadiendo el nuevo. Pero lo que nosotros queremos es tener el modo desarrollo lo más aislado posible así que restauramos la copia que hicimos anteriormente
  6. Creamos un miniscript en nuestro PATH o donde queramos que ejecute nuestro firefox de desarrollo y le pase el parámetro -profile y el path al perfil de desarrollo que creamos. Yo cree un script ffdev en /usr/local/bin con el siguiente contenido

    #!/bin/sh
    cd /usr/local/development/firefox
    ./firefox -profile development-profile

Los menos puristas habrán observado, que en realidad, no es necesario complicarse tanto la vida bajando un firefox aparte. Llegaría con:

Crear un perfil nuevo en la carpeta por defecto, marcar el antiguo perfil como el que hay que usar por defecto y crear un script que arranque el nuevo perfil firefox -P "Nombre del Nuevo Perfil"

Si hemos optado por la primera altenativa y finalmente decidimos pasar a la segunda, un sólo firefox en el sistema que se actualice al ritmo que marca nuestra distribución, el cambio es tan sencillo, como copiar la carpeta de perfil de desarrollo a una nueva ubicación (el
directorio por defecto de perfiles sería lo lógico) y modificar el script para indicarle la nueva ruta del perfil y que firefox tiene que
usar. Si quisieramos poder abrirlo desde el Gestor de Perfiles o con la opción -P en lugar de -profile deberemos añadirlo a profiles.ini

¿Creéis que es útil configurar un perfil para desarrollo o no hace falta? ¿Cual de los dos métodos preferís?

Qué es Twitter Bootstrap y cómo aprender a usarlo

Generar una plantilla básica sobre la que empezar un proyecto web que tenga en cuenta los distintos navegadores y tamaños de dispositivos consume mucho más tiempo del que debería. Para minimizar este problema durante los últimos dos o tres años han surgido varios frameworks de diseño web. Si te dedicas a esto y no has estado debajo de una piedra este tiempo, sin duda habrás oído hablar de twitter-bootstrap, que es el que se ha hecho más popular.

¿Qué es bootstrap?

Bootstrap o twitter-bootstrap es un framework creado originalmente por dos desarrolladores/diseñadores de twitter para acelerar el diseño de nuevas aplicaciones web.

El framework proporciona clases css y código javascript para definir el layout de la página, crear componentes que respondan a eventos y estilizar los elementos html más habituales. Estos ejemplos están hechos con la versión 2, pero valen para hacerse una idea.

Podemos decir que los principios en los que se basa la última versión (la 3) son:

  • Responsive Design: Que según mi definición particular consiste en que la página trata de «hacer lo correcto» al ser visualizada independientemente del dispositivo y tamaño de la pantalla. El término fue acuñado por Ethan Marcotte en 2010.
  • Mobile first: Al contrario que en la versión 2, en la 3, el diseño responsivo es la opción por defecto al trabajar con bootstrap
  • Cross Browser: Trata de ser compatible con la mayoría de navegadores.
  • Integración con jQuery: Está muy integrado con jquery para el que define nuevos plugins
  • Buenas prácticas: Trata de emplear algunas de las prácticas más extendidas en cuanto a usabilidad, uso de css3/html5, organización del código, …

¿Qué me aporta bootstrap?

Si eres desarrollador con poca experiencia en diseño te proporciona una forma muy rápida de crear un layout responsivo básico de la página en la que empezar a meter tu código.

Si eres diseñador, obtienes una enorme cantidad de clases CSS que personalizar a tu gusto, sin tener que partir de cero.

Si quieres aprender a hacer las cosas mejor, es un compendio de buenas prácticas.

Aprendiendo a usar bootstrap

La documentación de la página de bootstrap debería ser tu principal fuente de información, sobre todo porque el resto de documentación tiende a quedar más desactualizada, aún así, hay una serie de tutoriales que a mi me han resultado más útiles para empezar, sobre todo porque te permiten coger ideas más generales de lo que permite hacer.

Los enlazo en el orden que creo que merece la pena seguirlos:

  1. Tutorial de w3resource: Hay partes del tutorial que están con la versión 2, pero cubre muchos aspectos
  2. Understanding twitter bootstrap 3. También se le escapa alguna etiqueta de la v2 como el container-fluid, pero en general te permite aprender a diseñar un ejemplo básico.
  3. Una introducción a los componentes que proporciona bootstrap como el scrollspy o las ventanas modales
  4. Actualizado 31/Agosto/2015. En Udemy acaban de publicar un post con una muy buena introducción a boostrap.
  5. Bootstrap 3 Tutorial – An Introductory Course | Udemy. Una serie de videotutoriales muy chulos donde emplean unas cuantas clases que no he visto en otros sitios. Es de pago pero barato. Con los recursos anteriores seguramente ya no te será necesario este curso, así que mira alguno de los vídeos de muestra antes de comprarlo

Otros recursos

Desde que nació bootstrap han ido apareciendo un montón de recursos que sacan partido a este framework

Conclusiones

En un par de días puedes revisar los enlaces que se proporcionan en este artículo, y refactorizar alguna web sencilla que tengas para que use bootstrap. Será un tiempo bien empleado que recuperarás con creces.

No he probado otros frameworks del estilo, pero supongo que serán parecidos, cada uno con sus fortalezas y debilidades. Si le tienes manía a bootstrap, escoge otro, pero desde luego es una herramienta a meter en tu caja si eres desarrollador web.

Borrar automáticamente comentarios pendientes en WordPress

Esta mañana me he puesto a actualizar odiseus y he visto que la base de datos ocupaba cerca de giga y medio, siendo la mayoría consumido por los 300.000 comentarios de spam que se nos escaparon en un blog que hace tiempo que no tiene supervisión y no tenía Akismet instalado.

Por algún extraño motivo WordPress todavía no tiene un forma por defecto que permite marcar y eliminar todos los comentarios pendientes, tienes que hacerlo de 20 en 20. Las soluciones que vi no me convencían demasiado. Plugins anticuados, borrar cosas directamente en la base de datos sin saber las relaciones que puede haber en un multisite o entre tablas, … Y Akismet tampoco era capaz de lidiar con tantos comentarios.

Finalmente me decidí por el plugin WP-Optimize capaz de borrar los comentarios pendientes y hacer alguna otra cosilla mas

Por desgracia más de 50.000 comentarios ya estaban aprobados y no quería borrarlos todos sin más. La solución:

  1. Buscar la fecha del último post
  2. Marcar como no aprobados todos los comentarios hechos con posterioridad a un mes desde el último post

UPDATE `wp_4_comments` SET `comment_approved` = 0 WHERE `comment_date` > '20110601';

A continuación podemos borrar los comentarios no aprobados con wp-optimize.

Tutorial básico de django south

South es una app de django que permite modificar la estructura de la base de datos de una aplicación django cuando cambiamos el modelo (models.py).

El comando syncdb sólo crea nuevas tablas, pero no modifica tablas existentes, así que si en el modelo de una aplicación renombramos un campo de una tabla existente syncdb no realizará ese cambio en la base de datos. A este tipo de cambios en la base de datos se les denomina «migración del esquema» y es de lo que se encarga South.

Instalación

  1. pip install south
  2. Agregar «south» a INSTALLED_APPS
  3. Ejecutar syncdb antes de crear nuestros propios modelos. Está será la última (y única) vez, que necesitamos ejecutar este comando
    manage.py syncdb

Usar south en un una app nueva

  1.  Crear la aplicación, y empezar a rellenar el models.py
  2. Crear el script de migración inicial
    python manage.py schemamigration app_name --initial
  3. Hacer los cambios en la bbdd
    python manage.py migrate app_name

Usar south en una app ya creada

python manage.py convert_to_south app_name

En el caso de que haya otros desarrolladores en el equipo y cada cual esté usando su propia instancia de la base de datos, el resto de desarrolladores deberá migrar la primera versión en modo fake,
python manage.py migrate app_name 0001 --fake

el resto normal, así:
python manage.py migrate app_name

De lo contrario no podrán migrar su versión de la base de datos.

Migración de modelos

  1. Modificamos el models.py de nuestra aplicación
  2. Crear un nuevo script de migración
    python manage.py schemamigration app_name --auto
  3. Aplicar la migración a la bbdd
    python manage.py migrate app_name

Como funciona

Se puede decir que South funciona en varios niveles de abstracción disintos.

  • Añade una tabla en la base de datos que mantiene el estado actual de la base de datos. Es decir, guarda que migraciones se han aplicado.
  • Crea un directorio en la applicación, donde guarda para cada migración un fichero (script) con la información necesaria para realizarla
  • Añade varios comandos al manage.py

Los ficheros de migración generados en deben subirse al repositorio para que el resto de los desarrolladores pueda también realizar la migración.

Referencias

Nota: Editado el 7/Marzo/2015 para añadir el comentario de Mauricio.

SigLibre2011: Taller Linked Data

Hace poco CartoLab me dió la oportunidad de asistir a las V Jornadas de SIG Libre de Girona. El primer día, y a pesar de los temores de Gonzalo, llegamos a la sede de los talleres sin perdernos, aunque es de recibo decir que caimos de nuevo en el error del año pasado de intentar aparcar en el campus de la Facultat de Letres, lo que roza lo imposible, por lo que al final aparcamos en la ciudad y subimos andando (en realidad son apenas 10 minutitos de caminata).

El taller al que fuí por la mañana iba sobre Linked Data. Para mi gusto el taller acabo siendo más bien una clase teórica, por lo que por ahora para mi se queda en el cajón de “una esas tecnologías que habría que probar un día”.

LinkedData viene siendo un avance de cara a la web semántica, que se podría explicar diciendo algo así como que el objetivo es las webs no tengan datos si no información. Y esta información pueda estar enlazada y ser enlazable, no sólo en un formato entendible por los humanos, si no en un formato apto para que las máquinas puedan relacionarse entre sí. Ese lenguaje común que las máquinas podrían interpretar y en que se asienta el linked data es el RDF. La página de preguntas frecuentes de la web de Linked Data lo deja más claro de como lo puedo hacer yo.

Un ejemplo de las posibilidades sería por ejemplo que el IGN publicara un nomenclator en RDF. Cada uno de estos ficheritos RDF podría incluir el nombre del lugar y sus coordenadas geográficas. El INE en lugar de permitir bajarte csv podría publicar ficheros en RDF donde las estadísticas estuvieran enlazadas a los RDF que publica el nomeclator, lo que aportaría componente geográfica a los datos del INE sin que el INE se tuviera que preocupar de esta componente, sólo tendrían que enlazar una fuente fiable. Un tercero podría tomar ambos datos y proporcionar un servicio con ellos, por ejemplo rastrear las ofertas de trabajo de infojobs mezcladas con los datos del paro del INE y mostrar en un mapa que tipos de trabajo se ofrecen en los sitios donde hay más paro.

Me quedo con una de las frases del ponente que decía más o menos así:

Lo bueno o lo malo de LinkedData es que el producir la información es muy costoso pero el consumirla es relativamente sencillo.

La verdad es que es una tecnología con muy buena pinta, por ejemplo ya existen herramientas que permiten servir la información de una base de datos relacional en formato RDF, e interrogar a la BD mediante SPARQL.

Para saber más:

  • Linked Data.
  • CKAN. The data hub. Ejemplos de gente usando Linked Data, a los que podríamos enlazar nuestra propia información.
  • http://geosparql.appspot.com/