Contenido

Aplicaciones Javascript escalables

25 sep

+ 4

Hoy he estado leyendo ojeando una de las presentaciones de Nicholas Zakas, concretamente la de “Scalable Javascript Applications Architecture“. Aunque no es lo primero que leo sobre el tema, me ha gustado la claridad con la que Nicholas lo explica. Voy a intentar dejar constancia de las impresiones sacadas por si a alguien le puede ayudar.

1) Teoría de módulos

La teoría de módulos (como Nicholas la llama) nos dice que una forma de crear una aplicación que sea escalable y fácil de mantener, esta debe estar compuesta por módulos.

¿Que son módulos?

Un módulo (en nuestros términos) es aquella aplicación independiente que forma parte de una estructura mayor. Cada uno de ellos tiene un trabajo y únicamente se encarga de hacerlo.

estacion-espacial-internacional
(Ver Imagen)

(Me ha encantado esta imagen, da una imagen clara del significado de módulo).

Código

Core.register("hola-mundo", function(sandbox){
 // Variables privadas
 var priv = "Privada";

 // Métodos públicos
 return {
   init: function(){
     try{
      sandbox.console("iniciamos el módulo");
     } catch(ex) {
      alert("No se ha encontrado sandbox");
     }
   },
   destroy: function(){
    // destructor
   }
 };
});

Aquí vemos un ejemplo de módulo que registramos con Core.register() que lo veremos más adelante.

Si analizamos el módulo vemos que el primer parámetro informa el nombre del módulo y el segundo especifica la funcionalidad del módulo. Esta funcionalidad recibe como parámetro sandbox (tambien lo veremos más adelante).

Esta funcionalidad nos devolverá un objeto con al menos dos métodos (init() y destroy()) que compondrán las opciones disponibles en el módulo.

init() será tratado como el constructor del módulo y se ejecutará en el momento que se genere el módulo. Por otro lado destroy() será tratado como el destructor del módulo ejecutándose cuando el módulo sea eliminado.

Sandbox

En desarrollo de software se llama Sandbox al entorno aislado de pruebas donde ejecutan los experimientos sobre las aplicaciones. En este caso, prácticamente se basa de lo mismo ya que cada uno de los módulos usará un entorno aislado para los demás módulos.

Código

var Sandbox = function() {
   var private = "Privado";

   return {
     alert: function(str){
       alert(str + private);
     },
     console: function(str) {
       console.log(str);
     }
 }
};

Como vemos el Sandbox, se trata de un elemento que nos ofrece una serie de métodos con los que podremos interactuar con la aplicación. Por ejemplo, podría emplearse para interactuar con el DOM de la aplicación mediante un framework JS (o no), se podría implementar una versión sencilla y controlada de realizar peticiones Ajax o validar formularios,…. Todo ello disponible desde los módulos.

De esta forma los módulos únicamente deben preocuparse de lo que el Sandbox les permite sin preocuparse de lo que hay por debajo de él, facilitando así el desarrollo y la funcionalidad de cada uno de los módulos.

Ejemplo:

// Añadimos método notify() al Sandbox
var Sandbox = function() {
  ...
   notify: function(opt){
     // Comprobaciones previas
     // ....
     $("#notify #title").text(opt.title);
     $("#notify #content").html(opt.content);
   }
  ...
};

// Usamos el método notify() de Sandbox desde el módulo.
Core.register("hola-mundo", function(sandbox){
   // Variables privadas
   ver ver = "1.0";

   return {
    init: function(){
      try{
        sandbox.notify({
          title: "Hola Mundo v." + ver,
          content: 'Esto es una <strong>Prueba</strong>.<br />Para mostrar el uso de módulos'
        });
      } catch(ex) {
        alert("No se ha encontrado sandbox");
      }
    },
    destroy: function(){
     // destructor
     }
   };
});

En el ejemplo vemos que al iniciar el nuestro módulo, llamaremos al método notify() de sandbox sin preocuparnos de lo que hará este método.

