Archivo de 'desarrollo'

WebApps Working Group

Últimamente leo bastante la página del w3c (Qué acierto fue cambiar su diseño), y casi siempre me veo a mí mismo leyendo sobre el Grupo de Trabajo de Aplicaciones Web (WebApps Working Group). ¿Qué es?

El W3C Web Applications (WebApps) Working Group, una fusión de los grupos de trabajoWebAPI y WAF, se constituye para desarollar APIs estándar para el desarrollo de Aplicaciones Web del lado del cliente. Este trabajo incluirá tanto la documentación de APIs existentes como el XMLHttpRequest, como el desarrollo de nuevas APIs que enriquezcan las aplicaciones web.

Veamos en qué consisten algunas de esas APIs que están desarrollando:

Interfaz para Widgets

Cada widget podrá tener un documento de configuración que almacenará metadatos relativos al Widget. Además, cada instancia de un widget podrá almacenar datos de manera persistente.  ¿Cómo se hará esto? Gracias a otra API de almacenamiento de datos locales.

Está bastante maduro (En estado de Recomendación Candidata), y existe una suite de tests para probar su correcta implementación.

API de selectores Level 1

Supongamos el siguiente bloque de código HTML 4.01:

<table id="score">
  <thead>
    <tr>
      <th>Test
      <th>Result
  <tfoot>
    <tr>
      <th>Average
      <td>82%
  <tbody>
    <tr>
      <td>A
      <td>87%
    <tr>
      <td>B
      <td>78%
    <tr>
      <td>C
      <td>81%
</table>

Si quisiéramos obtener los valores de todas las celdas tendríamos que ejecutar algo similar a esto con la API de DOM Level 2:

var table = document.getElementById("score");
var groups = table.tBodies;
var rows = null;
var cells = [];

for (var i = 0; i < groups.length; i++) {
  rows = groups[i].rows;
  for (var j = 0; j < rows.length; j++) {
    cells.push(rows[j].cells[1]);
  }
}

¡Qué feo! La nueva API permite hacerlo de este modo mucho más conciso:

var cells = document.querySelectorAll("#score>tbody>tr>td:nth-of-type(2)");

Como véis, es exactamente igual que lo que ya hacemos con los selectores de jQuery, salvo que en un tiempo podremos realizarlo directamente desde el motor de JavaScript del navegador, sin necesidad de frameworks.

Esta API también está muy madura, y al igual que la anterior es una Recomendación Candidata. Está disponible en Firefox desde su versión 3.1+, en Internet Explorer 8 y en Safari 3.1+. Pero hasta que no borremos del mapa a IE6 e IE7 tendremos que seguir utilizando herramientas como jQuery.

Web Storage

Es un nuevo mecanismo de almacenamiento local que, a diferencia de las Cookies, permite almacenar un gran volumen de datos (Por ejemplo, los emails de una cuenta, haciendo innecesario plugins como Google Gears), y también permite almacenarlo accesible a todas las ventanas del dominio al que pertenecen.

Todo se realizaría de un modo muy sencillo: Simplemente accediendo al atributo que proceda dentro del objeto localStorage.

De nuevo, está disponible ya en Firefox 3.5, IE8, Safari 4.0, Chromium…

Web Workers

Permite lanzar distintos hilos de ejecución que se ejecutan en paralelo a la página principal. De este modo, se puede trabjar en un entorno thread-like trabajando con un mecanismo de coordinación de pase de mensajes.

Como ejemplos, podríamos:

  • Generar una hebra que busque números primos en background.
  • Un worker que actualice una base de datos local. Estaría permanentemente escuchando al servidor mediante un WebSocket, y cuando hubiera algún cambio, modificaría la base de datos local.
  • Operaciones de Lectura/Escritura de fondo.
  • Workers compartido. Distintas ventanas podría compartir un único Worker que, en un momento dado, podría actualizar a todas a la vez.
  • Delegación. Aprovechando las distintas CPUs de los microprocesadores multi-core.

Lógicamente, esto abre un gran número de posibilidades en cuanto al rendimiento de las páginas web.

Por el momento disponible en Firefox 3.5+, Safari 4, Chromium.

Server-Sent Events

