Notificaciones de Windows en WSL

Con todos los avances que ha tenido el Windows Subsystem fro Linux, una de las funcionalidades que todavía sigue pendiente de implementar es el soporte para notificaciones. Esta característica que podría haberse considerado meramente estética desde la aparición de los background jobs pasó a ser una necesidad.

A menos que nos podamos permitir tener varias terminales abiertas en pantalla para monitorear cualquier proceso ejecutado en segundo plano o de forma automática, es necesario que utilicemos un sistema de información centralizado y Windows ya nos provee sus notificaciones.

El principal problema con esta idea es que no existe ningún punto de contacto entre Windows y el D-Bus.  Dada esta limitación es necesario buscar otro enfoque. La mejor opción hasta ahora viene siendo aprovechar la interoperabilidad1 entre Windows y nuestro sabor de Linux.

Para esto, necesitamos instalar BurnToast, un módulo de PowerShell que nos permite lanzar desde la línea de comandos notificaciones de Windows.

PS > Install-Module -Name BurntToast

Una vez instalado, desde probamos el funcionamiento:

PS > New-BurntToastNotification -Text "Hi There!"

En caso de que nos de error «porque la ejecución de scripts está deshabilitada en este sistema». Es necesario que habilitemos la ejecución, por lo menos, para módulos firmados:

PS > Set-ExecutionPolicy RemoteSigned

Ahora que estamos seguros que todo está listo para emitir notificaciones desde PowerShell, es hora de que hagamos pruebas desde WSL.

WSL > powershell.exe -command "New-BurntToastNotification -Text 'Hi There!'"

Finalmente, ya estamos listos para enviar notificaciones a Windows desde WSL. Además de poder elegir el texto podemos personalizar otros aspectos de las notificaciones, toda la documentación para esto está en la página del módulo.

Recursos útiles para el desarrollo web

Serie de herramientas y bibliotecas online que son útiles durante el proceso de desarrollo web.

Google Analytics

Podemos usar otro pero definitivamente este es el gestor de estadísticas gratuito más completo. Información en tiempo real e histórica sobre los horarios de acceso, distribución geográfica, origen, étc. Y, más interesante al momento de pensar la, datos sobre el tipo de dispositivos usados para conectarse (mobile, tablet o desktop), el navegador o la resolución de pantalla. Por último, si tenés instalado el plugin (ahora sin soporte pero todavía funcional) podés incluso analizar el click heatmap de tu sitio.

Can I Use

Una vez que ya sabemos todo sobre los dispositivos que los usuarios van a usar para conectarse al sitio, es momento de empezar a delimitar las tecnologías que vamos a tener disponibles. En 10 años Can I Use se ha vuelto el standard de facto para obtener este tipo de información. Alcanza con ingresar en el buscador el nombre de la tecnología, un comando o etiqueta relacionado y tendremos información sobre el soporte por versión en los distintos navegadores, el uso relativo de los mismos y notas al pie sobre cosas a tener en cuenta.

MDN Web Docs

Definidas las tecnologías empieza el momento de picar código y comienzan, también las dudas que si un checkbox lanza un evento click o un change, que cual era el comando para agregar un elemento al principio de un Array, étc. Mientras más tecnologías están involucradas en el desarrollo web más difícil es acordarse al dedillo de todo y ahí entra a jugar MDN Web Docs una de las referencias más completas en el tema.

CSS-Tricks

Si bien MDN Web Docs tiene un apartado para CSS, la autoridad en el tema es de CSS-Tricks. Desde snippets a, como su nombre lo indica, trucos y consejos relacionados con el uso de los estilos y una galería de ejemplos de los más interesantes.

CSS Triggers

Una vez que ya empieza a tomar forma el sitio, empezamos a agregar más interactividad al mismo mediante la captura de eventos y manipulación del DOM. Estas modificaciones del modelos de objetos repercuten directamente en el CSSOM y pueden implicar un reflow, un repaint o un relayout cada uno con sus respectivas demoras. Cuando necesitamos saber si es mejor usar transform o modificar directamente el width de un objeto ahí entra CSS Triggers para no equivocarse.

Regular Expressions 101

