Phoenix es un framework de desarrollo web.

Introducción

Phoenix es un framework de desarrollo web escrito en Elixir, patrón MVC. Muchos de sus componentes y conceptos le resultará familiar a los que tenemos experiencia en otros framework como Ruby on Rails o Django. Phoenix ofrece lo mejor de ambos mundos - alta productividad en ambitos de desarrollo y un alto rendimiento de la aplicación.

Pero antes de seguir vamos a definir algunos conceptos:

¿ Qué es Erlang ?

Erlang es un lenguaje funcional y tiene una historia aún más larga con manejo de concurrencia. Erlang fue creado en Ericsson en la década de 1980 para permitir un mejor desarrollo de aplicaciones de telefonía. Acualmente WhatsApp tiene cientos de millones de usuarios. con más de diez mil conexiones simultáneas en una sola máquina, lo cual se ve como un gran reto , pero Whatsapp tener servidores individuales con más de 2 millones de conexiones simultáneas. 2 millones de conexiones en un solo servidor, manejados por Erlang.

Erlang también es popular para los servidores del juego. Millones de usuarios juegan con la infraestructura Erlang tález como Call of Duty y Juego de la Guerra.

¿Qué es Elixir?

Elixir creado por José Valim, comenta: “Me gustó todo lo que vi en Erlang, pero odiaba las cosas que no vi”. Elixir tiene su propio sistema de gestión de paquetes -> hex.pm.

Elixir es un lenguaje que se ejecuta en la máquina virtual de Erlang. Por lo que tiene todas las ventajas, probado en batalla y puede usar las bibliotecas existentes Erlang sin penalización en el rendimiento. Elixir y añade un montón de sutilezas. Uno de ellos es ```pipe operator``.

La diferencia entre Erlang y elixir no es sólo la sintaxis. Sin embargo, la sintaxis es importante, y especialmente para desarrolladores de Ruby la sintaxis Elixir será muy familiar.

Inmutabilidad y la programación funcional

Elixir es un lenguaje funcional con la inmutabilidad. La programación funcional es un paradigma de programación declarativa basado en el uso de funciones matemáticas, en contraste con la programación imperativa, que enfatiza los cambios de estado mediante la mutación de variables. La programación funcional tiene sus raíces en el cálculo lambda, un sistema formal desarrollado en los años 1930 para investigar la definición de función, la aplicación de las funciones y la recursión. Muchos lenguajes de programación funcionales pueden ser vistos como elaboraciones del cálculo lambda.

Me he dado cuenta de lo beneficioso que es. Incluso para la programación de un solo subproceso, mutabilidad trae una incertidumbre acerca de cómo va a ejecutar un programa. Y que no se pierda la mutabilidad en absoluto. La programación funcional y la inmutabilidad ayuda a aclarar las cosas y hace que sea más fácil de razonar sobre el código.

Concurrencia

Otro punto fuerte para Elixir es la simultaneidad. Concurrencia está aquí para quedarse, por varias razones. Para mencionar algunos: La tendencia en hardware es cada vez más núcleos de CPU. Los fabricantes de CPU no van a mejorar el rendimiento de un solo núcleo a la misma velocidad que antes. En su lugar, son la adición de más núcleos. También el mundo es concurrente y no desea que los usuarios finales u otros servicios de software que esperen innecesariamente una respuesta.

En la mayoría de los idiomas de concurrencia es un poco de dolor. No sólo es peligroso y difícil de hacer la sincronización. Con el estado mutable y bifurcación de procesos nativos también es a menudo lento y utiliza una gran cantidad de memoria.

Haciendo concurrencia en Erlang o Elixir otros idiomas es un poco como hacer ramas en Git contra la subversión . En la subversión era muy complicado de hacer - y nunca lo hice. En Git es mucho más fácil y lo hago todo el tiempo.

Bien mucho blabla y ahora un poco de acción ,para continuar vamos a necesitar instalar:

Ahora vamos a montar nuestro entorno de desarrollo para poder trabajar con este hermoso framework que mucho promete, lo primero sera instalar elixir:

Para instalar elixir en Mac OS X lo vamos hacer mediante Homebrew

Lo primero sera hacer un update a nuestro homebrew para tener la ultima version:

➜  ~ brew update

Para instalar elixir

➜  ~ brew install elixir

lo siguiente sera instalar erlang

➜  ~ brew install erlang

Comprobamos la versión de elixir

➜  ~ elixir -v
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Elixir 1.2.5

Gestor de paquetes Hex para poder levantar phoenix.

➜  ~ mix local.hex
Are you sure you want to install archive "http://s3.amazonaws.com/s3.hex.pm/installs/1.2.0/hex-0.11.5.ez"? [Yn] Y
* creating .mix/archives/hex-0.11.5.ez
➜  ~ mix archive.install https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez

Y vuala hasta acá ya tenemos todo listo para poder desarrollar, ahora vamos a crear nuestro primer proyecto: asi que ejecutamos ```mix phoenix.new hello_phoenix``

