Documentación continua en la nube

Tenemos Travis para integración continua, Scrutinizer para inspección continua… pero hasta hace unos días no existía un servicio para generar documentación continua de proyectos.

Para mí es un follón generar y subir a la web los phpDocs de mis proyectos de software libre cada vez que hago commit (ya que quiero tenerlos siempre actualizados); y también es un follón administrar y configurar Jenkins u otros servicios de integración continua para que generen los docs con cada build.

Así que he pensado que no sería tan complicado hacer un sistema que genere y aloje los documentos de mis proyectos en GitHub. Y si es útil para mí, también puede serlo para otros.

Dicho y hecho. Aquí lo tienes, tan sencillo como autorizar la aplicación en tu cuenta en GitHub y elegir qué repositorios quieres documentar. Cada vez que hagas push al repositorio, los documentos serán automáticamente generados y podrás verlos en github-phpdoc.israelviana.es/docs/[tu nombre de usuario GitHub]/[nombre del repositorio]:

Github-phpDocs landing page

Github-phpDocs landing repo list

GitHub-phpDoc documentación

Puedes probarlo ya en github-phpdoc.israelviana.es

El servicio es gratuito y open-source; por supuesto, el código está en GitHub y la documentación en la nube ;-)

De momento solo soporta proyectos en PHP alojados en GitHub (repositorios públicos de momento), pero si hay suficiente demanda se puede ampliar a otros lenguajes o alojamientos.

¿Y tú, generas documentación del código de tus proyectos? Si tienes proyectos PHP en GitHub te agradecería que probases el servicio y me dieras todo el feedback posible. ¡Gracias de antemano!

Y por último, una pregunta: ¿Estarías dispuesto a pagar 2€ por documentación privada de repositorios privados?

WordPress multisite sin WordPress multisite

Como sabrás, WordPress permite alojar varios sitios diferentes con una misma instancia del CMS. Pero este sistema tiene algunas limitaciones:

  • Los sitios deben estar en subdominios o subdirectorios, por ejemplo blog1.example.org o example.org/blog1. No puedes usar nombres de dominio únicos (blog1.com, blog2.com). El plug-in MU Domain Mapping resuelve esta limitación, pero hace magia negra, y no mola.
  • Todos los sitios comparten los themes, plug-ins, usuarios y base de datos (problema de escalabilidad: no podrías usar varios servidores de MySQL). Eso no mola nada. En mi caso, porque tengo diferentes sitios con diferentes administradores y cada uno tiene sus themes y plug-ins.

Así que, viendo cómo funciona el proceso de carga de WordPress, me he dado cuenta de que se puede hacer muy fácilmente un hack que nos permita tener bases de datos, themes y plug-ins separados para cada sitio, y que se puedan mapear a dominios diferentes… más o menos como hace Drupal con el multi-site. Un multi-site de verdad.

Dicho así parece complicado, pero solo hay que pararse un segundo a pensar. Imaginemos que tenemos dos instancias completamente independientes, dos WordPress normales y corrientes, cada uno con su base de datos, etc.

¿Qué tienen de diferente esas dos instancias?

La base de datos, el directorio wp-content y el fichero wp-config.php. Todo lo demás es exactamente igual. Duplicado.

Por tanto, si “engañamos” de alguna forma al cargador de WordPress para cargue un wp-content y wp-config.php u otro en función del nombre de dominio, este se conectará a una u otra base de datos, ya que la información de conexión a MySQL está especificada en wp-config.php. Por tanto, habremos logrado WordPress multi-site.

¿Y cómo hacemos ese truco para “engañar” a WordPress y hacer que cargue uno u otro directorio wp-content y fichero de configuración wp-config.php? En primer lugar, organizaremos nuestros sitios. Por ejemplo, en la raíz de la instancia crearemos un directorio sites, dentro del cual pondremos los wp-config.php y wp-content de cada sitio, en sub-directorios nombrados con el nombre de dominio:

Estructura de ficheros para WordPress multisiteCarpetas para cada sitioCarpeta de un sitio en WordPress multisite

Ahora viene lo bueno. Si echamos un vistazo a wp-load.php vemos que aquí se carga wp-config.php y se declara la constante WP_CONTENT_DIR, que indica la ubicación del directorio wp-content.

Modificaciones en el loader (wp-load.php) para WordPress multisite

Modificamos las declaraciones de WP_CONTENT_DIR y WP_CONFIG poniendo las rutas que nos interesen en función del nombre de dominio solicitado. El código final de wp-load.php quedaría así (código completo de wp-load.php en GitHub):

