Alguien voló sobre el nido del Phoenix

Phoenix es un Framework Web basado en Ruby On Rails, el padre de todos los Frameworks Web modernos. Está escrito en Elixir que es un lenguaje dinámico y funcional que corre sobre la Máquina virtual de Erlang.

BEAM o la Máquina Virtual de Erlang es una increíble pieza de ingeniería. Lleva entre nosotros 30 años y aunque para el público mainstream ha pasado desapercibido durante mucho tiempo, su robustez está más que contrastada. Sin ir más lejos, se estima que el 50% de los switches telefónicos mundiales corren sobre ella. Otro caso de éxito ha sido WhatsApp (artículoartículo), con un backend potenciado por BEAM.
También le debemos el cada vez más utilizado modelo de actores, sobre el que escribí un post no hace mucho tiempo. Algo que me resulta particularmente interesante, es que al contrario que JVM o .NET, la ErlangVM fue construida con Erlang en mente, un lenguaje funcional. Lo que implica que la librería estándar es funcional. En el caso de .NET si usamos F# terminamos arrastrando idiosincrasia del mundo de C#.

Elixir es un lenguaje de programación dinámico y funcional con una sintaxis claramente inspirada en Ruby. Como en el resto de lenguajes funcionales el concepto de objeto no existe. Los datos no mutan, se transforman. Elixir tiene un sistema de macros para extender el lenguaje, es interoperable con Erlang. Tiene un REPL, IEx. Y Mix como build tool. Incluso tiene un sistema de tipos gradual.

Si me sigues en twitter, sabrás que doy mucho las lata con los “typed-functional langs”. Desafortunadamente, aunque hay varios intentos, no hay ningún lenguaje production-ready en la BEAM con esta característica. Si te interesa estar al día con los lenguajes que corren sobre BEAM, este repo está genial.

Apoyándose sobre los hombros de BEAM, Phoenix facilita enormemente la construcción de Webs, APIs y Channels (canales de comunicación en tiempo real) sin inmiscuirse -demasiado- en nuestra aplicaciones. Dando como resultado aplicaciones relativamente mantenibles en el tiempo, o al menos más mantenibles de lo que nos ofrece un Framework Web promedio. Y es que, si nos quitamos Ecto de en medio, muchas veces da la sensación de estar usando una librería más. Esto es posible porque Phoenix está construido entorno al concepto de transparencia referencial que básicamente viene a decir que, para una misma entrada siempre habrá una misma salida o en otras palabras, tenemos garantía de que nuestras funciones no modifican el estado fuera de su ámbito. Con este nivel de aislamiento es muy simple testear o abrir un REPL y construir la aplicación por partes. Plug nace apoyándose en este concepto, y está en el corazón de Phoenix.

Plug

Según su propia documentación (). Plug es:

  1. Una especificación para componer módulos entre aplicaciones.
  2. Adaptadores para diferentes tipos de servidores en la máquina virtual de Erlang .

Un plug se puede ver como una función* con la siguiente firma:

    conn -> conn

Es decir, recibe como parámetro una conexión y retorna una conexión. La conexión en realidad es un diccionario. O sea, el plug recibe una conexión y retorna una transformación de dicha conexión. En Phoenix los plugs están en todas partes: controladores, router (que además es un pipeline de plugs), autenticación, logs… Hay muchísimas aplicaciones de terceros que siguen la especificación Plug, por lo que pueden ser consumidas desde Phoenix sin trabajo adicional.

*En realidad son dos funciones: init y call. Pero para el caso es lo mismo.

Hello World

Vamos a escribir el típico Hello World (en realidad iba a crear una app de notas, pero por extensión la voy a dejar para la siguiente entrada) Lo primero es hacer el setup de nuestro entorno.

Abrimos una terminal en la carpeta en la que queramos instalar el proyecto y ejecutamos:

mix phoenix.new hello_world

Mix nos preguntará si queremos descargar las dependencias. Obviamente diremos que sí, nos movemos al directorio hello_world y ejecutamos

