Personalizar un sitio web a medida

Este capítulo se ocupara de presentar los principios, tecnologías y prácticas que permiten personalizar nuestro sitio web a medida, colocándolas en contexto y comparándolas brevemente con otras, para profundizar finalmente en ellas. Luego de presentar la parte visual a través de las plantillas, se va adentrando en las fuentes de datos y desde allí introduce la necesidad de conocerlas y trasformalas a través del código.

Principios organizativos de la información

Los siguientes principios orientan la construcción de los sitios hechos en Brea, dan cuenta de cómo las apuestas de las infraestructuras de bolsillo encarnan específicamente en este proyecto y nos ayudar a leer e intervernir los sitios, cuando estemos creando contenidos, temas o extendiendo la funcionalidad de los mismos. Los enunciaremos a continuación y mostraremos otros lugares y tecnologías donde podemos ver aplicados principios similares.

  • Cercanos al upstream: Mientras que algunos CMS reempaquetan plantillas y temas que encuentran en Internet para adecuarlos a cómo tales CMS organizan la información, en Brea somos más cercanos a cómo los autores originales han diseñado tales temas y plantillas HTML, así que los intervenimos respetando la jerarquía de información original concebida por los autores e indicamos cómo los temas son interpretados y modificados por Brea (usualmente mediante un archivo brea.json o brea.yaml y/o una carpeta brea/ ubicados en el directorio raíz del tema, que contiene los archivos que organizan la manera en que Brea interpreta e interviene el tema, como veremos en su momento).

  • El sistema de archivos como “base de datos”: Un derivado del aspecto anterior es que el sistema de archivos opera como “base de datos” en el sentido de que si una página en Brea queremos que aparezca en una ruta en particular, habrá una jerarquía de carpetas, subcarpetas y archivos que modele dicha ruta y sea evidente dentro del sistema de archivos que compone un tema. Esto contrasta grandemente con otros CMS más complicados, donde ellos organizan la información de una manera particular y quien quiere la información web publicada en una ruta o forma específica, debe aprender la idiosincracia particular de dicho CMS y las maneras en que las carpetas, subcarpetas y archivos del mismo son interpretados para aparecer en otra ruta específica.

  • Proximidad y localidad: La información relacionada se encuentra más cerca entre sí y las configuraciones locales tienen prioridad sobre las configuraciones globales. Por ejemplo, la plantilla aplicada para producir un conjunto de páginas particular estará en la misma carpeta donde se almacenan dichas páginas en HTML y su código fuente en Markdown y un archivo de configuración guardado en un subfolder, tendrá prioridad sobre los archivos de configuración guardados en los folders ubicados más arriba en la jerarquía de archivos.

El primer principio puede rastrearse a los llamados sistemas de paquetes para instalar software en Gnu/Linux. Por ejemplo, mientras distribuciones basadas en RedHat/Fedora y Debian/Ubuntu, reorganizan el software que encuentran en Internet para que siga las conveciones de tales distribuciones y las colocan en formatos .rpm y .deb propios de las mismas, distribucions derivadas de Arch y Manjaro respetan mayoritariamente la organización de paquetes que los autores originales de los mismos han usado y empaquetar software para dichas distribucioes consiste sobre todo en crear unos sencillo scripts (llamados manifiestos) que dan cuenta de cómo dicho software, sin mayores cambios es interpretado por el gestor de paquetes para ser instalado y administrado en Arch o Manjaro.

Un ejemplo de los dos últimos principios mencionados puede, de nuevo, rastrearse a las distribuciones de Gnu/Linux. Mientras que la mayoría sigue un estandar Unix que “desparrama” la información de un mismo paquete por todo el árbol de directorios, de acuerdo a una convención y usa una base de datos extra para gestionar paquetes de software, distribuciones minoritarias, como GoboLinux, y NixOS y Gnu/Guix, colocan carpetas, subcarpetas y archivos que mantienen junta la información de un mismo paquete de acuerdo a convenciones propias (pero con correspondencias que las asocian con las convenciones más populares) y permiten que recorrer el árbol de carpetas y subcarpetas sea análogo a explorar la “base de datos” para ubicar por ejemplo todos los archivos que pertenecen a una misma versión del software, tener versiones paralelas, haciendo así que borrar paquetes sea, en esencia, borrar un único directorio

Los tres principios anteriores nos dan una mirada general de la “arquitectura de información” de Brea y nos ayudan a entrever cómo éste CMS concibe y prioriza la organización de la misma y serán particularmente útiles cuando empecemos a personalizar nuestros sitios web. Otro aspecto que será clave en dicha personalización tiene que ver con cómo diferentes fuentes de información se combinan para producir el sitio y a ello dedicaremos las siguientes secciones.

Lenguajes de Plantillas