La API que define esta especificación puede no parecer muy revolucionaria: Permite recivir notificaciones PUSH desde el servidor en forma de evento DOM. Perfectamente podemos lograr el mismo objetivo mediante XHR o un iframe. Sin embargo, dada su naturaleza, permitiria que, cuando el navegador se pueda coordinar con el operador de red, se ahorraran notablemente recursos de red. Uno de los efectos colaterales sería aumentar la duración de las baterías de los dispositivos portátiles.

WebSockets API

Esta API permite una auténtica conexión bidireccional entre el navegador y el servidor. Ya fue cubierta en este blog cuando Google Chrome anunció su implementación.

Web SQL Database

Es exactamente lo que su nombre sugiere. Consiste en una especificación de un API que permitirá almacenar información en una base de datos locale accesible mediante SQL.

Veamos un ejemplo de su funcionamiento:

function prepareDatabase(ready, error) {
  return openDatabase('documents', '1.0', 'Offline document storage', 5*1024*1024, function (db) {
    db.changeVersion('', '1.0', function (t) {
      t.executeSql('CREATE TABLE docids (id, name)');
    }, error);
  });
}

function showDocCount(db, span) {
  db.readTransaction(function (t) {
    t.executeSql('SELECT COUNT(*) AS c FROM docids', [], function (t, r) {
      span.textContent = r.rows[0].c;
    }, function (t, e) {
      // couldn't read database
      span.textContent = '(unknown: ' + e.message + ')';
    });
  });
}

prepareDatabase(function(db) {
  // got database
  var span = document.getElementById('doc-count');
  showDocCount(db, span);
}, function (e) {
  // error getting database
  alert(e.message);
});

En primer lugar se define la función prepareDatabase() que, en caso de que fuera necesario, crea la base de datos con una tabla llamada “docids” con dos columnas (“id” y “name”). Si hay éxito, o no es necesario crearla, se llama a la función getDatabase(), que obtiene un manejador de la base de datos, y entonces llama a la función que hace realmente el trabajo, en este caso showDocCount().

File API

Como último ejemplo de apartados en los que trabaja el WebApps Working Group, voy a mosotrar la File API. Permitirá un manejo avanzado de ficheros desde JavaScript, pudiendo:

  • Una vez que el usuario conceda permisos, el navegador permitirá leer y parsear un fichero.
  • Se podrá almacenar información de forma local.
  • Se permitirá guardar los archivos, del mismo modo que ahora se pueden descargar ficheros de servidores remotos.
  • Se podrán enviar ficheros grandes a servidores de un modo más eficiente que el actual. Por ejemplo, se podrá dividir en porciones.
  • Los navegadores implementarán mecanismos para poder cancelar o impedir los casos de uso enumerados anteriormente.

Sin duda, APIs como éstas permitirán realizar aplicaciones reales que funcionen en el navegador sin necesidad de un servidor. Como ejemplo, un reproductor multimedia avanzado, que guarde una caché local con metadatos de nuestra música y películas.

Creo que muy pronto comenzaremos a ver todas estas nuevas aplicaciones ir aparenciendo, poco a poco, hasta que un día el navegador realmente sea un framework de aplicaciones más.

Vídeo, audio e imágenes de entrada al navegador

Hace poco se ha publicado un nuevo borrador del w3c (The Capture API) que permitirá conectar dispositivos de entrada al navegador, permitiendo por ejemplo capturar una fotografía, mensaje de audio por el micrófono, o un vídeo.

Aun se encuentra en un estado muy prematuro, pero nos enumeran una serie de posibles casos de uso:

  • Captura y envío de imágenes. Permitiendo el envío por XHR de varias imágenes.
  • Captura de imagen panorámica. Por ejemplo, con 3 tomas que posteriormente se “concatenan” automáticamente para mostrar la panorámica.
  • Video Chat. Aun está sin definir el método para realizar streaming, sin embargo todas las soluciones propuestas pasan por websockets.
  • Cámara web. Permitirá realizar una aplicacion de vigilancia para controlar la cámara, incluyendo movimientos como arriba, abajo, izquierda o derecha, o hasta aplicaciones de detección de movimiento.
  • Búsqueda por voz. Introduciendo por el micrófono la cadena de búsqueda.
  • Recordatorio de voz. De nuevo, desde el micrófono.