Hablando de tópicos donde hace falta un ayuda memoria, llegamos a las expresiones regulares. Karma de muchos programadores, Regular Expressions 101 trae tanto una referencia como un entorno de pruebas para poder generar ese pattern perfecto.

Debuggex

Ya ni nos acordamos que matchea ese pattern que tenemos delante o estamos leyendo código de otra persona y vamos medio perdidos nada mejor que Debuggex, un tester visual que nos permite ver de qué va la cosa.

CSS Stats

Recién habíamos terminado de armar todo cuando el cliente nos pidió «unos pocos cambios, algo acá y allá» o llevamos tiempo en producción y hasta el hijo de la vecina, «que sabe un poco de computadoras», metió mano. Por lo que sea terminamos con 402 colores únicos o 12k de reglas y no lo sabemos. Llevar un buen control sobre la situación de nuestros archivos de estilo es una tarea que se ve tremendamente simplicada con CSS Stats.

Pingdom

Siguiendo en la línea de controlar la performance del sitio, entramos en el área de las herramientas más generales como Pingdom que nos provee rápidamente con un resumen de la situación general. Vistoso por demás, también resulta útil para «robar» algunos gráficos para presentar al cliente.

WebPagetest

Lo que Pingdom tiene de bonito, WebPagetest lo tiene de detallado. Nunca lo vamos a usar como imagen en un Power Point pero si necesitamos estadísticas precisas para ver dónde está el cuello de botella en la carga o qué script está consumiendo demasiado tiempo este sitio nos va a permitir encontrar la información que buscamos.

WordPress y PHPUnit

PHPUnit es uno de los frameworks para test unitarios automáticos para PHP más usados y el elegido por los desarrolladores de WordPress junto con QUnit para probar la plataforma. Para facilitar las pruebas, los desarrolladores han creado ya todo un conjunto de test y clases auxiliares que nos resultarán muy útiles en nuestro workflow.

Instalación

Primero, necesitamos instalar PHPUnit en su versión 6 ya que la 7 no es soportada por WordPress. Hay distintas formas documentadas en el sitio del framework y podemos elegir la que más se adapte a nuestro entorno.

Segundo, creamos una nueva base de datos separada para los tests porque que la suite va a borrar todos los datos de las tablas de la instalación donde se ejecute.

Tercero, no es necesario pero definitivamente es la mejor forma de manejar el entorno de pruebas vamos a instalar wp-cli. Nuevamente, hay varías formas de llevar adelante la tarea y va a depender de nuestro entorno el método que elijamos.

Por mi parte, me ha dado mejores resultados la instalación recomendada: descargar el .phar, darle permisos de ejecución y ponerlo en una carpeta que esté en PATH.

Cuarto, nos situamos en la carpeta de la instalación de wordpress para utilizar las opciones del paquete scaffold de wp-cli para generar los archivos necesarios para instalar los tests según sea un plugin o un theme.

wp scaffold plugin-tests <nombre plugin>
wp scaffold theme-tests <nombre theme>

Quinto, ejecutamos el archivo generado dentro de la carpeta del plugin/theme en el paso anterior para instalar el entorno de pruebas. Vamos a necesitar las credenciales y datos de acceso a la base de datos que creamos antes.

bin/install-wp-tests.sh <nombre bbdd> <usuario> <contraseña> <host>

Con esto queda todo listo para que empecemos a desarrollar nuestros tests y ponerlos en la carpeta homónima para que PHPUnit los encuentre.

Para más información sobre los unit test en WordPress estos artículos van a dar una idea de las posibilidades:

Patrón de Inyección de Dependencias

La idea detrás del patrón de inyección de dependencias es lograr una mayor separación de las responsabilidades de nuestro código cambiando la forma en que se manejan las dependencias entre objetos.

Un forma común de establecer esta dependencia es codificar dentro de una clase, normalmente en el constructor, la creación de la instancia de un objeto que es necesario para su funcionamiento.

 
public class Dependencia { ... }

public class Clase {
	private Dependencia depend;
	
	public Clase() {
		depend = new Dependencia();
	}
	
	public void funcion() {
		depend.doSomething();
	}
}