➜  ~ mix phoenix.new hello_phoenix
* creating hello_phoenix/config/config.exs
* creating hello_phoenix/config/dev.exs
* creating hello_phoenix/config/prod.exs
* creating hello_phoenix/config/prod.secret.exs
* creating hello_phoenix/config/test.exs
* creating hello_phoenix/lib/hello_phoenix.ex
* creating hello_phoenix/lib/hello_phoenix/endpoint.ex
* creating hello_phoenix/test/views/error_view_test.exs
* creating hello_phoenix/test/support/conn_case.ex
* creating hello_phoenix/test/support/channel_case.ex
* creating hello_phoenix/test/test_helper.exs
* creating hello_phoenix/web/channels/user_socket.ex
* creating hello_phoenix/web/router.ex
* creating hello_phoenix/web/views/error_view.ex
* creating hello_phoenix/web/web.ex
* creating hello_phoenix/mix.exs
* creating hello_phoenix/README.md
* creating hello_phoenix/web/gettext.ex
* creating hello_phoenix/priv/gettext/errors.pot
* creating hello_phoenix/priv/gettext/en/LC_MESSAGES/errors.po
* creating hello_phoenix/web/views/error_helpers.ex
* creating hello_phoenix/lib/hello_phoenix/repo.ex
* creating hello_phoenix/test/support/model_case.ex
* creating hello_phoenix/priv/repo/seeds.exs
* creating hello_phoenix/.gitignore
* creating hello_phoenix/brunch-config.js
* creating hello_phoenix/package.json
* creating hello_phoenix/web/static/css/app.css
* creating hello_phoenix/web/static/js/app.js
* creating hello_phoenix/web/static/js/socket.js
* creating hello_phoenix/web/static/assets/robots.txt
* creating hello_phoenix/web/static/assets/images/phoenix.png
* creating hello_phoenix/web/static/assets/favicon.ico
* creating hello_phoenix/test/controllers/page_controller_test.exs
* creating hello_phoenix/test/views/layout_view_test.exs
* creating hello_phoenix/test/views/page_view_test.exs
* creating hello_phoenix/web/controllers/page_controller.ex
* creating hello_phoenix/web/templates/layout/app.html.eex
* creating hello_phoenix/web/templates/page/index.html.eex
* creating hello_phoenix/web/views/layout_view.ex
* creating hello_phoenix/web/views/page_view.ex

Fetch and install dependencies? [Yn]

Fetch and install dependencies? [Yn] Y
* running mix deps.get
* running npm install && node node_modules/brunch/bin/brunch build

We are all set! Run your Phoenix application:

    $ cd hello_phoenix
    $ mix phoenix.server

You can also run your app inside IEx (Interactive Elixir) as:

    $ iex -S mix phoenix.server

Before moving on, configure your database in config/dev.exs and run:

    $ mix ecto.create
➜  mix local.rebar
* creating /Users/fbarrios/.mix/rebar
* creating /Users/fbarrios/.mix/rebar3

Up server

➜  mix phoenix.server

En caso de que de error y no cargen los CSS

Couldn't find preset "/Users/fbarrios/Documents/phoenix/hello_test/node_modules/babel-preset-es2015

Instalamos babel-preset-es2015

npm install --save-dev babel-preset-es2015

Estructura de nuestra aplicación:

├── 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

First Resourse