wp-load.php interceptado (2)

wp-load.php interceptado (1)

Para tener todo listo solo faltan dos detalles: la configuración de Apache y la creación de la base de datos.

Crear la base de datos para el WordPress multisite

Para crear la base de datos de cada site, simplemente tendremos que clonar la BD de un WordPress recién instalado para los demás sitios. No sería difícil automatizarlo con un script.

Configurar Apache

La configuración necesaria para un WordPress multi-sitio con esta receta es muy sencilla: crear tantos vhosts como queramos, haciendo que todos ellos tengan el mismo DocumentRoot. Por ejemplo:


        ServerName wp1.com
        ServerAlias  wp2.com wp3.com
        DocumentRoot /var/www/wp-multisite

Otro detalle importante: para que los administradores de los diferentes sitios puedan acceder a sus directorios wp-content particulares (y solo a los suyos), puedes crear usuarios del sistema (Linux, por supuesto) cuyo directorio $HOME es el subdirectorio de sites que le corresponde. Por ejemplo, para el usuario administrador de blog1.com, su directorio $HOME sería /var/www/wp-multisite/sites/blog1.com, suponiendo que tengamos la instancia de WordPress en /var/www/wp-multisite.

Conclusión

Al final, con este sistema lo que tenemos es prácticamente igual a tener instancias independientes de WordPress, pero con algunas ventajas interesantes:

  • Actualizaciones del núcleo centralizadas, ya que tenemos una sola instancia. Ya no tendrás que ir actualizando sitio por sitio. Eso sí, los plug-ins y themes se deben actualizar independientemente.
  • Ahorro de memoria: ahorras disco duro, y sobre todo ahorras RAM si usas APC (si no lo estás usando… ¡deberías hacerlo!). Una instancia de WordPress ocupa más o menos 20MB en APC; imagínate si tenemos 100 instancias de WordPress en el servidor… ¡compartiendo el código podemos ahorrar Gigas!

Desventajas

  • Es un sistema experimental que aún no he probado en producción, así que puede fallar por cualquier lado :-P
  • No existe una forma automatizada y amigable de crear nuevos sitios. Debes crearlos a mano a partir de plantillas de wp-config.php, wp-content y base de datos.
  • Si se actualiza el núcleo WordPress con el sistema automático, las actualizaciones que afecten a la base de datos solo afectarán a la del sitio desde el cual se haya actualizado el núcleo.
  • Seguridad: a no ser que se establezcan mecanismos adicionales, un administrador de un sitio puede romper con facilidad las otras instancias.

El genial e injustamente desconocido Adminer

Una breve nota para intentar difundir un poco más Adminer, una estupenda alternativa a phpMyAdmin. Si te parece que la nueva interfaz de phpMyAdmin es más incómoda que la “tradicional”, o que tiene demasiadas opciones, o que es muy lenta, Adminer es lo que necesitas. Y si estás contento con phpMyAdmin, al menos deberías probar Adminer una vez 

Adminer tiene varias cosas que le diferencian del archiconocido phpMyAdmin:

  • Es mucho, mucho más rápido.
  • La edición en línea de registros funciona de verdad.
  • Funciona con MySQL, PostgreSQL, SQLite, SQL Server y Oracle.
  • No tiene tantas opciones como phpMyAdmin: nada de gestión de privilegios, replicación, diseñador gráfico de esquemas… tan sólo crear y alterar tablas, búsqueda y manipulación de datos.
  • Se distribuye como un sólo archivo PHP, así que su despliegue y actualización es mucho más sencillo.

En mi opinión, la interfaz de Adminer es uno de esos ejemplos en los que ves claramente cómo una buena UI no consiste en botones redondeados con efecto 3D o vistosas animaciones, sino en una navegación rápida, directa y previsible. Y eso es el gran acierto de Adminer: su interfaz es ágil y sencilla, que no te hace perder el tiempo mientras trabajas con la base de datos.

Más info y descarga en www.adminer.org.

Merece la pena

[...] he participado en dos tipos de proyectos: Aquellos en los que se invierte algo de tiempo en usar tests automatizados (Unit Testing u otros..) que al final se acaba recuperando con creces además de hacer un producto o un sitio web bastante más estable, y aquellos en los que no hay “tiempo para esas cosas”, pero sí hay horas y horas (y días y días) para arreglar en un servidor de producción los problemas que unos pocos tests hubieran detectado un mes antes cuando alguien tuvo un mal día y tocó la línea de código equivocado.