Un lenguaje de plantillas es esenciamente una forma de inyectar datos en plantillas prehechas, que se convierten habitualmente en documentos (HTML, PDF). Se comportan de manera similar a como lo hacen las plantillas de los procesadores de palabra habituales (MS Word, LibreOffice Writer, Apple Pages), en los que, en lugar de crear un documento en blanco, partimos de una plantilla que tiene la información pre-organizada de acuerdo a un molde, por ejemplo el de una carta. Crear un documento a partir de una plantilla es llenar los datos de la misma, cambiando unos placeholders por nuestra información específica (ejp: fecha, remitente, asunto, cuerpo de la carta), mientras que mantenemos la estructura general.

Existen esencialmente dos tipos de lenguajes de plantillas:

  • Logicless: Sólo indican si un dato es único, múltiple, ausente o presente y la lógica es externa a la plantilla. Un ejemplo de estos sistemas es Mustache.
  • Logicfull: Incluyen, además de lo anterior, cómo deben procesarse ese datos, es decir vincuan la lógica de procesamiento a la plantilla, usualmente a traves de operadores de programación: ciclos (for), condicionales (if), etc. Casi siempre surgen vinculados a una comunidad de programación que los usa para un lenguaje particular. Ejemplos son Jinja (Python), Twig (PHP), Liquid (Ruby), entre muchos otros.

Haremos una comparación de estos dos enfoques acompañada por código. En caso de no estar familiarizados con el mismo, recordemos la recomendación inicial respecto a ver el código como un “lenguaje extranjero” con el que vamos teniendo progresivamente experiencias más significativas en la medida en que nos lo encontramos. Así que el consejo es no evadir o saltar la lectura de código, sino pensarlo como “jeroglifos” de los que vamos haciendo sentido progresivo mientras nos preguntamos proactivamente por el mismo. Si ya tenemos experiencia con el código, la comparativa entre unos lenguajes y otros puede ser llamativa. Recuerdemos que la lectura es hipertextual, así que también nos invita a visitar enlaces y buscar por nuestra cuenta aquellos elementos conexos con lo que leemos.

Los lenguajes de plantillas logicfull desperdigan la lógica tanto dentro de la plantilla, donde además la entremezclan con los elementos de la presentación, como en los lenguajes de scripting que manipulan la plantilla. Ejemplifiquemos cómo ocurre lo anterior con Jinja. Una plantilla, llamada ejemplo.html.jinja para dicho sistema luciría algo así:

<!DOCTYPE html>
<html>
  <head>
    <title>{{ variable|escape }}</title>
  </head>
  <body>
  {%- for item in item_list %}
    {{ item }}{% if not loop.last %},{% endif %}
  {%- endfor %}
  </body>
</html>

