Cómo hice ésta página

Para inaugurar la página me parece apropiado hablar justamente sobre cómo la he creado, más que nada por que lo acabo de hacer, no por nada en especial. Si te interesa saber cómo se pueden hacer páginas web con python, quédate por aquí que lo vamos a ver en seguida. Tampoco me voy a meter mucho en temas técnicos, lo justo para dar una vista general de las tecnologías involucradas y el papel que cumple cada una de ellas.

La página web como tal está hecha con Django. Para generar los artículos del blog y el tema de los proyectos utilizo R markdown, ya que una parte importante del contenido que voy a hacer necesita poder presentar código, resultados y gráficos interactivos.

La barra de navegación está implementada con bootstrap, y en el frontend poco más que comentar. Algo de css para poner las cosas bonitas y listo. Pero vamos por partes.

Django!!

Django unchained is not python django

No, no es ese Django

Django es un framework de python que sirve para crear páginas web. Cada vez que un usuario solicita una página se ejecuta una función de python encargada de generar la página web, y luego se la manda al cliente.

En la jerga del desarrollo web a ésto se le llama server side rendering, ya que la página se genera en el servidor cada vez que un usuario la pide. Ésto permite cambiar el contenido de la página en función del usuario que la visita, entre otras muchas cosas. Puedes ver un ejemplo rápido en ésta app que he hecho.

El framework facilita muchísimo el trabajo a la hora de hacer páginas web, ya que trae de serie muchas cosas útiles (gestión de usuarios, contraseñas, un panel de administración, envío de correos…).

Nginx

Nginx es un servidor web, es decir, el componente que atiende las peticiones de los usuarios, y se comunica con los diferentes componentes del backend para poder atenderlas y generar el contenido que los usuarios requieren. Aquí el vocabulario nos juega una mala pasada, ya que coloquialmente cuando decimos “servidor” nos referimos a muchas cosas.

Pero, ¿acaso Django no es capaz de atender las peticiones de los clientes? En teoría sí que puede, pero de forma limitada ya que solo puede atender una petición a la vez.

Para poder atender varias peticiones lo que hacemos es ejecutar varias copias de Django. Aquí es donde entra Nginx, ya que actúa como balanceador de carga, es decir, recibe todas las peticiones y las va distribuyendo de manera uniforme entre todas las copias.

Pero la cosa se complica… Django no puede hablar directamente con Nginx, por lo que se requiere otro componente que haga de intermediario. En mi caso escogí uwsgi, aunque también se puede utilizar guinicorn u otros. El esquema quedaría más o menos así:

Relationship between nginx, uwsgi and django

Nginx recibe las peticiones, y las distribuye entre varias copias o instancias de Django a través de uwsgi

R markdown

Para hacer páginas web se utiliza un lenguaje de marcado (que no de programación) que se llama html. Por ejemplo, para el título de ésta sección utilicé una etiqueta <h2>, que le indica al navegador que es… pues el título de una sección.

No obstante, escribir html es una tarea “interesante”, y para no tener que hacerlo se inventó markdown, que lo facilita bastante. Por ejemplo, para hacer ésta sección el markdown sería:

## R markdown

Para hacer páginas web se utiliza un lenguaje de marcado (que no de programación) que se llama html. Por ejemplo, para el título de ésta sección utilicé una etiqueta `<h2>`, que le indica al navegador que es... pues el título de una sección.

No obstante, escribir html a pelo es una tarea "interesante", y para no tener que hacerlo se inventó **markdown**, que lo facilita bastante. Por ejemplo, para hacer ésta sección el markdown sería:

Mientras que el html quedaría mas o menos así:

<h2>R markdown</h2>

<p>Para hacer páginas web se utiliza un lenguaje de marcado (que no de programación) que se llama html. Por ejemplo, para el título de ésta sección utilicé una etiqueta <code><h2></code>, que le indica al navegador que es... pues el título de una sección.</p>

<p>No obstante, escribir html a pelo es una tarea "interesante", y para no tener que hacerlo se inventó <strong>markdown</strong>, que lo facilita bastante. Por ejemplo, para hacer ésta sección el markdown sería:</p>

Vemos que en el html cada elemento viene definido por una etiqueta de apertura y otra de cierre, mientras que markdown es mucho más sencillo.

Aunque utilices markdown para hacer las páginas, al final los navegadores hablan html, así que se debe convertir al mismo. La ventaja, como hemos visto, es que es mucho más cómodo de escribir.

Pues R markdown es básicamente markdown, pero con el añadido de que permite definir fragmentos de código que se ejecutan cuando generas el documento, permitiendo mostrar gráficos o tablas. Veamos un ejemplo:

#Cargamos un conjunto de datos que viene con R
df <- mtcars

boxplot(mpg ~ cyl, data = df)

En el gráfico podemos ver cuantas millas se pueden recorrer por cada galón de combustible consumido en función del número de cilindros en algunos coches americanos (un valor más alto implica mayor eficiencia).

R markdown se creó para ayudar a comunicar los resultados de investigaciones científicas y para poder compartir el código y los resultados que genera. Dado que una parte importante del contenido que voy a hacer será sobre ciencia de datos era muy importante para mí poder generar los artículos con R markdown, pero ha sido una pesadilla. A lo mejor en el futuro comentaré el proceso con más detalle, pero por ahora simplemente hay que saber que no fue divertido.

¿Y que hay del frontend?

Suicidal filthy frank

Lo cierto es que el frontend no es mi especialidad, así que tampoco me he complicado mucho. Para los que anden despistados, el frontend es todo aquello con lo que interactúa el usuario, y el backend es aquello que el usuario no ve, pero que hace falta para generar el contenido que solicita.