$ mix help | grep -i phoenix
$ mix phoenix.digest      # Digests and compress static files
$ mix phoenix.gen.channel # Generates a Phoenix channel
$ mix phoenix.gen.html    # Generates controller, model and views for an HTML based resource
$ mix phoenix.gen.json    # Generates a controller and model for a JSON based resource
$ mix phoenix.gen.model   # Generates an Ecto model
$ mix phoenix.gen.secret  # Generates a secret
$ mix phoenix.new         # Create a new Phoenix v1.1.2 application
$ mix phoenix.routes      # Prints all routes
$ mix phoenix.server      # Starts applications and their server

Ejemplo tipo scaffols en ruby on rails:

mix phoenix.gen.html Post posts title:string body:text
* creating web/controllers/post_controller.ex
* creating web/templates/post/edit.html.eex
* creating web/templates/post/form.html.eex
* creating web/templates/post/index.html.eex
* creating web/templates/post/new.html.eex
* creating web/templates/post/show.html.eex
* creating web/views/post_view.ex
* creating test/controllers/post_controller_test.exs
* creating priv/repo/migrations/20160516033253_create_post.exs
* creating web/models/post.ex
* creating test/models/post_test.exs

Add the resource to your browser scope in web/router.ex:

    resources "/posts", PostController

Remember to update your repository by running migrations:

    $ mix ecto.migrate

Ejecutamos

$ mix ecto.migrate
mix ecto.migrate

00:48:33.841 [info]  == Running HelloPhoenix.Repo.Migrations.CreatePost.change/0 forward

00:48:33.841 [info]  create table posts

00:48:34.216 [info]  == Migrated in 3.7s

Channel

mix phoenix.gen.channel Room rooms

El primer argumento es el nombre del módulo para el canal. El segundo argumento es el plural.

a channel in web/channels
a channel_test in test/channels

Routes.

El archivo de router que genera Phoenix, web/router.ex , tendrá un aspecto como éste:

defmodule HelloPhoenix.Router do
  use HelloPhoenix.Web, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", HelloPhoenix do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
  end

  # Other scopes may use custom stacks.
  # scope "/api", HelloPhoenix do
  #   pipe_through :api
  # end
end

HelloPhoenix corresponde al nombre de la aplicación, tanto para modelo, controlador o router.

HTTP get, post, y put. y no menos importante resources,

 mix phoenix.routes

Hemos recorrido un largo camino en esta guía sin hablar de una de las primeras líneas que vimos en el router

 pipe_through :browser
  pipeline :browser do
    plug :accepts, ["html"] Define el formato que sera aceptado.
    plug :fetch_session Va a buscar los datos de la sesión y lo pone a disposición de la conexión.
    plug :fetch_flash Que recupera los mensajes de flash que pueden haber sido establecidas
    plug :protect_from_forgery Seguridad pu master anti  Cross-Site Request Forgery (CSRF)
    plug :put_secure_browser_headers
  end

De esta manera cargamos :browser y utilizamos la basura

  scope "/", HelloPhoenix do
    pipe_through :browser # Use the default browser stack
    resources "/posts", PostController
    get "/", PageController, :index
  end

Pero qué es plug…

Plug permite la comunicacion entre diferentes maquinas Erlang.

Se puede pensar plug es un framgento de código que recibe una estructura de datos, hace algún tipo de transformación, y devuelve esta misma estructura de datos, ligeramente modificada. Esta estructura de datos que Plug recibe y vuelve por lo general se llama conexión, y representa todo lo que hay que saber acerca de una solicitud.

Como siempre plug reciben y devuelven una conexión, pueden ser fácilmente componibles, formando lo que se llama una Plug pipeline.

Tenemos dos tipos de plug:

Function plug es una función que recibe connection (%Plug.Conn{}) y un conjunto de opciones, y devuelve una connection. Aquí está un ejemplo sencillo de Plug:

def my_plug(conn, opts) do
  conn
end

Es cualquier módulo que implementa dos funciones: init/1 y call/2, como el siguiente ejemplo:

module MyPlug do
  def init(opts) do
    opts
  end

  def call(conn, opts) do
    conn
  end
end

Una característica interesante de module plug es que init / 1 se ejecuta en tiempo de compilación, mientras que la llamadacall / 2 ocurre en tiempo de ejecución.