class Program {
	public static void main(String [ ] args) {
		Clase miclase = new Clase();
		miclase.funcion();
	}
}

Este tipo de dependencia suele ser denominado fuerte porque una clase depende directamente de la otra para funcionar. Cualquier cambio en la clase de la que se depende obliga a la realización de cambios en la clase dependiente generando, en la práctica, una subordinación entre una y otra.

Como podemos suponer, al ser dos clases diferentes, las responsabilidades de cada una son distintas y no deberían estar tan ligadas porque dificulta el mantenimiento, la extensión del código y la escalabilidad del software. Aquí es donde entra la inyección de dependencias.

Para lograr una mayor separación de responsabilidades, este patrón recomienda la utilización de interfaces o clases abstractas para establecer las dependencias y, por lo tanto, el uso de objetos ya creados en vez de instanciarlos internamente.

En la práctica, cada clase debe indicar el «tipo» de objeto que necesita para trabajar y es otra parte del código la que se debe encargar de implementar la clase en función de la interfaz, crearlo y pasarlo al objeto.

 
public interface iDependencia { ... }

public class MiDependencia : iDependencia { ... }

public class Clase {
	private iDependencia Depend;
	
	public Clase(iDependencia d) {
		Depend = d;
	}
	
	public void funcion() {
		Depend.doSomething();
	}
}

class Program {
	static void main() {
		MiDependencia dependencia1 = new MiDependencia();
		Clase miclase = new Clase(dependencia1);
		miclase.funcion();
	}
}

Como se puede observar ya no existe una relación directa entre ambas clases. Nuestra clase indica que necesita un objeto creado a partir de una clase que implemente la interfaz pero no específica qué clase. Este tipo de separación permite cambiar rápidamente la clase que pasamos como dependencia e incluso trabajar con varias clases.

Un ejemplo muy extendido de este tipo de diseño es el que utilizan los frameworks que se comunican con bases de datos. Estos establecen una interfaz con este fin y una o dos clases que la implementen para distintas BBDD dando la libertad al programador de crear una nueva si necesita trabajar con otra o instanciarlas varias veces si necesita más de una conexión.

Como toda solución tiene sus pros y sus cons. Como otra ventaja aparte de las mencionadas, al estar más modularizado el código, es más fácil realizar test unitarios.

Como contra la necesidad de que el lenguaje soporte interfaces o clases abstractas y la necesidad de escribir más código para implementar el diseño. También, a consecuencia de agregar un grado de separación entre la dependencia y la clase, se puede dificultar la depuración en caso de surgir errores de integración.

Patrón de Carga Diferida: Value Holder

Esta entrada es la parte 4 de 4 en la serie Patrón de Carga Diferida

El patrón de carga diferida es una técnica para mejorar la performance utilizada en casos en que nos encontramos con que no todas las características de un programa son usadas durante su ejecución o para distribuir los tiempos de carga, cuando estos son muy grandes, durante la ejecución para poder mejorar los tiempos de respuesta al iniciar.

Hay cuatro formas comunes de implementar la carga diferida: inicialización diferida, proxy virtual, fantasma y value holder.

Value Holder

Esta técnica implica la utilización de un objeto cuyo tiempo de carga es menor y que reemplaza al objeto original hasta que sea necesario su carga.

Por ejemplo, la utilización de una imagen con pocos colores y de muy  pequeño tamaño (un logo en escala de grises) que se utiliza en los sitios webs con muchas fotos en vez de la foto original hasta que esta es cargada.

Es necesario que el value holder esté optimizado al máximo, si termina siendo menos o igual de eficiente que cargar el objeto original el método pierde sentido.

<img class="lazy" src="placeholder-image.jpg" data-src="image-to-lazy-load-1x.jpg" data-srcset="image-to-lazy-load-2x.jpg 2x, image-to-lazy-load-1x.jpg 1x" alt="I'm an image!">
document.addEventListener("DOMContentLoaded", function() {
  var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));

  if ("IntersectionObserver" in window) {
    let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          let lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          lazyImage.srcset = lazyImage.dataset.srcset;
          lazyImage.classList.remove("lazy");
          lazyImageObserver.unobserve(lazyImage);
        }
      });
    });

    lazyImages.forEach(function(lazyImage) {
      lazyImageObserver.observe(lazyImage);
    });
  }
});