Jose A. Reyero

¿Quieres más razones para hacer unit testing? Aquí tienes doce.

Si te animas, aquí tienes algunos recursos para empezar a hacer unit testing en PHP:

¿Y tú, ya automatizas tus tests?

Todo lo que deberías saber sobre APC (II)

Configurar APC: directivas de configuración Aviso: si no has leído antes el primer artículo de la serie deberías hacerlo.

CONFIGURANDO APC para una óptima optimización optimizada

Como ya sabrás, las directivas de configuración se pueden cambiar en los ficheros .ini de configuración de PHP y sus extensiones. En el caso de Linux, probablemente el fichero esté en /etc/php5/apache2/conf.d/apc.ini, aunque también puedes añadir directivas en php.ini o cualquier otro fichero .ini del directorio conf.d/, ya que todos son cargados por el motor de PHP.

De todas las directivas de configuración que APC ofrece, creo que estas son las más jugosas:

  • apc.stat: indica si APC debe comprobar, a cada petición, si el archivo solicitado ha cambiado. En un servidor de producción es interesante desactivar esta opción ya que nos ahorraremos esa llamada al sistema. Pero ¡cuidado con los cambios de código! Para recompilar un script debes limpiar manualmente el APC o bien reiniciar Apache (con FastCGI no serviría).
  • apc.stat_ctime: comprueba que un archivo ha cambiado a través de los inodes, en lugar de con mtime.
  • apc.shm_size: especifica la memoria reservada para APC, en MB. Por defecto es 30.
  • apc.max_file_size: tamaño máximo de script cacheable.
  • apc.lazy_functions y apc.lazy_classes: cargan las funciones y clases de los includes sólo cuando son necesarios.
  • num_files_hint: aproximadamente cuántos scripts tienes en tu servidor. Ayuda a APC a optimizar sus índices internos. Si no estás seguro, mejor dejarlo a 0.
  • user_entries_hint: aproximadamente cuántas entradas de usuario guardarás. No estás seguro, mejor déjalo en 0.
  • apc.cache_by_defaultapc.filters: si pones apc.cache_by_default = 1, APC sólo cacheará los scripts cuyo nombre coincida con la expresión regular que especifiques en apc.filters. Interesante si tienes algunos scripts que sabes que van a cambiar muy frecuentemente (por ejemplo, durante un período de actualización) y has sido tan machote de desactivar apc.stat.
  • apc.include_once_override: se trata de una característica experimental, que se supone que optimiza las llamadas include_once y require_once para que consuman menos recursos. Dentro de algún tiempo tendremos más información sobre esta funcionalidad.

La extraña pero maravillosa directiva apc.rfc1867

Entre todas estas directivas de configuración destaca rfc1867, que obviamente hace referencia al documento RFC 1867, el cual especifica la subida de ficheros por HTML/HTTP. Pero ¿esto a qué viene?

Pues viene a que con APC, además de cachear los opcodes y guardar valores en la cache, también puedes controlar el progreso de las subidas de ficheros.

Sí, amigos. Si activamos la directiva apc.rfc1867, por cada fichero que se suba a tu servidor APC creará e irá actualizando una user entry con información sobre la subida. Esta entrada contendrá algo así como:

Array
(
    [total] => 1142543
    [current] => 1142543
    [rate] => 1828068.8
    [filename] => test
    [name] => file
    [temp_filename] => /tmp/php8F
    [cancel_upload] => 0
    [done] => 1
)

Es decir, el tamaño total del fichero, los bytes transferidos (current), la velocidad de subida (rate) y otros parámetros. Con esta valiosa información puedes hacer una bonita barra de progreso para indicar a tus usuarios cómo van sus subidas. Si quieres más detalles sobre cómo utilizar esta característica, te remito a este artículo y, como siempre, al manual oficial.

Si te has quedado con ganas de más

  • apc@facebook: presentación de 2007 donde se explica el funcionamiento de APC y se exponen los valores de configuración en los servidores de Facebook. Además explican su interesantísimo sistema para distribuir configuraciones en múltiples servidores a través de APC.
  • 2bits cuentan un caso interesante con Drupal y la discusión es también muy rica.
  • ¡El manual! No me canso de decirlo.

Esto no termina aquí

Te toca a ti. ¿Tienes experiencia con APC? ¿Has notado la mejora de rendimiento en tus servidores de producción? ¿Cómo lo has configurado? ¿Me das la contraseña de root?