En el caso de las páginas web el front es un documento html. En éste sitio, para generar el html utilizo el sistema de plantillas que trae Django. Gracias a las plantillas, puedes generar documentos html tomando otros como modelo.

Por ejemplo, la mayoría de las páginas aquí se crean a través de una plantilla genérica que incluye los estilos del sitio, así como la barra de navegación en la parte superior.

Además el sistema de plantillas permite crear plantillas… a través de otras plantillas. Es decir, plantillas que heredan características de otras plantillas. Por ejemplo, para los artículos del blog utilizo una plantilla que toma como base la plantilla genérica, añade unos cuantos estilos, y carga el contenido de cada artículo.

De ésta forma todos los artículos tendrán siempre el mismo formato. También se pueden incrustar otros documentos html en las plantillas, lo que se puede utilizar para añadir widgets o elementos que vayan a ser usados en varias plantillas.

Tal y como vimos antes, el html define como será la estructura de la página, pero para que las páginas se vean mejor se recurre al CSS. Por ejemplo, con html le digo al navegador que un componente es un título, o que está en negrita, pero para que la negrita se muestre con un color azul le tengo que aplicar CSS.

CSS funciona mediante reglas y selectores. Las reglas definen las características estéticas como tal (color, fuente, forma…), y los selectores agrupan un conjunto de reglas y deciden sobre que elementos html se van a aplicar. Por ejemplo:

p {
  color: red;
  font-family: "Arial";
}

Éste selector css aplica sobre los elementos <p>, que en el html hacen referencia a los párrafos del texto. Al aplicarlo, todo el texto de los mismos estaría en rojo y con fuente Arial. Hay que destacar que éste selector sólo afecta a los párrafos, no a los títulos. Para ello tendríamos que cambiarlo a:

p, h1, h2, h3, h4 {
  color: red;
  font-family: "Arial";
}

Las etiquetas <h1>, <h2>, <h3>, <h4> hacen referencia a los títulos. <h1> serían títulos principales, <h2> serían subtítulos, <h3> sub-subtítulos, etc…

Con html definimos la estructura de una página web, con el css el estilo.

Pues básicamente con éstas dos cosas se ha generado ésta página, y el sitio en general. La barra de navegación la he implementado con bootstrap, aunque tengo intención de quitar ésta librería y hacerla con html y css manualmente.

No hay javascript (más allá del que aporta bootstrap). Con Django se puede obtener suficiente interactividad como para que no haga mucha falta.

Quizás la parte más complicada ha sido integrar R markdown con Django, así que ahí va un pequeño rant.

Sirviendo R markdown a través de Django

Servir documentos de R markdown con Nginx es cosa fácil. Simplemente conviertes los ficheros de R markdown (.Rmd) a html, y le dices a Nginx que sirva el directorio. Añades un fichero index.html que contenga enlaces al resto de documentos y ya lo tienes. Se puede hacer con github pages y es lo que hacía antes para servir mi portfolio en github. También se puede usar el paquete blogdown que facilita mucho el proceso.

El problema es que yo quería mantener la barra de navegación en la parte superior de la pantalla, y para generarla necesito cargar templates de Django… Además, quiero que los artículos del blog cojan el mismo css que el resto de la página, para que siempre tengan el mismo estilo (fuentes, colores…).

A pesar de que el contenido del blog cambia relativamente poco, servirlo de forma dinámica con Django tiene algunas ventajas. Por ejemplo, podría añadir una sección al final del artículo con otras lecturas recomendadas en función de los gustos del usuario.

Servir el contenido generado por R markdown mediante Django es una tarea que puede parecer sencilla, pero es un caso de dos tecnologías que plantean dos maneras incompatibles de hacer las cosas.

Por un lado, R markdown quiere que todas las cosas (css, javascript, imágenes) estén en el mismo directorio o en directorios bajo el que contiene el html. Django en cambio quiere que literalmente todo esté en directorios diferentes. Las imágenes por aquí, el css por allá, el javascript por éste otro lado…

Otro de los problemas que he encontrado es que algunos de los elementos interactivos que se pueden incluir en R markdown, como las pestañas para incluir secciones o la tabla de contenidos flotante utilizan una versión arcaica de bootstrap. Como yo también utilizo bootstrap para darle estilo al sitio aquí se genera un conflicto ya que una misma página no puede cargar dos versiones diferentes de la biblioteca.

Éstas dos situaciones son un ejemplo de por qué no conviene andar añadiendo dependencias a un proyecto a no ser que sea absolutamente necesario, especialmente si hablamos de frameworks en vez de librerías. Al combinar diferentes tecnologías es frecuente encontrarte con conflictos de dependencias o con que cada uno de los componentes plantea su manera de hacer las cosas, generando grandes dolores de cabeza.

En mi caso no me queda otra, y he tenido que sufrir las consecuencias, aunque al final he llegado a una solución que funciona bastante bien.

Al encontrar un problema se debe intentar solucionarlo utilizando las herramientas que te dan las tecnologías que ya tienes incorporadas al proyecto, en vez de incorporar otra específica para resolverlo.

Ideas como “utiliza la herramienta adecuada para cada problema” y “no reinventes la rueda” tienen sentido de forma intuitiva, pero si se aplican de forma indiscriminada puedes acabar con un proyecto que no es más que un conjunto de librerías, frameworks y herramientas pegadas con celo. En éstos casos el tiempo que te ahorra cada una de las piezas acaba invertido en solucionar los conflictos que surgen entre ellas.