mix ecto.create

El comando anterior creará la base datos

mix phoenix.server

Esto levantará un servidor, si vamos a http://localhost:4000 veremos nuestra flamante nueva app.

Si ahora editamos el fichero web/pages/index.html.eex con el texto “HelloWorld!” y salvamos. Al volver a la página, veremos como se actualiza automáticamente.

helloWorld

Click para ver (perdón por la calidad, el limite es 1MB)

La vista se acaba de recompilar (sí, phoenix soporta la compilación en caliente)  al salvar y gracias a que en el entorno de desarrollo por defecto hay un socket escuchando, los cambios en nuestros ficheros la página se actualiza automáticamente sin necesidad de herramientas externas.

Estructura 

La estructura de un proyecto Phoenix es la siguiente:

── config

── deps

── lib

── priv

── test

── web

── mix.exs

config: aquí irán los archivos de configuración del proyecto. Por defecto habrá un archivo de configuración por cada entorno: Dev, Prod y Test.

deps: todas las dependencias de nuestra aplicación ( que se encuentra en mix.exs) serán instaladas aquí.

lib: dentro de lib está el punto de entrada de nuestra aplicación.

priv: normalmente se utiliza para lo relacionado con los datos. Por ejemplo, los archivos de localización, las migraciones o el repositorio.

test: directorio de tests por defecto.

mix.exs: es el punto de entrada para Mix. Define entre otras cosas, las dependencias del proyecto.

web: es el lugar dónde estará nuestra aplicación. Y tienen la siguiente estructura:

── channels

── controllers

  └── page_controller.ex

── models

── static

── router.ex

── templates

  ── layout

    └── app.html.eex

  └── page

      └── index.html.eex

└── views

|   ── error_view.ex

|   ── layout_view.ex

|   └── page_view.ex

└── web.ex

channels: tendemos un archivo por cada channel. Recordamos que un channel es un punto de entrada en nuestro servidor que permite comunicación en tiempo real y *con estado* con un cliente.

controllers: como prácticamente en todos los frameworks MVC, la carpeta de los controladores.

models: se suele utilizar para definir el esquema de los datos y las funciones de transformación (behaviours). Recordemos que en Elixir no hay objetos y el patrón ActiveRecord se ha reemplazado por Repository.

static: assets

router.ex: archivo de definición de rutas

templates: Phoenix hace diferenciación entre Views y Templates. Templates es el equivalente a Razor, es decir, un DSL para generar HTML. Por convención, tendrá un directorio por cada controlador y un fichero para cada acción.

views: aquí irán las funciones de transformación necesarias para dejar nuestros datos listos para que la Template sea lo más “tonta” posible. Separarlo es conveniente porque muchas de las transformaciones pueden ser aplicadas no sólo a templates sino también a APIs o Channels.

web.ex: aquí podemos incluir las definiciones de nuestros modulos. Por defecto incluye para rutas, modelos, controladores, vistas y canales.

Conclusión

Phoenix tiene todas las papeletas para convertirse en el primer framework web funcional mainstream. Creo que las apps y webs de los próximos años consumirán canales y Phoenix los incorpora out of the box. Hay cosas que no me terminan de convencer como el acoplamiento de Ecto o que Elixir sea dinámico. Aún así creo que la ErlangVM va a dar mucho que hablar durante los próximos años.

4 Comentarios

  1. Un artículo genial! Esperando con ansias el siguiente! Por cierto me encanta el título 😀

  2. Disculpen, creo que hay un error en el artículo, Phoenix está basado en Elixir, no en Ruby on Rails.

    • jmgomez

      20 Septiembre, 2016 at 4:25 pm

      Hola simonbdz, nada que disculpar 🙂
      No, no es un error. La arquitectura de Phoenix está basada (inspirada) en RoR. Que no es lo mismo que el lenguaje en el que está escrito. Que como bien apuntas, es Elixir.

Deja un comentario

Tu dirección de correo electrónico no será publicada.

*