Creando módulos en Node.js

Lo del servidor web con pocas líneas o refactorizado para que tenga forma de clase va quedando más o menos apañado. Pero en cualquier proyecto que vaya creciendo vamos a necesitar bastantes más cosas y claro, ir metiendo todo el programa en un único fichero, aunque algún programador bajeril pueda decir que es más simple, pues está muy feo. Como en cualquier otro lenguaje y sea el tipo de programación que sea, como mínimo para facilitar la gestión del proyecto conviene separar. Una clase un fichero. Y en el caso de Node.js se les suele llamar módulos.

Módulos propios en Node.js

En los programas habrás observado que se suele empezar importando módulos: http, connect,... etc. Si queremos separar nuestro código por módulos y ponerlo en distintos ficheros y luego poder importarlos, debemos hacerlo de una forma especial. Cada método que queramos que sea usado desde fuera deberá ser exportado.

Como ejemplo vamos a ver un módulo de logging que he creado haciendo uso del módulo para colorear los mensajes de consola. Este módulo de logging tiene distintos métodos según el tipo de error y el color del mensaje varía según el tipo. Hay unos colores y configuraciones por defecto que el usuario del módulo podrá cambiar:

/**
* coloredlog
* @author Pello Xabier Altadill Izura
* @greetz any as always
*/
var color = require('colors');

var name = '';       // Name to add
var prefix = false;  // Whether to add [INFO],[WARN],[ERROR]
var showDate = false;

/**
* we init colors to set a kind of 'theme'.
*
*/
color.setTheme({
		 msg_color: 'green',
		 warning_color: 'yellow',
		 error_color: 'red',
		 request_color: 'blue'
});

/**
* set prefixes for logging
*/
exports.setOpt = function (optName, optPrefix,optShowDate ) {
	name = optName;
	prefix = optPrefix;
	date = optShowDate;
};

/**
* allows user to set other colors
*/
exports.setColors = function (infoColor, warningColor, errorColor, requestColor) {
	// We check params... and assign defaults if no value was given
	infoColor = (infoColor!='')?infoColor:'green';
	warningColor = (warningColor!='')?warningColor:'yellow';
	errorColor = (errorColor!='')?errorColor:'red';
	requestColor = (requestColor!='')?requestColor:'blue';
	
	color.setTheme({
		 msg_color: infoColor,
		 warning_color: warningColor,
		 error_color: errorColor,
		 request_color: requestColor
	});
};

/**
* log without colors
*/
exports.log= function (msg) {
	finalPrefix = genPrefix('');
	console.log(finalPrefix+msg);
};

/**
* normal log, green color
*/
exports.loginfo = function (msg) {
	finalPrefix = genPrefix('INFO');
	console.log((finalPrefix+msg).msg_color);	
};

/**
* warning log
*/
exports.logwarn = function (msg) {
	finalPrefix = genPrefix('WARN');
	console.log((finalPrefix+msg).warning_color);
};

/**
* error log
*/
exports.logerr = function (msg) {
	finalPrefix = genPrefix('ERROR');
	console.log((finalPrefix+msg).error_color);
};

/**
* conditional prefix generation, If any name is given and if type
* prefix is required. Double ternary!!! - aj! mis hogos!!-
*/
function genPrefix (type) {
		return (name!='')?name+' '+((prefix)?'['+type+']':'')+'> ':'';
}

¿Cómo exportamos y usamos esto?

Si hemos metido el fichero de modulos dentro de una carpeta llamada lib, basta con hacer un require de ese fichero y asignarlo a una variable. A partir de ahí con esa variable ya podemos acceder a todos los métodos exportados.

// We add some color to our logs...
var logger = require('./lib/coloredlog.js'); // we can omit .js
logger.setOpt('MusicChartSvr',true,false);

...
logger.logwarn(' 404 Resource not found: ' + req.url);
...
logger.loginfo('Express server listening on port ' + app.get('port'));
...

Y así es como quedaría:

Logger con colorines

Ya decía yo que el pantallazo salía pesadito, no es por los colores, es el caballero oscuro que sale atrás. Por cierto, el twitter de Christian Bale el mejor de la historia. Qué grande eres.

¿Cómo exportar clases?

Si estás habituado a la programación orientada a objetos, eso de andar exportando función por función te debe paracer un horror innominado e innominable de las profundidades abisales más ignotas del oceano insondable. Bueno, nada te impide crear una clase y exportarla, si es que con eso te quedas más tranquilo. Así podrás lucir las gafas de pasta pero en el fondo seguirás siendo un ortodoxo reaccionario e intransigente que frunce el ceño ante cualquier tecnología rompedora.

/**
* example of module but instead of exporting de gijon functions one by one
* we create a class and we just export this with all its properties and methods.
* @author Pello Xabier Altadill Izura
* @greetz for those Keepers of the orthodoxy
*
* To use this from another module:
*  var dummy = require('./lib/dummyclass');
*  myDummy = new dummy.dummyclass(true);
*  console.log(myDummy.toString());
*/

exports.dummyclass = function (a2) {

	var self = this;
	
	this.attrib1 = 'Sense of life';
	this.attrib2 = a2;
	this.attrib3 = 42;

	// Init function
	this.init = function (a1, a2, a3) {
		this.attrib1 = a1;
		this.attrib2 = a2;
		this.attrib3 = 3;
	};

	// toString to see attrib values
	this.toString = function () {
		return this.attrib1+","+this.attrib2+","+this.attrib3;
	};
};
Creando un módulo para Node.js