Por supuesto, para proteger la privacidad de los usuarios, el navegador tendrá que pedir explícitamente confirmación del usuario para permitir que se acceda a estos dispositivos.

Ejemplo de uso:

// Create a container div element and append it to the document body.
var container = document.createElement("div");
document.body.appendChild(container);

// The browser viewport width in pixels.
var screenWidth = window.innerWidth;

function successCallback(data) {
for (var i in data) {
var img = document.createElement("img");
img.src = data[i].uri;
// If the image width exceeds that of the browser viewport, the image
// is scaled to fit the screen keeping the aspect ratio intact.
if (data[i].format.width > screenWidth) {
img.style.width = screenWidth + "px";
img.style.height = (data[i].format.height/data[i].format.width)*screenWidth + "px";
}
container.appendChild(img);
}
}

function errorCallback(err) {
alert(err.message + " (" + err.code + ")");
}

// Launch the device camera application and invoke the callback once
// the user exits the camera application.
transactionId = navigator.device.captureImage(successCallback, 1, errorCallback);

Mientras tanto, y hasta que esto sea una realidad, se puede utilizar el paquete flash.media de ActionScript3, en concreto las clases Camera y Micrphone. Pero claro, no es lo mismo. Una verdadera lástima tener que esperar tanto tiempo. Veremos cuándo tiene el navegador más utilizado estas funcionalidades.

Google Chrome ahora con Web Sockets

La noticia del día en cuanto a desarrollo web sin duda ha sido la implementación de Web Sockets en Chromium. una tecnología de comunicación bidireccional para aplicaciones web.

Los Web Sockets son un borrador del W3C que, mediante una conexión TCP, permiten realizar fácilmente un Server Push, es decir, una petición iniciada desde el servidor central. Es un cambio notable en la programación web, hasta ahora dirigida por peticiones iniciadas desde el cliente.

Veamos un ejemplo del código del lado del cliente:

if ("WebSocket" in window) {
  var ws = new WebSocket("ws://example.com/service");
  ws.onopen = function() {
    // Se conecta el websocket. Puedes enviar datos con el método send()
    ws.send("mensaje a enviar"); ....
  };
  ws.onmessage = function (evt) { var received_msg = evt.data; ... };
  ws.onclose = function() { // se cierra el websocket. };
} else {
  // el navegador no soportaWebSocket.
}

Ridícultamente sencillo, ¿verdad? :) Como se puede observar en la URI de la petición, funciona mediante un protocolo distinto al HTTP (ws://example.com/service), el web socket protocol. Por tanto el servidor debe estar capacitado para manejar dichas peticiones. Con fines experimentales, Google ha creado pywebsocket, un módulo del servidor web Apache que implementa dicho protocolo (Dejo para otro post el colgar un howto para ver cómo instalarlo y ejecutar un ejemplo funcional).

Las ventajas son evidentes: Supongamos un chat. Un usuario accede y dice “hola”. Empleando tecnología AJAX, deberá enviarse una petición HTTP completa, posiblemente superando 1KB para sólo cuatro caracteres. Multipliquemos esto por miles de conexiones simultáneas con millones de usuarios diarios (Como le ocurre a Facebook): Tendríamos un problema de ancho de banda. Con este nuevo protocolo, las peticiones son mínimas :)

Uno de los apartados más criticados ha sido la necesidad de relegar el socket a una conexión TCP, impidiendo aprovechar otros protocolos como UDP o RUDP. Además, y pese a ir sobre TCP, funciona sobre otro protocolo a nivel de aplicación, por lo que no sería posible acceder desde el navegador a, por ejemplo, un servidor IRC (Salvo que se haga através de otro servidor que haga de proxy).

Comet

No se puede hablar de WebSockets sin mencionar otra tecnología. En el año 2006 Alex Russell definió y acuñó lo que hoy conocemos como Comet: Un patrón que define un método para implementar Server Push desde cualquier navegador. Si bien no fue el que lo creó, pues algunos sitios como el chat de Google en Gmail ya utilizaban técnicas similares.