Fuente:  Lazy Loading Images and Video

Patrón de Carga Diferida: Fantasma

Esta entrada es la parte 3 de 4 en la serie Patrón de Carga Diferida

El patrón de carga diferida es una técnica para mejorar la performance utilizada en casos en que nos encontramos con que no todas las características de un programa son usadas durante su ejecución o para distribuir los tiempos de carga, cuando estos son muy grandes, durante la ejecución para poder mejorar los tiempos de respuesta al iniciar.

Hay cuatro formas comunes de implementar la carga diferida: inicialización diferida, proxy virtual, fantasma y value holder.

Ghost

Esta técnica implica la creación del recurso pero con una cantidad mínima de información y diferir el resto de la carga hasta que sea necesario.

Por ejemplo, al presentar un listado inicializamos el objeto con la información mínima para mostrar (por ejemplo un título o una descripción) y al hacer click en un ítem recién cargamos el resto del objeto para poder acceder a la información completa.

Algunas consideraciones que es necesario tener en cuenta al utilizar este patrón son:

  • Como la carga se realiza en dos tramos, puede que cuando hagamos la carga inicial el objeto esté disponible y cuando querramos obtener el resto de la información no.
  • Para que tenga sentido usar este patrón la carga mínima tiene que ser considerablemente más chica que la carga total del recurso sino el overhead por realizar dos accesos puede terminar haciendo todo el proceso menos eficiente.
function Documento(id) {
  var self = this;

  $.get('/get_preview/' + id, function (response) {
    self.title = response.title;
    self.path = response.path;
  });

  function mostrar_documento() {
    $.get('/get/' + id, function (response) {
      self.data = response.data;
      console.log(self.data);
    });
  }
}

var documentos = [
  new Documento(1),
  new Documento(3),
  new Documento(4),
];

documentos.forEach( function(e) {
  $('body').append( function(html, index) {
    var $item = $('<p><strong>' + e.id + ': ' + e.title + '</strong>');
    $item.click( this.mostrar_documento() );
  });
});

Patrón de Carga Diferida: Proxy Virtual

Esta entrada es la parte 2 de 4 en la serie Patrón de Carga Diferida

El patrón de carga diferida es una técnica para mejorar la performance utilizada en casos en que nos encontramos con que no todas las características de un programa son usadas durante su ejecución o para distribuir los tiempos de carga, cuando estos son muy grandes, durante la ejecución para poder mejorar los tiempos de respuesta al iniciar.

Hay cuatro formas comunes de implementar la carga diferida: inicialización diferida, proxy virtual, fantasma y value holder.

Proxy virtual

Esta técnica implica la creación de un contenedor con la misma interfaz que el recurso original que carga el mismo cuando se realiza el primer llamado a uno de sus métodos.

Por ejemplo, una galería con cientos de imágenes que crea los objetos que representan todas las imágenes al iniciar el programa pero estos recién leerán la imagen del disco cuando tengan que dibujarla.

Algunas consideraciones que es necesario tener en cuenta al utilizar este patrón son:

  • Dependiendo del lenguaje de implementación y el tamaño de la clase puede terminar siendo un código engorroso y repetitivo con un montón de métodos públicos que únicamente llamen al loader.
  • La carga del recurso es transparente. A los efectos del resto del programa se hace al momento de crear el objeto.
  • Como en cualquier otro método de carga diferida, nos podemos encontrar conque el recurso no existe o no está accesible. Además, si toma mucho tiempo cargarlo, la ejecución del programa se puede ver interrumpida.
public class Image {

  public Image(filename) {
    /* Ahora cargaría la imagen desde el disco */
  }
  
  public void draw() { /***/ }
}

public class ImageProxy {
  private String filename;
  private Image image;

  public ImageProxy( filename ) {
    this.filename = filename;
  }

  public void draw() {
    if (this->image == null) {
      this.image = new Image(this.filename)
    }

    this.image.draw();
  }
}

 

Insertar o actualizar en MySQL

