Refréscame esa caché

Wordpress, el CMS que uso para gestionar mi , dispone de varios plugins para acelerar su carga mediante cachés, algo muy necesario en general, y más si, como yo, eres usuario de un servicio de hosting barato.

En mi caso, el de caché que estoy usando es WPSuperCache, que guarda una copia estática de cada página generada por , y la sirve directamente en próximas peticiones, siempre y cuando el usuario no esté registrado. Esto evita todas las peticiones contra la base de datos por parte de . Además, opcionalmente, el permite guardar las páginas estáticas con una estructura de directorios equivalente a la que las representa, y proporciona reescrituras de URL para llegar a dichas páginas directamente, evitando toda intervención por parte de (y evitando, por lo tanto, la ejecución de código PHP en el servidor). Finalmente, además, te da la opción de guardar los archivos comprimidos con GZip. Todas estas opciones aceleran notablemente la carga de la página, puesto que el único trabajo que debe realizarse es el del : encontrar la página y servirla.

WPSuperCache, como la mayoría de plugins de caché, cuenta con un borrado automático de la caché cada cierto tiempo. Cada vez que se ejecuta esta tarea, las siguientes peticiones (si las hay icon_biggrin.gif ) a las distintas páginas del harán que se regenere la caché automáticamente.

Sin embargo, cuando tienes pocas visitas, no es buena idea hacer que la caché sea regenerada por los . En ese caso, el mío icon_smile.gif , es probable que un lector obtenga una página no cacheada en vez de una que sí lo está. Una posiblidad es aumentar en gran medida el intervalo de borrado de la caché, pero en general es preferible tener una caché actualizada. La otra posiblidad es, además de borrar la caché, regenerarla automáticamente, de tal manera que todos los del se beneficien de la caché del mismo.

En mi caso, he escrito un que visita todos los enlaces de una página web basándose en el sitemap de la misma, siempre que este cumpla el protocolo descrito por Sitemaps.org. El código es el siguiente:

#!/bin/
# Visit all the links provided by a  file.
# Diego Toharia - http://.deigote.com