El método tras una serie de validaciones prévias, simplemente añadirá un título y un contenido a un elemento #notify usando jQuery.

De esta forma, el Sandbox hace de filtro entre el módulo y el framework controlando lo que este pretende hacer sobre nuestra aplicación.

El Core

En todo lo anterior hemos visto una variable (Core) que parece que es la piedra angular de todo esto.  Se trata de un pequeño script que nos permite registrar módulos y asociar una nueva instancia del SandBox a cada uno de ellos cada vez que se ejecuta.

var Core = function(){
   // Variable privadas
   var modules = {};

   // Cremos la instancia
   function createInstance(moduleID){
    var instance = modules[moduleID].creator(new Sandbox(this)),
    name, method;

    if (!debug) {
      for (name in instance){
        method = instance[name];
        if (typeof method == "function") {
          instance[name] = function(name, method) {
            return function(){
              try { return method.apply(this, arguments);    }
              catch(ex) { log(1, name + "(): " + ex.message);    }
            }
          }(name, method);
        }
      }
    }
  return instance;
 }

 // Método públicos
 return {
   register: function(moduleID, creator) {
     modules[moduleID] = {
       creator: creator,
       instance: null
     };
   },
   start: function(moduleID) {
     modules[moduleID].instance = createInstance(moduleID);
     modules[moduleID].instance.init();
   },
   stop: function(moduleID){
     var data = modules[moduleID];
     if (data.instance) {
       data.instance.destroy();
       data.instance = null;
     }
   },
   startAll: function(){
     for (var moduleID in modules) {
       if (modules.hasOwnProperty(moduleID)) {
         this.start(moduleID);
       }
     }
   },
   stopAll: function() {
     for (var moduleID in modules) {
       if (modules.hasOwnProperty(moduleID)) {
         this.stop(moduleID);
       }
     }
   }
 };
}();

Como vemos se trata de un pequeño script (esto es una base, se puede extender dependiendo de las necesidades del proyecto) que nos permite generar los módulos que queremos por cada aplicación.

Ejemplo

Core.register("...", function(sandbox){});
Core.register("...", function(sandbox){});
Core.register("...", function(sandbox){});
Core.register("...", function(sandbox){});
...

// Iniciamos todos módulos
Core.startAll();

Código completo

Bueno, para verlo todo junto, he creado un fichero .js donde podrás verlo más claramente.

  • Siempre he pensado que debemos llevar el desarrollo al lado del cliente más allá. Debemos dejar de lado el uso mediocre facilista de los frameworks donde ponemos código en un tag script con efectos $.show o $.fadeIn que en muchas ocaciones son innecesarios.

    Creo que en muchas de nuestras aplicaciones siempre utilizamos el mismo código Javascript, con los mismos efectos porque no vemos al lenguaje como algo serio, no implementamos pátrones de diseño y no pensamos en crear un paquete reutilizable y flexible. Esto se debe a que frameworks como jQuery han hecho que cualquiera pueda manipular el DOM de forma muy simple sin ánimar a sus usuarios a aplicar ingeniería haciendolos pensar que tan solo con jQuery se puede hacer un proyecto.

    Luego de esto viene el crecimiento de las aplicaciones y se comienzan a ver sitios lentos, que bloquean navegadores, líneas de código repetidas hasta 10 veces más de lo que se necesita o archivos xHTML inmensos solo por no aplicar una ingeniería front-end.

    Saludos.

  • Muy bueno! Estoy implementando algo similar y sin dudas este método resuelve un par de problemas que estaba teniendo :D

  • Muy buena presentación, estaba buscando algo para poder organizar mas mi js pero hasta ahora nada me convencía del todo.

Comentar

#

Me reservo el derecho de eliminar y/o modificar los comentarios que contengan lenguaje inapropiado, spam u otras conductas no apropiadas en una comunidad civilizada. Si tu comentario no aparece, puede ser que akismet lo haya capturado, cada día lo reviso y lo coloco en su lugar. Siento las molestias.