Al momento de agregar una nueva fila a una tabla en MySQL nos podemos encontrar que nos devuelve el error 1062: Duplicate entry <valor> for key <columna>, indicándonos que ya existe un registro con ese valor para esa columna. Ya sea porque enviamos un bloque de sentencias y necesitamos que se ejecute completo aunque haya duplicados o porque queremos solucionar con una sentencia la inserción o actualización de un registro, nos encontramos con la necesidad de poder indicarle a MySQL que hacer en estos casos.

Para esto, el motor de BBDD, pone a nuestra disposición, 3 opciones:

IGNORE

INSERT IGNORE INTO t1 (a,b,c) VALUES (1,2,3);

A partir de la versión 4.0.1 de MySQL se puede utilizar la clausula IGNORE para indicar que no se tengan en consideración los errores que surjan al intentar insertar el nuevo registro. Dependiendo del error, nos podemos encontrar frente a dos situaciones: un error de inserción (por ej., clave duplicada) con lo que el nuevo registro se descarta silenciosamente o un error de conversión de datos (por ej., pasaje de un string en vez de un integer) en donde el motor fuerza la conversión e inserta el registro.

Una consideración es que desde la versión 5.1.22, aunque el registro sea descartado, las columnas con AUTO_INCREMENT igualmente aumentaran su índice. Normalmente no nos debería afectar pero es bueno tenerlo en cuenta.

Una vez terminada la ejecución podemos utilizar mysql_info (en C) o mysqli_info (en PHP) para determinar la cantidad de registros efectivamente agregados a la tabla.

REPLACE

REPLACE INTO t1 (a,b,c) VALUES (1,2,3);

La instrucción REPLACE nos permite indicar al motor de base de datos que si el registro ya existe, lo reemplace por el que indicamos. Es como realizar un DELETE y luego un INSERT en una operación atómica. Al eliminar primero el registro anterior, no podemos utilizar ninguno de los datos almacenados en el mismo. Los campos para los que no especifiquemos valor, tomaran el que se haya indicado como por defecto para la columna al crear la tabla.

A tener en cuenta, como no se actualiza el registro anterior sino que se elimina e inserta uno nuevo, para poder utilizar REPLACE se necesitan permisos de DELETE e INSERT sobre la tabla; las columnas con AUTO_INCREMENT tomarán valores nuevos y cualquier instrucción cascada será ejecutada.

Además, como ocurre con cualquier operación de INSERT o DELETE, el índice de la tabla tiene que ser reconstruido haciendo de esta una operación extremadamente costosa.

La cantidad de registros afectados por la sentencia REPLACE que nos informa el motor de base de datos equivale a la suma de las bajas y altas que se realizaron. Es decir, cuenta 1 por registro si no existía y 2 si lo reemplazó.

ON DUPLICATE KEY

INSERT INTO t1 (a, b, c) VALUES (1, 2, 3)
  ON DUPLICATE KEY UPDATE c = c + 1;

Desde su versión 4.1, MySQL permite utilizar la clausula ON DUPLICATE KEY UPDATE en las sentencias INSERT permitiéndonos indicar al motor que cuando se encuentre que ya existe un registro con esa clave o valor para una columna declarada como UNIQUE en vez de abortar la operación, haga un UPDATE.

Al igual que en cualquier UPDATE, en caso de tener claves compuestas, la selección para la actualización se hará de la forma más restrictiva posible (por. ej, si UNIQUE(a, b), se usará WHERE a=? AND b=? y no un operador disyuntivo). Igualmente, si se actualiza un registro preexistente, los índices de las columnas AUTO_INCREMENT, no variarán.

En caso de que los valores del nuevo registro sean de gran tamaño o queramos evitar enviar dos veces el mismo valor, se puede utilizar la instrucción SET de la siguiente forma:

SET @a = 1, @b = 2, @c = 3;

INSERT INTO t2 (a, b, c)
  VALUES (@a, @b, @c)
  ON DUPLICATE KEY UPDATE b=@b, c=@c;

La cantidad de registros afectados por la sentencia INSERT que nos informa el motor de base de datos equivale a la suma de las actualizaciones y altas que se realizaron. Es decir, cuenta 1 por registro si existía y 2 si hubo que darlo de alta.