Los principales métodos para lograr Comet en el navegador son éstos:

  • Streaming – Consiste en mantener una una única conexión persistente desde el navegador al servidor. Cada vez que el servidor envía un nuevo evento, el navegador lo interpreta. Hay dos técnicas:
    1. IFrame oculto – Se utiliza un IFrame oculto en el que el servidor va escribiendo, cada vez que lo desea, porciones de código javascript. Es efectivo gracias a que los navegadores ejecutan los documentos HTML de forma secuencial. Sin embargo trae problemas en el motor de renderizado KHTML, pues no se comparte javascript entre distintos documentos.
    2. XMLHTTPRequest – En 1995, Netscape Navigator añadió una funcionalidad llamada “server push” que permite peticiones XHR “multipart” mediante el tipo mime multipart/x-mixed-replace. De ese modo se puede utilizar una petición XHR como canal de streaming. Sin embargo sólo es soportado por el motor Gecko, no así por otros grandes players como Trident o Webkit.
  • Long polling en AJAX – Las soluciones anteriores causan efectos negativos en los navegadores modernos. Por eso, muchas aplicaciones optan por una estrategia de long polling, funcional en todos los navegadores que soportan XHR.Esta técnica se basa en el uso de AJAX, realizando una petición que no es cerrada hasta que el servidor contesta. Una vez se recibe respuesta, comienza de nuevo el sondeo.
    • XMLHttpRequest long polling – Funciona como la mayoría de aplicaciones AJAX: Se lanza una petición al servidor, y no se cierra la conexión hasta que se recibe la respuesta. Una vez recibida, automáticamente se lanza otra nueva petición.
    • Script tag long polling – Si bien los métodos anteriores funcionan entre subdominios, no lo hacen entre distintos dominios de segundo nivel debido a protecciones anti XSS de los navegadores. Gracias a que la etiqueta script, a diferencia de un IFrame o de una petición XHR, puede apuntar a distintos dominios de segundo nivel, se logra solucionar este problema.

Especial mención respecto a Comet merece el protocolo Bayeux, y la implementación CometD de Dojo Foundation. Utilizando el paradigma Comet, han diseñado todo un protocolo de red que, a diferencia de “web socket protocol”, funciona generalmente sobre HTTP, permitiendo ser ejecutado en cualquier navegador moderno. Como API del lador del cliente se puede utiliar indistintamente su framework javascript Dojo, o JQuery. Eso sí, el lado del servidor debe saber interpretar también el protocolo Bayeux, por tanto es necesario instalar unas determinadas bibliotecas, actualmente disponibles para servidores Java.

Otras implementaciones de Sockets

Por supuesto aquí no acaba la cosa. Algunos plugins permiten ejecutar sockets, como por ejemplo el objeto Socket de Adobe Flash que permite enviar flujos binarios. Por supuesto Silverlight y Java mediante applets también permiten realizarlo.

El uso de Flash como proxy para conexiones bidireccionales, por ejemplo, puede resultar muy atractivo, pues está presente en prácticamente todos los navegadores. Sin embargo, y en mi opinión, siempre es mejor emplear tecnologías estándar, como los Web Sockets del W3C, en lugar de soluciones propietarias.

¿Y ahora qué?

Las comunicaciones bidireccionales reales están más cerca. ¿Qué cambia esto? Para los desarrolladores significa un método más versátil y aun más sencillo que XHR para nuestras páginas web. Por supuesto también es un ahorro en ancho de banda (Aunque bendito el programador web que emprenda y deba enfrentarse a problemas de ancho de banda).

¿Y para los usuarios? Junto con otras tecnologias, los Web Sockets abren muchas puertas de cara al futuro. Por ejemplo, con O3D o WebGL, sockets y <audio> se podrán desarrollar videojuegos en HTML si necesidad de Flash. Aun nos falta, por ejemplo, soporte para el micrófono, la webcam, o datagramas binarios, pero tiempo al tiemo :) ¡Estén atentos!

Facturas en CSS

Vía css-tricks veo un sencillo método para crear facturas sólo con CSS. ¿Y por qué usar este método en lugar de un software específico? Bueno, gracias a esto sólo necesitas el navegador para poder crear tus facturas. Y qué demonios, es muy ilustrativo el ejemplo. ¡Qué de cosas se pueden hacer con textarea! Además, es fácil de imprimir, y pasarlo a PDF es algo trivial.