# Verify parameter
if [[ $# -ne 1 ]] ; then
    echo "Error: first parameter ( ) missing"
    echo "Usage: `basename $0` "
    exit 1
fi

=$1
links=`wget -q -O - http://.deigote.com/.xml |  '{ print $1 }' | grep "^http" |  'BEGIN { FS=">" } { print $2 }' |  'BEGIN { FS="<" } { print $1 }'`

for i in $links ; do
	echo "Visiting " $i
	wget -q -O - $i > /dev/null
done

Seguro que hay formas más elegantes de hacerlo, pero es tan potente que es difícil resistirse a usarlo icon_biggrin.gif . Lo he llamado visit_site_by_sitemap, original que es uno icon_rolleyes.gif .

Una vez tenemos el , lo más fácil es programar una tarea del cron que cada cierto tiempo (preferiblemente, en franjas horarias con el menor tráfico posible) borre la caché y ejecute el pasándole como parámetro la del . Por cierto que, en mi caso, el lo genera el Google Sitemap Generator. El mandato para la regla en mi caso sería algo como:

cd path/al//wp-content ; find  -type f -name '*.' -exec rm {} \; -o -name '*.gz' -exec rm {} \; ; ~/bin/visit_site_by_sitemap http://.deigote.com/.xml

La idea es borrar todos los ficheros y gz generados por la caché y regenerar la misma visitando todos los enlaces proporcionados por el del .

Podemos hacer un par de pruebas que, sin ser demasiado científicas, nos dan una idea del beneficio que obtenemos. La primera sería ejecutar en local el dos veces, previo borrado de la caché. La primera visitaría todos los enlaces sin disponer de caché, mientras que la segunda lo haría usando la caché.

$ cd path/al//wp-content
$ find  -type f -name '*.' -exec rm {} \; -o -name '*.gz' -exec rm {} \;
$ time ~/bin/visit_site_by_sitemap http://.deigote.com/.xml
Visiting  http://.deigote.com/
...
real    4m12.102s
$ time ~/bin/visit_site_by_sitemap http://.deigote.com/.xml
Visiting  http://.deigote.com/
...
real	0m7.759s

Podemos ver que los resultados son espectaculares. De 4 minutos hemos pasado a 7 segundos. Sin embargo, estamos probando el caso óptimo, en el que la latencia es mínima y la velocidad de conexión con el es máxima, lo que hacen que la capacidad de proceso sea el único parámetro que influye en los resultados.

Si ejecutamos esta misma prueba en una máquina externa y situada en España, la misma desde la que estoy escribiendo, obtenemos unos resultados bien distintos: casi trece minutos (12m45) frente a casi 9 (8m44s).

Sin embargo, esto es culpa de la lamentable latencia y velocidad de conexión que tiene en España, ya que ejecutando la prueba en una máquina situada en USA (y de otro servicio de hosting distinto), se obtienen 3 minutos (3m02s) frente a 22 segundos, resultados más parecidos a la ejecución en local. Tendré que pensar seriamente en cambiar de hosting icon_cry.gif .

La otra prueba que se puede hacer es algo más realista: medir el tiempo de descarga de una única página, que es lo que hace un usuario cualquiera (no creo que tenga ningún lector tan fan como para visitarse todas las entradas del una detrás de otra icon_lol.gif ). En mi caso, he usado un navegador Firefox con la caché deshabilitada y con la extensión Firebug instalada, usando la pestaña Red de dicha extensión para medir el tiempo de carga del de la página de inicio. He realizado varias pruebas con la caché vacía y con la caché llena y he obtenido de media unos 2.5 segundos frente a medio segundo respectivamente, lo cual no está mal. Sin embargo, el resto de elementos de la página (malditos emoticonos icon_evil.gif ) ralentiza la carga total de la misma en gran medida, aunque eso es otra historia icon_smile.gif .

Gracias a Álvaro por su inestimable ayuda a la hora de lanzar el juego de pruebas icon_razz.gif en un servidor externo a españa.

Si la salida fuese un Excell, lo llamaríamos ingeniería del software

Lo que ha empezado como un simple conteo de ficheros para ver qué proyecto hacía que Eclipse fuese lento, ha terminado en todo un de líneas digno de aparecer en cualquier libro de del (nótese la cursiva, por favor icon_confused.gif ), si no fuera porque es un de consola con salida de texto simple.

Al grano:

#!/bin/
EXTENSIONES="$@"
ficheros_total=0
lineas_total=0
vacias_total=0
novacias_total=0
for ext in $EXTENSIONES ; do
   echo EXTENSION $ext
   ficheros=`find . -name "*.$ext" | wc -l`
   =`find . -name "*.$ext" | xargs cat | wc -l`
   novacias=`find . -name "*.$ext" | xargs cat |  'BEGIN {  = 0 } { if ($0 != "") ++} END { print  }'`
   vacias=`find . -name "*.$ext" | xargs cat |  'BEGIN {  = 0 } { if ($0 == "") ++} END { print  }'`
   porcentaje=`echo $vacias $ |  '{ print $1 / $2 * 100 }'`
   echo Tiene $ficheros ficheros de tipo $ext y $ , de las cuales $novacias tienen contenido y $vacias son vacias \(un $porcentaje %\)
   ficheros_total=`expr $ficheros_total + $ficheros`
   lineas_total=`expr $lineas_total + $`
   vacias_total=`expr $vacias_total + $vacias`
   novacias_total=`expr $novacias_total + $novacias`
done
if [[ $# -gt 1 ]] ; then
   porcentaje_total=`echo $vacias_total $lineas_total |  '{ print $1 / $2 * 100 }'`
   echo TOTAL
   echo Tiene $ficheros_total ficheros en total, con $lineas_total , de las cuales $novacias_total tienen contenido y $vacias_total son vacias \(un $porcentaje_total %\)
fi

Ejemplo de uso (guardandolo en un fichero cuenta_lineas.sh accesible por el path y con los permisos adecuados):

$ cd directorio_raiz_del_proyecto/ ; ./cuenta_lineas.sh java jsp xml
EXTENSION java
Tiene 388 ficheros de tipo java y 60035 , de las cuales 47806 tienen contenido y 12230 son vacias (un 20.3714 %)
EXTENSION jsp
Tiene 792 ficheros de tipo jsp y 91354 , de las cuales 75267 tienen contenido y 16088 son vacias (un 17.6106 %)
EXTENSION xml
Tiene 170 ficheros de tipo xml y 32282 , de las cuales 30437 tienen contenido y 1846 son vacias (un 5.71836 %)
TOTAL
Tiene 1350 ficheros en total, con 183671 , de las cuales 153510 tienen contenido y 30164 son vacias (un 16.4228 %)

Mola icon_mrgreen.gif aunque es mejorable sacando porcentajes (ver abajo icon_biggrin.gif ), pero no he encontrado un mandato tipo expr que trabaje con floats icon_neutral.gif (a ver si algún comentarista me da el tip icon_smile.gif )

EDITO: Ya se me ha ocurrido cómo hacer los porcentajes mientras contestaba icon_lol.gif actualizado el código y la salida del mismo

Columnas y centrado vertical, esos grandes amigos

O cómo centar verticalmente un flotante. Elegid el título que queráis, creo que ambos son igual de confusos icon_biggrin.gif .

Todo aquel que haya dedicado algo de tiempo a realizar páginas web, seguro que ha tenido que utilizar hojas de estilo CSS. De no ser así, puede ser poque se tenga una página web sin decoración alguna icon_biggrin.gif o porque se esté decorando la misma utilizando los obsoletos atributos de las etiquetas destinadas a esa tarea (ya se sabe, los atributos color, width, etcétera). En este último caso, se está incurriendo en un error, ya que estos elementos están desaconsejados desde HTML 4, y existen alternativas para los mismos.

Con la llegada de dicho estándar y de las mencionadas hojas de estilo, otra de las cosas que se desaconsejan es la con tablas, siendo su alternativa la utilización de divs. Existen muchísimos enlaces al respecto, en los que se puede leer acerca de cómo , cómo evitar hacerlo, y las razones para ello. Mi resumen de las respuestas sería algo como:

  • Que es realmente fácil, ya que por defecto cuentan con columnas, filas y celdas y permiten trabajar con ellas de manera muy flexible e intuitiva.
  • Que para no se debe englobar cada conjunto de información en divs (seguramente, el mismo conjunto que antes englobaríamos en una celda de una tabla) y jugar con las posibilidades que ofrece (sobretodo, las propiedades float y clear)
  • Y que las razones para no son que las tablas sólo deben usarse para, precisamente, representar datos agrupados en forma tabular. En definitiva, la idea es usar cada tag para dar información semántica y nunca estética, ya que de esto último se encargan las propiedades .

Sin embargo, es difícil conseguir algunas de las cosas que con tablas son realmente fáciles, debido a que estas últimas tienen un comportamiento muy noble, mientras que algunas propiedades , y en concreto una fundamental como es float, se comportan de manera realmente extraña en muchas ocasiones. Una de esas cosas es el centrado vertical de algún elemento que se encuentra dentro una columna maquetada con divs.

¿Qué pretendo?

Básicamente, lo que quiero conseguir es algo como esto:

columna uno columna dos,
la cual es bastante
más alta que la anterior
columna uno columna dos,
la cual es bastante
más alta que la anterior,
y además la podemos hacer
todavía más alta
y la columna 1 sigue centrada

Si examináis el código fuente de los ejemplos anteriores, veréis que están maquetados con tablas. Automáticamente, la información de la columna uno se centra verticálmente, aunque posteriormente podemos modificarla con la propiedad de . Por ejemplo, la primera tabla tiene este código fuente:

< style="border: 1px solid green">
<tbody>
<tr>
<td style="border: 1px solid red">columna uno</td>
<td style="border: 1px solid blue">columna dos,
la cual es bastante
más alta que la anterior,
y además la podemos hacer
todavía más alta
y la columna 1 sigue centrada</td>
</tr>
</tbody></>

El problema

Si esta misma la hacemos usando divs, obtendríamos el siguiente resultado:

columna uno
columna dos,
la cual es bastante
más alta que la anterior,
y además la podemos hacer
todavía más alta
y la columna 1 ya no se centra

cuyo código fuente es el siguiente:

< class="contendor" style="border: 1px solid green; margin: 0; padding: 0">
< class="columna1" style="border: 1px solid red; margin: 0pt; padding: 0pt; float: left; width: 10em; : 100%; : ;">columna uno</>
< class="columna2" style="border: 1px solid blue; margin: 0; padding: 0; padding-left: 10em">columna dos,
la cual es bastante
más alta que la anterior,
y además la podemos hacer
todavía más alta
y la columna 1 ya no se centra</>
</>

Como podemos observar, el comportamiento de los es bastante diferente al de las tablas por defecto. Por ejemplo, la anchura se adapta a la del contenedor en lugar de a la del contenido, y el alineado vertical se ajusta a la parte superior.

La idea es, sin embargo, que permite modificar dicho comportamiento por defecto, pero en la práctica no podemos alterarlo tan fácilmente, ya que casi siempre estamos obligados a utilizar la propiedad float, que tiene algunas características curiosas, como por ejemplo hacer que el tamaño del se ajuste al contenido (como en las tablas) y que puedas modificar la anchura con respecto al contenedor, pero no la altura.

Es decir, que podemos decir que el ancho sea de 10em (o podríamos decirle un 50% del contenedor), pero que le digamos que la altura es de un 100% no le afecta. Las dos cosas se pueden observar en el ejemplo anterior.

Una posible solución

La única solución que he encontrado hasta ahora es hacer que los se comporten como tablas. Esto es posible porque los creadores del estándar incluyeron en la propiedad display una serie de valores para permitir maquetar divs usando la lógica de tablas. El resultado sería algo como lo siguiente:

columna uno
columna dos,
la cual es bastante
más alta que la anterior,
y además la podemos hacer
todavía más alta
y la columna 1 se vuelve a centrar

Que, como podemos ver, permite el centrado vertical sin mayor problema. Su código fuente es el siguiente:
< class="contendor" style="border: 1px solid green; margin: 0; padding: 0; display: ">
< class="contendor-secundario" style="border: 1px solid yellow; margin: 0; padding: 0; display: ">
< class="columna1" style="border: 1px solid red; margin: 0pt; padding: 0pt; : ; display: ">columna uno</>
< class="columna2" style="border: 1px solid blue; margin: 0; padding: 0; display: ">columna dos,
la cual es bastante
más alta que la anterior,
y además la podemos hacer
todavía más alta
y la columna 1 ya no se centra</>
</>
</>

Podemos observar que necesitamos un que haga de tabla (contenedor, con la propiedad display como ), uno que haga de una fila de la tabla (contenedor-secundario, con la propiedad display como ) y cada una de las celdas (columna1 y columna2, con la propiedad display como ).

Si os fijáis, esto añade un nuevo, el cual no tiene ningún propósito excepto el de ayudar a la , lo cual nunca es recomendable (se supone que el diseñador no debe tener necesidad de modificar el si este está bien empaquetado en sus correspondientes divs etiquetados con identificadores y clases). Además, resulta irónico tener que simular el comportamiento de las tablas vía para lograr lo mismo que anteriormente se lograba usando tablas directamente. Estas razones hacen que no me guste demasiado esta solución, no obstante es la única que de momento conozco.

Tener que recurrir a este tipo de soluciones me parece la prueba más evidente de que la usando no está en absoluto depurada, conclusión a la que probablemente habrán llegado la mayoría de diseñadores web icon_biggrin.gif .

Caso particular: la columna a alinear es una imagen

En el caso de que queramos centrar verticalmente una columna cuyo único contenido es una imagen, podemos conseguirlo haciendo que esa imagen sea la imagen de fondo de la columna, ya que la propiedad background si que permite alinear verticalmente en todos los casos (parece que float, la más utilizada, es la única conflictiva icon_razz.gif ).

Esto sólo se debería usar en el caso de que la imagen sea méramente decorativa y no forme parte del contenido. Recordemos que idealmente, si eliminamos todas las hojas de estilo, la web no debería perder funcionalidad ni contenido, por lo que si la imagen aporta contenido, debería estar en el . Un ejemplo de cómo hacer esto sería el siguiente:

columna dos,
la cual es bastante
más alta que la anterior,
y además la podemos hacer
todavía más alta
y la columna 1 sigue centrada

Cuyo código fuente es el siguiente:

< class="contendor" style="border: 1px solid green; margin: 0; padding: 0; background: (http://.deigote.com/wp-content/themes/k2/styles/deigote/info.png) no-repeat scroll 0% 50%; padding-left: 60px">columna dos,
la cual es bastante
más alta que la anterior,
y además la podemos hacer
todavía más alta
y la columna 1 sigue centrada
</>

Podemos ver que en este caso nos evitamos todos los excepto el contenedor, quedando el código más limpio. Sin embargo, este caso es muy particular y no nos resuelve nada en la mayoría de ocasiones icon_sad.gif .

Los chistes si míos, gracia me hacen

Si, ya sé que lo normal es citar a otras personas. Pero yo he sido bendecido con el mayor don que una persona puede recibir: me hago mucha gracia a mi mismo.

No puedo evitarlo, mis lamentables ocurrencias siempre me hacen partirme de risa, incluso cuando el resto de personas no pueden sino mirarse entre ellos icon_eek.gif sin saber cómo sortear la tensión que supone que alguien cuente un y nadie se ría. En mi caso, esto es mucho peor, porque sí que se ríe alguien, pero siempre soy yo mismo icon_lol.gif .

Hace tiempo me callaba los chistes para evitar esta situación, pero ya he llegado a tal paz conmigo mismo que no me importa. Cuando puedo, la suelto y me descojono yo solo. Y en ocasiones, las más escasas, incluso acompañado icon_biggrin.gif .

Por ello no puedo sino citarme a mi mismo con mi última ocurrencia (algunos dirán que es ego, pero yo prefiero pensar que es por todo lo que he dicho antes… y total, como ya he explicado arriba, me viene dando igual lo que penséis icon_lol.gif ).

Así que ahí va. Yo dije (y me quede tan ancho):

Lo bueno si bebe, no pasa sed

Deigote, en el Twitter.