Workflow en WordPress

La estructura de directorios que uso en mi workflow se aprovecha de una feature de WordPress que permite distribuir grupos de themes. La idea es que en vez de almacenar un theme por directorio se puedan poner varios usando subdirectorios.

El funcionamiento de esta feature es bastante sencillo, cuando WP lista las carpetas en wp-content/themes para ver que themes hay instalados, revisa si en la raíz  de las mismas está el archivo style.css; si no lo encuentra busca en los subdirectorios de primer nivel de la misma por si es un grupo de themes.

La idea entonces es que en nuestro entorno de desarrollo ese subdirectorio, que WP va a identificar como el que contiene el theme, sea el de las builds y que cualquier otro subdirectorio de primer nivel no tenga un archivo style.css.

  • build
  • dist/theme
  • src
    • images
    • languages
    • scripts
      • admin
      • customize
      • modules
    • styles
    • templates
      • admin
      • customize
      • modules
    • vendor
  • tasks

Build y Dist

Como se deduce de sus nombre, build, contiene las builds con todo el código sin comprimir y preparado para debug mientras que en dist se guarda el theme listo para producción.

Para evitar confundir a WP, es importante que en la raiz del directorio dist no se encuentre el style.css sino en un subdirectorio de este. Esto, además, nos simplifica el proceso de crear el zip / tar.gz para distribuir porque ya nos queda todo en un directorio listo para comprimir.

Src

Los «fuentes» del theme en el que estamos trabajando: php, imágenes y scss sin procesar, archivos de traducción, étc. Casi todo lo que está en este directorio va a ser procesado, optimizado, comprimido y demás operaciones que van a dar como resultado nuestro theme.

La idea original del directorio images era, justamente, guardar imágenes que se usaran en el diseño del theme pero, hoy en día, con los avances de CSS únicamente almacena el screenshot.

La carpeta templates contiene todo el código php, el ordenamiento interno tiene que cumplir con las limitaciones y recomendaciones de cualquier theme.

Me gusta mucho trabajar con el customizer así que suelo generar bastante código para este y, por lo tanto, tanto en la carpeta de scripts como de templates lo guardo en un directorio separado.

Además, a lo largo del tiempo, he creado algunos snipets de código que utilizo tan habitualmente como preload y lazyload, google fonts, étc que los mantego de forma separada y que cuando los incluyo en un proyecto los guardo en la carpeta modules.

Por una cuestión de separación también guardo en otro directorio, admin, todo el código que está pensado únicamente para ejecutarse en el dashboard de WP.

Por último, como no siempre hay paquetes con la librería que necesito, la versión que busco o no quiero usar un CDN, o por lo que sea, tengo el directorio vendor que se copia íntegramente tanto a las build como a la dist.

Tasks

Las tasks de Gulp.js: build, clean, clean-vendor, images, scripts, styles, templates, translation, vendor, watch.

Mantengo separadas las partes de código propio del código de vendor: build y clean para uno y vendor y clean-vendor para el otro. Ídem con las traducciones: translation.

Normalmente, build se encarga tanto de generar tanto la versión de pruebas como la versión para distribución. Antes las generaba con tareas específicas pero siempre se terminaban dando dos escenarios: dos tareas muy parecidas que había que mantener sincronizadas manualmente o una tarea con un montón de código duplicado y un enredo de condicionales.

La más importante de las tareas es watch que monitorea los cambios y actualiza la build. Para esto utilizo el modulo que trae Gulp por defecto en conjunto con BrowserSync para la inyección del nuevo CSS pero sin actualización automática. Pero, cuando trabajo sobre el customizer, desactivo completamente BS porque no se llevan bien y se suele quedar con pantallas en blanco u errores.

Gists

WP_Deduplicator: Clase estática que permite llevar el control de los post mostrados para evitar duplicar el contenido.

WP_Keepalive: Función que agrega o modifica la cabecera Connection para informar al cliente que es posible reutilizar la conexión abierta ahorrándonos establecer una conexión nueva para cada archivo.

WP_Clipboard: Función que usa una lista blanca para filtrar las etiquetas HTML del texto que se pega en el editor.