Ver demo

Botones súper increíbles con CSS3 y RGBA

CSS3 ya está aquí, y ha llegado para quedarse. Gracias a él, podemos crear increíbles efectos en navegadores modernos (Teniendo en cuenta un enfoque de graceful degradation). En éste artículo voy a mostrar cómo, desde ZURB, han creado unos botones CSS que realmente son súper increíbles. Accede a la página del artículo para ver demostraciones en vivo.

Botón en ancla »

Botón en ancla 2 »

La magia está en el CSS:

.button{
   background:#222 url(/wp-content/uploads/2009/12/alert-overlay.png) repeat-x 0 0;
   display:inline-block;
   padding:5px 15px 6px;
   color:#fff !important;
   font-size:13px;
   font-weight:bold;
   line-height:1;
   text-decoration:none;
   -moz-border-radius:5px;
   -webkit-border-radius:5px;
   -moz-box-shadow:0 1px 3px rgba(0,0,0,0.25);
   -webkit-box-shadow:0 1px 3px rgba(0,0,0,0.25);
   text-shadow:0 -1px 1px rgba(0,0,0,0.25);
   border-bottom:1px solid rgba(0,0,0,0.25);
   position:relative;
   cursor:pointer;
   overflow:visible;
   width:auto
}

button::-moz-focus-inner{
   border:0;
   padding:0
}

.button:hover{
   background-color: #111111;
   color: white
}

.button:active{
   top:1px
}

Una sombra a la caja, otra al texto, un borde redondeado, y de fondo una imagen png que realiza el degradado (Se puede realizar también con CSS en Webkit). Una pasada hacer todo esto sólo con CSS, ¿no?

¡Pero espera! ¡Ahí no queda la cosa! ¿Qué ocurriría si cambiásemos el color de fondo sobre el que está el botón? La sombra se vería “rara”, al igual que el color del borde.

super-awesome-buttons-fixed

Y lo mismo ocurriría con la sombra del texto si cambiásemos el color de relleno del propio botón. ¿Cómo se soluciona? Ahora es cuando llega al rescate la A de RGBA :) Por ejemplo, en la sombra de la caja, lo hemos definido como:

rgba(0,0,0,0.25)

Es decir, color negro al 25% de transparencia. De ese modo, la sombra siempre “lucirá” del mismo modo usemos el color que usemos.

Espero que os haya gustado tanto como a mí.

Vía Smashin Magazine,

El test de Joel adaptado al desarrollo web

Leyendo blogs, me encuentro con este artículo que trata sobre una revisión del sencillo test de Joel Spolsky sobre la calidad del software. Esta nueva revisión, de la mano de Brandon Savage, propone 12 pasos adaptados al desarrollo web hoy día. Los pasos se responden con un sí o un no. Estos son los posibles resultados:

  • 12 síes. Perfecto.
  • 11 síes. Aceptable.
  • 10 o menos síes. Tienes un serio problema.

Ahora veamos las preguntas:

  1. ¿Usas algún sistema de control de versiones?
  2. ¿Puedes generar fichero para distribuir tu software en sólo un paso?
  3. ¿Usas integración continua?
  4. ¿Guardas un registro de bugs?
  5. ¿Corriges los bugs tras escribir nuevo código?
  6. ¿Cumples los hitos a tiempo?
  7. ¿Documentas las especificaciones?
  8. ¿Disfrutan tus programadores de un entorno de trabajo tranquilo?
  9. ¿Usas las mejores herramientas, y gastas dinero en aquéllas que son necesarias y caras?
  10. ¿Escribes test unitarios?
  11. ¿Tus nuevos candidatos demuestran sus conocimientos de programación con alguna prueba tangible durante la entrevista?
  12. ¿Tienes testers?

En mayor o menor medida, todas me parecen propuestas muy acertadas. No deja de ser una curiosidad más, pero posiblemente este “juego” sea una métrica de calidad de software equiparable a otros sistmas varios órdenes de magnitud más complejos.

Por cierto, yo obtengo un 6 sobre 11 (La pregunta número 11 no se aplica en mi caso).