Aquí se mezclan tres tipos de elementos:

  • Etiquetas HTML clásicas, que describen la apariencia del contenido en la plantilla como <html>, </html>, <head>, </head>, <body> y </body> (entre otras).
  • Instrucciones de escape al HTML, marcadas por elementos como {{, }}, {%, {%- y %}, que indican que lo que está allí corresponde a un valor que debe ser calculado y/o inyectado desde una fuente externa y colocado dentro del HTML por nuestro lenguaje de plantillas.
  • Instrucciones de procesamiento colocadas dentro de las instrucciones de escape al HTML representadas por elementos como interadores (for, endfor), condicionales (if, endif), y variables (item, item_list, variable).

El código en Python que procesa la plantilla anterior es el siguiente:

from jinja2 import Template
with open('example.html.jinja') as f:
    tmpl = Template(f.read())
print tmpl.render(
    variable = 'Value with <unsafe> data',
    item_list = [1, 2, 3, 4, 5, 6]
)

y su ejecución produce el siguiente resultado:

<!DOCTYPE html>
<html>
  <head>
    <title>Value with &lt;unsafe&gt; data</title>
  </head>
  <body>
    1,
    2,
    3,
    4,
    5,
    6
  </body>
</html>

El código en Python también contiene instrucciones de procesamiento, como podemos apreciar en elementos como from, import, with, as, open, print y variables como item_list y variable.

Es decir que las personas que van a trabajar con sistemas logicfull, tipo Jinja, debe conocer algo de programación para poder inyectar la lógica dentro de la plantilla y también en los scripts del lenguaje de programación que las procesa y que podrían tener incluso más lógica de programación adentro (por ejemplo la lista item_list podría no estar definida explícitamente como los números de 1 a 5, sino ser calculada usando un ciclo de Python).

En contraste, los sistemas de plantillas logicless, separan la parte del procesamiento de la parte de la presentación, de modo que alguna persona trabajando en un frente, no está obligada a saber del otro, sino que está invitada. La plantilla expresa en esencia la ausencia o presencia de datos y su caracter único o múltiple, y el lenguaje de programación se encarga de definir cómo calcular dichos datos e inyectarlos en esta plantilla.

Consideremos el mismo ejemplo desde la aproximación de Mustache. Supongamos que tenemos un archivo de texto en la carpeta temporal, llamado ejemplo.mus.html, con este contenido:

<!DOCTYPE html>
<html>
  <head>
    <title>{{ variable }}</title>
  </head>
  <body>
  {{# item_list }}
    {{ item }},
  {{/ item_list }}
  </body>
</html>

El siguiente código de Pharo, ejecutado en un playground, producirá una salida idéntica en la práctica a la de plantillas en Jinja,

| coleccion datos |
coleccion := OrderedCollection new.
1 to: 5 do: [ :i | 
    coleccion add: { 'item' -> i } asDictionary ].
datos := Dictionary new.
datos
    at: 'variable' put: 'Value with <unsafe> data'; 
    at: 'item_list' put: coleccion.
(FileLocator temp / 'ejemplo.mus.html') contents asMustacheTemplate 
    value: datos.

como se muestra en esta figura:

La diferencia fundamental entre los dos enfoques antes vistos es que el segundo (logicless) concentra en un sólo lugar toda la lógica en los scripts que procesan las plantillas, leen archivos, definen diccionarios de datos y demás. Esto hace que las plantillas sean mucho más sencillas, como podemos apreciar al comparar la plantilla en Jinja y su contraparte en Mustache y que no se requiera conocimientos de código para crearlas o modificarlas. Simplemente indicamos qué datos están presentes en ellas y si se trata de datos únicos (como {{ variable }}) o múltiples (como los contenidos entre {{# item_list }} y {{/ item_list }}) con su nombre (en este ejemplo {{item}}). La definición y procesamiento de los datos, como vimos en el script de Pharo anterior, apenas toma un par de líneas más que su contraparte en Python.

Al separar la lógica de la presentación, es posible también intervernir las plantillas desde múltiples lenguajes en distintos paradigmas de programación (funcional, objetual, declarativo, procedimental) y si bien en Brea hemos elegido a Pharo para intervenir las plantillas en Mustache y poblarlas de contenido, una vez dichas plantillas han sido definidas, podríamos intervenirlas desde Python, Lua, Nim, Elixir, JavaScript o alguno de nuestros lenguajes favoritos. Mientras que los lenguajes logicfull, nos fuerzan a pensar en el paradigma de lenguaje específico (usualmente procedimental) para declarar el comportamiento de nuestras plantillas, los lenguajes logicless nos permiten usar el lenguaje con el que nos sintamos más cómodos para poblar esos datos presentes, ausentes, únicos o múltiples (nota que para este ejemplo en Pharo no usamos ciclos for o condicionales if a diferencia del código en Python donde no tenemos otra alternativa, pues hace parte de la plantilla misma).


  • Ubica y abre el archivo plantilla.mus.html del tema para blogs que hemos venido usando en los ejercicios precedentes y ubica cuáles datos entre llaves dobles ({{}}) corresponden a datos únicos y cuáles a datos múltiples. Coloca sus nombres.
    ¿Qué hay de los datos entre llaves triples ({{{}}})? ¿A qué crees que correspondan?
    Si estás en un taller, comparte tus respuestas con las demás participantes usando el documento en vivo.
  • Crea un archivo ejemplo.mus.html en la carpeta temporal de tu computador y replica el ejemplo anterior en un playground desde Pharo.
  • ¿Estarías en condiciones de descargar otro tema de HTML5UP y crear una plantilla para el mismo? Documenta tus intentos y comparte tus exploraciones al respecto.
  • Si la respuesta al item anterior es afirmativa prueba el tema como hicimos en la sección de memoria distribuida y resiliente y crea un repositorio solo con las carpetas y archivos que lo personalizan.

Como es habitual, iremos documentando avances y dudas en colectivo, que permitirán completar los ejercicios.


Referencias extra:

Diccionarios de datos y plantillas

Retomemos en detalle el ejemplo con el que cerramos la sesión anterior, ejecutando el script justo antes de leer la plantilla e inyectar los datos en ella. Para ello usaremos una de de las características interesantes de Pharo y es que nos permite ejecutar trozos de código, en lugar de todo o nada, como en otros lenguajes. Haremos esto seleccionando con el ratón la líneas de código que queremos ejecutar, o manteniendo presionadas las teclas de selección con el teclado. Una vez hayamos seleccionado esas líneas presionamos el atajo de teclado Ctrl/Cmd + g y veremos el resultado de ese trozo de código ejecutado, como muestra la siguiente figura:

Fuentes de datos, consultas y transformaciones


||