Si tenemos un módulo decente compuesto de varios ficheros todos ordenaditos dentro de una misma carpeta podemos convertir eso en un módulo para Node.js agregando un fichero llamado package.json que indique los contenidos y el fichero principal del mismo. Una especie de Manifest. Este podría ser el contenido de uno de esos ficheros:

{
  "name": "mysupersever",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node mysuperserver.js"
  },
  "dependencies": {
    "express": "3.3.5",
    "jade": "*"
  }
}

by Pello Altadill 08/18/2013 22:45:09 - 384 hits

AsyncTask en Android

Los AsyncTask están recomendados para tareas concretas y finitas, como por ejemplo descargar el contenido de una URL. Si lo que necesitas es una especie de Hilo que esté ejecutándose contínuamente tendrías que usar los Thread convencionales (no se detienen ni al pulsar home ni al pulsar Back) o directamente crear un Service de Android. Para crear un AsyncTask debes extender la clase AsyncTask indicándole tres tipos de clase en la declaración, como por ejemplo AsyncTask<String, String, V...

by Pello Altadill 08/18/2013 11:06:08 - 797 hits

More »

Perfiles de desarrollo y producción con Maven

Algo muy común y recomendable en cualquier proyecto medianamente serio es contar con un servidor de desarrollo y otro de producción, además del propio equipo del programador donde se hacen las primeras pruebas. Los programas se prueban en local, se prueban en desarrollo y finalmente, cuando se ha verificado que todo está correcto, se puede pasar a producción donde se explotará una BD con datos reales y habrá usuarios reales. Hay lugares en los que incluso existe una servidor de pre-producción....

by Pello Altadill 08/17/2013 22:16:00 - 719 hits

More »

Hilos en Android con Threads java

Toda aplicación de Android tiene al menos un hilo o thread de ejecución. Ese thread es el encargado de la pantalla que tienes ante ti y es imprescindible por la manera en la que Android gestiona los cambios en el interfaz: a través de una cola de mensajes. Es decir, cada vez que aplicamos algún cambio en algún View no se aplica directamente sino que se deja la petición en una cola. Y ese hilo, el UI thread o el hilo principal de la aplicación es quien precisamente se encarga de procesar esa cola...

by Pello Altadill 08/17/2013 10:50:52 - 833 hits

More »

Servidor web de Node.js refactorizado

Sí, seguro que el primer código que has visto de Node.js es uno de esos milagrosos servidores web hechos con pocas líneas. Olvídese de aparatosos sockets, de punteros o de BufferedStreamsWriters, un módulo, unos callbacks, eliges un puerto y a dar servicio. Bueno, uno trata de ser un good Node.js citizen y este código se entiende y mola, pero a la larga, si lo queremos ir mejorando y añadiendo otras funcionalidades cada vez va a ser más complicado mantenerlo. Lo que propongo en ...

by Pello Altadill 08/16/2013 23:18:31 - 393 hits

More »

Hibernate self-join con anotaciones

Vamos a dejar por unos instantes tanto Javascript sin tipos y sin estructura y pongámonos otra vez la corbata para volver al mainstream de aplicaciones empresariales J2EE. Quedaba pendiente ver cómo montar un self-join pero con anotaciones, es decir una clase que se hace referencia a sí misma. En su momento ya puse aquí la versión con el mapeo por XML, vamos a ver cómo quedaría la cosa pero usando las anotaciones en la ...

by Pello Altadill 08/16/2013 17:06:58 - 279 hits

More »

Un vistazo a Backbone

Backbone es un framework MVC de javascript para clientes web que facilita el desarrollo de aplicaciones de una sola página. El hecho de aplicar MVC permite separar los datos de la presentación y Backbone lo hace sin invadir la página y con una serie de funciones que permiten la persistencia de datos en el servidor. Dicho de otro modo, podemos hacer páginas web que man...

by Pello Altadill 08/16/2013 01:37:50 - 393 hits

More »

El ciclo de vida de una Activity en Android

Android tiene una forma peculiar de gestionar las aplicaciones que choca un poco con los sistemas operativos tradicionales. Pese a estar montado en un linux con el kernel 2.6, Android no tiene por costumbre matar las aplicaciones cuando las cerramos. La clave está en que igual lo hace o igual no, según las necesidades o lo que Android considere oportuno. La cosa es que no hay que empeñarse en tener un botón para matar la aplicación, oficialmente no se recomienda y se todo se resume a un tranqui...

by Pello Altadill 08/15/2013 13:55:06 - 868 hits

More »

Callbacks y funciones asíncronas, el estilo Node.js

El estilo nodejs Yo pensaba que sabía -algo- de javascript hasta que descubrí Node.js :P. En fin, espero ser siempre un aprendiz. Conforme te vas asomando a nuevas tecnologías tratas de hacer las cosas correctamente y como recién llegado aplicas lo de donde fueres haz lo que vieres. ¿Existe algún documento con las convenciones de Node.js? Sí, Node.js tiene una guía de estilo aunque no e...

by Pello Altadill 08/14/2013 22:08:41 - 938 hits

More »