Translate

Mostrando las entradas con la etiqueta Elixir. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Elixir. Mostrar todas las entradas

lunes, 18 de noviembre de 2024

Elixir: Concurrencia Hecha Sencilla


Elixir, basado en la máquina virtual de Erlang (BEAM), utiliza el modelo de actores como su paradigma de concurrencia. Este modelo permite manejar múltiples procesos de manera eficiente y segura, lo que lo hace ideal para sistemas distribuidos y concurrentes.

El modelo de actores es un paradigma de concurrencia en el que las entidades llamadas actores:

  • Son unidades independientes de ejecución.
  • Tienen su propio estado y no comparten memoria con otros actores.
  • Se comunican mediante el envío de mensajes.

En Elixir, los procesos son implementaciones del modelo de actores y son extremadamente ligeros gracias a la eficiencia de la VM de Erlang.

En Elixir, los actores se implementan utilizando módulos como GenServer. Vamos a crear un ejemplo básico de un contador que incrementa su valor en respuesta a mensajes.

   defmodule Counter do

     use GenServer


     # Inicio del actor con un estado inicial

     def start_link(initial_value) do

       GenServer.start_link(__MODULE__, initial_value, name: __MODULE__)

     end


     # Callbacks

     def init(initial_value) do

       {:ok, initial_value}

     end


     # Manejar el mensaje para incrementar el contador

     def handle_call(:increment, _from, state) do

       {:reply, state + 1, state + 1}

     end


     def handle_call(:get, _from, state) do

       {:reply, state, state}

     end

   end


   # Iniciar el actor con un valor inicial de 0

   {:ok, _pid} = Counter.start_link(0)


   # Incrementar el contador

   Counter.call(:increment) # Devuelve 1

   Counter.call(:increment) # Devuelve 2


   # Obtener el valor actual

   Counter.call(:get) # Devuelve 2


Ahora crearemos múltiples actores que se comuniquen entre sí. Supongamos que tenemos un sistema donde un actor recopila datos y otro los procesa.


   defmodule DataCollector do

     use GenServer


     def start_link(processor_pid) do

       GenServer.start_link(__MODULE__, processor_pid, name: __MODULE__)

     end


     def init(processor_pid) do

       {:ok, processor_pid}

     end


     def handle_cast({:collect, data}, processor_pid) do

       send(processor_pid, {:process, data})

       {:noreply, processor_pid}

     end

   end

 

   defmodule DataProcessor do

     use GenServer


     def start_link(_) do

       GenServer.start_link(__MODULE__, [], name: __MODULE__)

     end


     def init(_) do

       {:ok, []}

     end


     def handle_info({:process, data}, state) do

       IO.puts("Procesando: #{data}")

       {:noreply, [data | state]}

     end

   end


   {:ok, processor_pid} = DataProcessor.start_link([])

   {:ok, collector_pid} = DataCollector.start_link(processor_pid)


   GenServer.cast(collector_pid, {:collect, "dato1"})

   GenServer.cast(collector_pid, {:collect, "dato2"})


DataCollector recopila datos y los envía a DataProcessor. DataProcessor procesa los datos recibidos y los guarda en su estado.


Como ventaja del modelo de actores tenemos:

Aislamiento Total: Los actores no comparten memoria, eliminando condiciones de carrera.

Escalabilidad: Los procesos son livianos y se ejecutan de manera concurrente.

Resiliencia: Si un actor falla, el sistema no se detiene; los supervisores pueden reiniciarlo.


El modelo de actores de Elixir proporciona una forma poderosa, segura y eficiente de manejar concurrencia. Al entender cómo implementar actores y supervisarlos, puedes construir sistemas robustos que escalen sin problemas.

miércoles, 6 de noviembre de 2024

Supervisores y Árboles de Supervisión en Elixir


La concurrencia es uno de los puntos fuertes de Elixir, y el modelo de supervisión es fundamental para construir aplicaciones resilientes. 

El modelo de concurrencia en Elixir está basado en procesos ligeros y aislados que se comunican entre sí enviándose mensajes, siguiendo el paradigma del modelo de actor. Estos procesos no comparten memoria, lo que reduce los riesgos de condiciones de carrera y hace que el sistema sea más seguro.

Supervisores son procesos especiales en Elixir que gestionan y supervisan otros procesos, reiniciándolos si fallan. Esto asegura que la aplicación siga funcionando incluso cuando ocurren errores.

Elixir provee módulos como Supervisor y Task.Supervisor para gestionar procesos de manera eficiente. Vamos a crear un simple supervisor que inicie y supervise un proceso Worker.


Primero, definimos el proceso Worker usando GenServer:


defmodule Worker do

  use GenServer


  def start_link(initial_state) do

    GenServer.start_link(__MODULE__, initial_state, name: __MODULE__)

  end


  def init(state), do: {:ok, state}


  def handle_cast(:do_work, state) do

    # Simulamos un trabajo que puede fallar

    if :rand.uniform() > 0.5 do

      {:stop, :error, state}

    else

      IO.puts("Trabajo completado exitosamente")

      {:noreply, state}

    end

  end

end


Ahora, creamos un supervisor que inicie y supervise nuestro proceso Worker:


defmodule MySupervisor do

  use Supervisor


  def start_link(_opts) do

    Supervisor.start_link(__MODULE__, :ok, name: __MODULE__)

  end


  def init(:ok) do

    children = [

      {Worker, :some_initial_state}

    ]


    Supervisor.init(children, strategy: :one_for_one)

  end

end


Elixir ofrece varias estrategias de supervisión que permiten diferentes enfoques de recuperación en caso de fallo:


  • :one_for_one: Solo reinicia el proceso que falló.
  • :one_for_all: Reinicia todos los procesos supervisados si uno falla.
  • :rest_for_one: Reinicia el proceso que falló y todos los procesos que fueron iniciados después de este.
  • :simple_one_for_one: Útil para supervisar un número dinámico de procesos que comparten el mismo tipo de inicialización.


En el ejemplo anterior, usamos :one_for_one, que reiniciará únicamente el proceso Worker si falla.

Los árboles de supervisión permiten organizar supervisores en una jerarquía. Esto es ideal para sistemas complejos que necesitan distintos niveles de supervisión.

Por ejemplo, podríamos tener un supervisor principal que supervise varios supervisores secundarios, cada uno a cargo de procesos específicos. Aquí hay una estructura básica:


defmodule MainSupervisor do

  use Supervisor


  def start_link(_opts) do

    Supervisor.start_link(__MODULE__, :ok, name: __MODULE__)

  end


  def init(:ok) do

    children = [

      MySupervisor, # Supervisor de workers

      AnotherSupervisor # Otro supervisor

    ]


    Supervisor.init(children, strategy: :one_for_all)

  end

end


En esta configuración:

  • MainSupervisor es el supervisor principal.
  • MySupervisor y AnotherSupervisor son supervisores secundarios.
  • Si cualquiera de los supervisores secundarios falla, MainSupervisor los reiniciará junto con sus respectivos procesos.


Los supervisores y árboles de supervisión en Elixir son una herramienta poderosa para construir sistemas concurrentes y resilientes. Siguiendo estos patrones, puedes crear aplicaciones que se recuperen automáticamente de fallos sin necesidad de intervención manual. Esto convierte a Elixir en una excelente opción para aplicaciones que requieren alta disponibilidad.

domingo, 3 de noviembre de 2024

Monadex en Elixir


Elixir, aunque no tiene una implementación nativa de mónadas como Haskell, permite patrones funcionales que se pueden potenciar con bibliotecas como Monadex. Monadex nos brinda las clásicas Maybe y Either, permitiéndonos manejar valores opcionales y errores de forma compositiva, y aprovechando el poder de la programación funcional.

Primero, agrega Monadex a tu archivo mix.exs:

defp deps do

  [

    {:monadex, "~> 1.1"}

  ]

end


Ejecuta mix deps.get para instalar la dependencia.


La mónada Maybe es útil cuando deseas trabajar con valores que podrían ser nil. Monadex provee funciones para encapsular operaciones en un flujo que se detiene automáticamente si algún valor es nil.

Supongamos que estamos buscando datos de un usuario y aplicando transformaciones a su información.


alias Monadex.Maybe


def get_user_info(user) do

  Maybe.return(user)

  |> Maybe.and_then(&get_name/1)

  |> Maybe.and_then(&upcase_name/1)

end


defp get_name(%{name: name}), do: Maybe.return(name)

defp get_name(_), do: Maybe.nothing()


defp upcase_name(name), do: Maybe.return(String.upcase(name))


user = %{name: "Juan"}

get_user_info(user) # Retorna: {:ok, "JUAN"}


Either es útil para operaciones que pueden tener éxito o devolver un error. Similar a Maybe, Either permite encadenar operaciones pero distingue entre :ok y :error.


Procesemos datos que pueden fallar en algún paso.


alias Monadex.Either


def process_data(data) do

  Either.return(data)

  |> Either.and_then(&validate/1)

  |> Either.and_then(&transform/1)

end


defp validate(data) do

  if valid?(data), do: Either.ok(data), else: Either.error("Invalid data")

end


defp transform(data), do: Either.ok("Processed: #{data}")


process_data("valid_data")  # Retorna: {:ok, "Processed: valid_data"}

process_data("invalid")      # Retorna: {:error, "Invalid data"}


Monadex facilita el manejo de errores y valores opcionales en Elixir, siguiendo patrones funcionales.

Dejo link: https://github.com/rob-brown/MonadEx


lunes, 28 de octubre de 2024

Quicksort en Elixir


Un Algoritmo que me gusta mucho es el quicksort, porque es un algoritmo por demás claro. Ya he escrito lo fácil que es implementarlo en scalaerlangrusthaskell y lisp.

Ahora le toca a Elixir. Básicamente el algoritmo toma un pivot y agrupa los menores del pivot al principio y los mayores al final y aplica quicksort a estos 2 grupos. Y si la lista es vacia o tiene un elemento, ya esta ordenada. 

Vamos al código: 


defmodule QuickSort do

  def sort([]), do: []

  def sort([pivot | tail]) do

    lower = Enum.filter(tail, &(&1 <= pivot))

    higher = Enum.filter(tail, &(&1 > pivot))


    sort(lower) ++ [pivot] ++ sort(higher)

  end

end


jueves, 4 de mayo de 2023

Primeros pasos con Phoenix parte 9

 


Seguimos la idea del post anterior: Phoenix adopta el diseño de enchufe o plugs para funcionalidad componible. 

Por ejemplo los Endpoints estan organizados por plugs: 

defmodule HelloWeb.Endpoint do

  ...


  plug :introspect

  plug HelloWeb.Router


Los conectores Endpoint predeterminados hacen bastante trabajo. Aquí están en orden:

Plug.Static: sirve activos estáticos. Dado que este complemento viene antes que el registrador, las solicitudes de activos estáticos no se registran.

Phoenix.LiveDashboard.RequestLogger: configura el registrador de solicitudes para Phoenix LiveDashboard, esto le permitirá tener la opción de pasar un parámetro de consulta para transmitir registros de solicitudes o habilitar/deshabilitar una cookie que transmite registros de solicitudes desde su tablero.

Plug.RequestId: genera un ID de solicitud único para cada solicitud.

Plug.Telemetry: agrega puntos de instrumentación para que Phoenix pueda registrar la ruta de la solicitud, el código de estado y la hora de la solicitud de forma predeterminada.

Plug.Parsers: analiza el cuerpo de la solicitud cuando hay disponible un analizador conocido. De forma predeterminada, este complemento puede manejar contenido codificado en URL, de varias partes y JSON (con Jason). El cuerpo de la solicitud se deja intacto si el tipo de contenido de la solicitud no se puede analizar.

Plug.MethodOverride: convierte el método de solicitud en PUT, PATCH o DELETE para solicitudes POST con un parámetro _method válido.

Plug.Head: convierte las solicitudes HEAD en solicitudes GET y elimina el cuerpo de la respuesta

Plug.Session: un complemento que configura la gestión de sesiones. Tenga en cuenta que fetch_session/2 aún debe llamarse explícitamente antes de usar la sesión, ya que este complemento solo configura cómo se obtiene la sesión.

En el medio del endpoint, también hay un bloque condicional:


  if code_reloading? do

    socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket

    plug Phoenix.LiveReloader

    plug Phoenix.CodeReloader

    plug Phoenix.Ecto.CheckRepoStatus, otp_app: :hello

  end


Este bloque solo se ejecuta en desarrollo. Permite:

  • recarga en vivo: si cambia un archivo CSS, se actualizan en el navegador sin actualizar la página;
  • recarga de código, para que podamos ver los cambios en nuestra aplicación sin reiniciar el servidor;
  • verificar el estado del repositorio, lo que garantiza que nuestra base de datos esté actualizada y, de lo contrario, genera un error legible y procesable.


En el enrutador, podemos declarar enchufes dentro de tuberías:


defmodule HelloWeb.Router do

  use HelloWeb, :router

  pipeline :browser do

    plug :accepts, ["html"]

    plug :fetch_session

    plug :fetch_live_flash

    plug :put_root_layout, {HelloWeb.LayoutView, :root}

    plug :protect_from_forgery

    plug :put_secure_browser_headers

    plug HelloWeb.Plugs.Locale, "en"

  end

  scope "/", HelloWeb do

   pipe_through :browser

    get "/", PageController, :index

  end


Las rutas se definen dentro de los ámbitos y los ámbitos pueden canalizarse a través de múltiples canalizaciones. Una vez que una ruta coincide, Phoenix invoca todos los complementos definidos en todas las tuberías asociadas a esa ruta. Por ejemplo, acceder a "/" se canalizará a través de la canalización del navegador, invocando en consecuencia todos sus conectores.

Como veremos en la guía de enrutamiento, las tuberías en sí mismas son tapones. Allí, también discutiremos todos los complementos en la tubería :browser.

Finalmente, los controladores también son enchufes, por lo que podemos hacer:


defmodule HelloWeb.PageController do

  use HelloWeb, :controller

  plug HelloWeb.Plugs.Locale, "en"


En particular, los complementos del controlador brindan una función que nos permite ejecutar complementos solo dentro de ciertas acciones. Por ejemplo, puedes hacer:

defmodule HelloWeb.PageController do

  use HelloWeb, :controller

 plug HelloWeb.Plugs.Locale, "en" when action in [:index]


Y el complemento solo se ejecutará para la acción de índice.

Al cumplir con el contrato de conexión, convertimos una solicitud de aplicación en una serie de transformaciones explícitas. No se detiene ahí. Para ver realmente qué tan efectivo es el diseño de Plug, imaginemos un escenario en el que necesitamos verificar una serie de condiciones y luego redirigir o detenernos si una condición falla. Sin enchufe, terminaríamos con algo como esto:



defmodule HelloWeb.MessageController do

  use HelloWeb, :controller

  def show(conn, params) do

    case Authenticator.find_user(conn) do

      {:ok, user} ->

        case find_message(params["id"]) do

          nil ->

            conn |> put_flash(:info, "That message wasn't found") |> redirect(to: ~p"/")

          message ->

            if Authorizer.can_access?(user, message) do

              render(conn, :show, page: message)

            else

              conn |> put_flash(:info, "You can't access that page") |> redirect(to: ~p"/")

            end

        end

      :error ->

        conn |> put_flash(:info, "You must be logged in") |> redirect(to: ~p"/")


    end

  end

end


¿Observa cómo unos pocos pasos de autenticación y autorización requieren anidamiento y duplicación complicados? Mejoremos esto con un par de enchufes.


defmodule HelloWeb.MessageController do

  use HelloWeb, :controller

  plug :authenticate

  plug :fetch_message

  plug :authorize_message

  def show(conn, params) do

    render(conn, :show, page: conn.assigns[:message])

  end


  defp authenticate(conn, _) do

   case Authenticator.find_user(conn) do

      {:ok, user} ->

        assign(conn, :user, user)

      :error ->

        conn |> put_flash(:info, "You must be logged in") |> redirect(to: ~p"/") |> halt()

    end

  end

  defp fetch_message(conn, _) do

    case find_message(conn.params["id"]) do

      nil ->

        conn |> put_flash(:info, "That message wasn't found") |> redirect(to: ~p"/") |> halt()

      message ->

        assign(conn, :message, message)

    end

  end


  defp authorize_message(conn, _) do

    if Authorizer.can_access?(conn.assigns[:user], conn.assigns[:message]) do

      conn

    else

      conn |> put_flash(:info, "You can't access that page") |> redirect(to: ~p"/") |> halt()

    end

  end

end


Para que todo esto funcione, convertimos los bloques de código anidados y usamos halt(conn) cada vez que llegamos a una ruta de error. La funcionalidad halt(conn) es esencial aquí: le dice a Plug que no se debe invocar el siguiente plug.

Al final del día, al reemplazar los bloques de código anidados con una serie aplanada de transformaciones de complemento, podemos lograr la misma funcionalidad de una manera mucho más componible, clara y reutilizable.


lunes, 24 de abril de 2023

Primeros pasos con Phoenix parte 8


Plug vive en el corazón de la capa HTTP de Phoenix. Interactuamos con los enchufes o Plug en cada paso del ciclo de vida de una request, y los componentes principales de Phoenix, como end points, enrutadores y controladores, son solo enchufes internamente. 

Plug es una especificación para módulos componibles entre aplicaciones web. También es una capa de abstracción para adaptadores de conexión de diferentes servidores web. La idea básica de Plug es unificar el concepto de "conexión" sobre la que operamos. Esto difiere de otras capas de middleware HTTP como Rack, donde la solicitud y la respuesta están separadas en la pila de middleware.

En el nivel más simple, la especificación Plug viene en dos formas: complementos de funciones y complementos de módulos.

Para actuar como un enchufe, una función necesita: aceptar una estructura de conexión (%Plug.Conn{}) como primer argumento y opciones de conexión como segundo;

Cualquier función que cumpla con estos dos criterios servirá. Por ejemplo:


def introspect(conn, _opts) do

  IO.puts """

  Verb: #{inspect(conn.method)}

  Host: #{inspect(conn.host)}

  Headers: #{inspect(conn.req_headers)}

  """


  conn

end


Esta función hace lo siguiente:

  1. Recibe una conexión y opciones (que no usamos)
  2. Imprime alguna información de conexión en el terminal.
  3. Devuelve la conexión

Veamos esta función en acción agregándola a nuestro end point en lib/hello_web/endpoint.ex. Podemos conectarlo en cualquier lugar, así que hagámoslo insertando plug :introspect justo antes de delegar la solicitud al enrutador:

defmodule HelloWeb.Endpoint do

  ...


  plug :introspect

  plug HelloWeb.Router


  def introspect(conn, _opts) do

    IO.puts """

    Verb: #{inspect(conn.method)}

    Host: #{inspect(conn.host)}

    Headers: #{inspect(conn.req_headers)}

    """


    conn

  end

end


Los complementos de función se conectan pasando el nombre de la función como un átomo. Para probar esto, vamos al navegador y buscamos http://localhost:4000. Debería ver algo como esto impreso en su terminal de shell:


Verb: "GET"

Host: "localhost"

Headers: [...]


Nuestro enchufe simplemente imprime información de la conexión. Aunque nuestro complemento inicial es muy simple, puede hacer prácticamente cualquier cosa que desee dentro de él. 

Ahora veamos la otra variante de enchufe, los enchufes de módulo.

Los conectores de módulo son otro tipo de conector que nos permite definir una transformación de conexión en un módulo. El módulo solo necesita implementar dos funciones:

  • init/1 que inicializa cualquier argumento u opción que se pase a call/2
  • call/2 que realiza la transformación de la conexión. call/2 es solo un complemento de función como vimos anteriormente

Para ver esto en acción, escribamos un complemento de módulo que coloque la clave y el valor :locale en la conexión para uso posterior en otros complementos, acciones de controlador y nuestras vistas. Coloquemos el contenido a continuación en un archivo llamado lib/hello_web/plugs/locale.ex:


defmodule HelloWeb.Plugs.Locale do

  import Plug.Conn


  @locales ["en", "fr", "de"]


  def init(default), do: default


  def call(%Plug.Conn{params: %{"locale" => loc}} = conn, _default) when loc in @locales do

    assign(conn, :locale, loc)

  end


  def call(conn, default) do

    assign(conn, :locale, default)

  end

end


Para probarlo, agreguemos este complemento de módulo a nuestro enrutador, agregando el complemento HelloWeb.Plugs.Locale, "en" a nuestra tubería de navegación en lib/hello_web/router.ex:


defmodule HelloWeb.Router do

  use HelloWeb, :router


  pipeline :browser do

    plug :accepts, ["html"]

    plug :fetch_session

    plug :fetch_flash

    plug :protect_from_forgery

    plug :put_secure_browser_headers

    plug HelloWeb.Plugs.Locale, "en"

  end

  ...


En la devolución de llamada init/1, pasamos una configuración regional predeterminada para usar si no hay ninguna presente en los parámetros. También utilizamos la coincidencia de patrones para definir varios encabezados de función call/2 para validar la configuración regional en los parámetros, y recurrimos a "en" si no hay ninguna coincidencia. assign/3  es parte del módulo Plug.Conn y es cómo almacenamos valores en la estructura de datos de conn.

Para ver la asignación en acción, vayamos a la plantilla en lib/hello_web/components/layouts/home.html.heex y agreguamos el siguiente código después del cierre de la etiqueta </h1>:


<p>Locale: <%= @locale %></p>


Si vamos a http://localhost:4000/ y debería ver la configuración regional exhibida. Y si vamos a http://localhost:4000/?locale=fr y debería ver la asignación cambiada a "fr". Alguien puede usar esta información junto con Gettext para proporcionar una aplicación web totalmente internacionalizada.

Eso es todo lo que hay que hacer con Plug. Phoenix adopta el diseño de enchufe de las transformaciones componibles en toda la pila. 



jueves, 6 de abril de 2023

Primeros pasos con Phoenix parte 7

 


Agreguemos un poco de complejidad a nuestra aplicación. Vamos a agregar una nueva página que reconocerá una parte de la URL, la etiquetará como "mensajero" y la pasará a través del controlador a la plantilla para que nuestro mensajero pueda saludar.

Como hicimos la última vez, lo primero que haremos será crear una nueva ruta.

Vamos a reutilizar HelloController creado en el post anterior y agregaremos una nueva acción de mostrar. Agregaremos una línea justo debajo de nuestra última ruta, así:


scope "/", HelloWeb do

  pipe_through :browser

  get "/", PageController, :home

  get "/hello", HelloController, :index

  get "/hello/:messenger", HelloController, :show

end


Usamos la sintaxis :messenger en la ruta. Phoenix tomará cualquier valor que aparezca en esa posición en la URL y lo convertirá en un parámetro. Por ejemplo, si apuntamos el navegador a: http://localhost:4000/hello/Frank, el valor de "messenger" será "Frank".

Las solicitudes a nuestra nueva ruta serán manejadas por la acción show HelloWeb.HelloController. Ya tenemos el controlador en lib/hello_web/controllers/hello_controller.ex, así que todo lo que tenemos que hacer es editar ese controlador y agregarle una acción show. Esta vez, necesitaremos extraer el messenger de los parámetros para que podamos pasarlo a la plantilla. Para hacer eso, agregamos esta función show al controlador:

def show(conn, %{"messenger" => messenger}) do

  render(conn, :show, messenger: messenger)

end


Dentro del cuerpo de la acción show, también pasamos un tercer argumento a la función render, un par clave-valor donde :messenger es la clave, y la variable messenger se pasa como el valor.

Si el cuerpo de la acción necesita acceso al mapa completo de parámetros enlazados a la variable params, además de la variable messenger enlazada, podríamos definir show/2 así:


def show(conn, %{"messenger" => messenger} = params) do

  ...

end


Es bueno recordar que las claves del mapa de parámetros siempre serán cadenas, y que el signo igual no representa una asignación, sino una afirmación de coincidencia de patrón.

Ahora necesitaremos una nueva plantilla. Dado que es para la acción de mostrar de HelloController, irá al directorio lib/hello_web/controllers/hello_html y se llamará show.html.heex. Se parecerá sorprendentemente a nuestra plantilla index.html.heex, excepto que necesitaremos mostrar el nombre de nuestro mensajero.

Para hacer eso, usaremos las etiquetas HEEx especiales para ejecutar expresiones Elixir: <%= %>. Observe que la etiqueta inicial tiene un signo igual como este: <%= . Eso significa que se ejecutará cualquier código de Elixir que se encuentre entre esas etiquetas, y el valor resultante reemplazará la etiqueta en la salida HTML. Si faltara el signo igual, el código aún se ejecutaría, pero el valor no aparecería en la página.

Nuestras plantillas están escritas en HEEx (HTML+EEx). HEEx es un superconjunto de EEx, por lo que comparte la sintaxis <%= %>.


Y así es como debería verse la plantilla:


<section>

  <h2>Hello World, from <%= @messenger %>!</h2>

</section>


Nuestro messenger aparece como @messenger.

Los valores que pasamos a la vista desde el controlador se denominan colectivamente nuestras "asignaciones". Podríamos acceder a nuestro valor de mensajería a través de asignaciones.messenger pero a través de alguna metaprogramación, Phoenix nos brinda la sintaxis @ mucho más limpia para usar en plantillas.

Si vamos a http://localhost:4000/hello/emanuel, debería ver una página similar a esta:

Hello World, from emanuel!

lunes, 3 de abril de 2023

Primeros pasos con Phoenix parte 6


Hay un par de cosas interesantes para notar sobre el post anterior. No necesitábamos detener y reiniciar el servidor mientras realizábamos los cambios. ¡Sí, Phoenix tiene recarga de código caliente! Además, aunque nuestro archivo index.html.heex consta de una sola etiqueta de sección, la página que obtenemos es un documento HTML completo. La plantilla index en realidad se representa una pagina compuesta por el diseño globlal de lib/hello_web/components/layouts/root.html.heex y lib/hello_web/components/layouts/app.html.heex. Si abrimos este archivo, verá una línea que se ve así en la parte inferior:

<%= @inner_content %>

Que es donde se inyecta el html particular. 

Plug es una biblioteca y una especificación para unir aplicaciones web. Es una parte esencial de cómo Phoenix maneja las solicitudes. Cada conector define una parte del procesamiento de solicitudes. En el endpoint encontrarás un esqueleto más o menos así:


defmodule HelloWeb.Endpoint do

  use Phoenix.Endpoint, otp_app: :hello


  plug Plug.Static, ...

  plug Plug.RequestId

  plug Plug.Telemetry, ...

  plug Plug.Parsers, ...

  plug Plug.MethodOverride

  plug Plug.Head

  plug Plug.Session, ...

  plug HelloWeb.Router

end


Cada uno de estos plug tiene una responsabilidad específica. El último complemento es precisamente el módulo HelloWeb.Router. Esto permite que el endpoint delegue todo el procesamiento de solicitudes adicional al enrutador. Como sabemos ahora, su responsabilidad principal es mapear pares de verbo/ruta a controladores. Luego, el controlador le dice a una vista que represente una plantilla.

En este momento, puede estar pensando que pueden ser muchos pasos para simplemente renderizar una página. Sin embargo, a medida que nuestra aplicación crezca en complejidad, veremos que cada capa tiene un propósito distinto:

Endpoint (Phoenix.Endpoint): contiene la ruta común e inicial por la que pasan todas las solicitudes. Si desea que suceda algo en todas las solicitudes, se dirige al punto final.

Router (Phoenix.Router): es responsable de enviar verbos/ruta a los controladores. El enrutador también nos permite medir la funcionalidad. Por ejemplo, algunas páginas de su aplicación pueden requerir la autenticación del usuario, otras no.

Controlador (Phoenix.Controller): el trabajo del controlador es recuperar la información solicitada, hablar con su dominio comercial y preparar datos para la capa de presentación.

Vista: la vista maneja los datos estructurados del controlador y los convierte en una presentación para mostrar a los usuarios. Las vistas a menudo reciben el nombre del formato de contenido que representan.

Hagamos un resumen rápido y cómo los últimos tres componentes funcionan juntos agregando otra página.


jueves, 30 de marzo de 2023

Primeros pasos con Phoenix parte 5


Cuando su navegador accede a http://localhost:4000/, envía una solicitud HTTP a cualquier servicio que se esté ejecutando en esa dirección, en este caso, nuestra aplicación Phoenix. La solicitud HTTP se compone de un verbo y una ruta. Por ejemplo, las siguientes solicitudes del navegador se traducen en:

BROWSER ADDRESS             VERBO PATH

http://localhost:4000/                 GET /

http://localhost:4000/hello         GET /hello

http://localhost:4000/hello/world GET /hello/world


Hay otros verbos HTTP. Por ejemplo, enviar un formulario generalmente usa el verbo POST.

Las aplicaciones web generalmente manejan las solicitudes asignando cada par de verbo/ruta a una parte específica de su código y esto lo hace el router. Por ejemplo, podemos asignar "/artículos" a una parte de nuestra aplicación que muestra todos los artículos. Por lo tanto, para agregar esto, nuestra primera tarea es agregar una nueva ruta.

El router asigna pares únicos de verbo/ruta HTTP a pares de controlador/acción que los manejarán. Los controladores en Phoenix son simplemente módulos Elixir. Las acciones son funciones que se definen dentro de estos controladores.

Phoenix genera un archivo de router para nosotros en lib/hello_web/router.ex. 

La ruta de nuestro "¡Bienvenido a Phoenix!"  tiene este aspecto.


    get "/", PageController, :home


Si ponemos  en el browser http://localhost:4000/ estamos llamando a / con el metodo GET por lo tanto será manejada por la función home en el módulo HelloWeb.PageController definido en lib/hello_web/controllers/page_controller.ex.

La página que vamos a construir dirá "¡Hola mundo, desde Phoenix!" cuando apuntamos nuestro navegador a http://localhost:4000/hello.

Lo primero que debemos hacer es crear la ruta de la página para una nueva página. Abramos lib/hello_web/router.ex en un editor de texto. 

Agreguemos una nueva ruta al enrutador que asigna una solicitud GET para /hello a la acción de índice de un HelloWeb.HelloController que se creará próximamente dentro del bloque do scope "/" del enrutador:


scope "/", HelloWeb do
  pipe_through :browser

  get "/", PageController, :home
  get "/hello", HelloController, :index
end


Los controladores son módulos de Elixir y las acciones son funciones de Elixir definidas en ellos. El propósito de las acciones es recopilar los datos y realizar las tareas necesarias para la representación. Nuestra ruta especifica que necesitamos un módulo HelloWeb.HelloController con una función index/2.

Para hacer que suceda la acción de índice, creemos un nuevo archivo lib/hello_web/controllers/hello_controller.ex y hagamos que tenga el siguiente aspecto:

defmodule HelloWorldWeb.HelloController do
  use HelloWorldWeb, :controller

  def index(conn, _params) do
    render(conn, :index)
  end
end


Todas las acciones del controlador toman dos argumentos. El primero es conn, una estructura que contiene una gran cantidad de datos sobre la solicitud. El segundo es params, que son los parámetros de solicitud. .

El núcleo de esta acción es render(conn, :index). Le dice a Phoenix que renderice la plantilla de índice. Los módulos responsables de renderizar se denominan vistas. De forma predeterminada, las vistas de Phoenix llevan el nombre del controlador (HelloController) y el formato (HTML en este caso), por lo que Phoenix espera que exista un HelloWeb.HelloHTML y defina una función index/1.

Las vistas de Phoenix actúan como capa de presentación. Por ejemplo, esperamos que el resultado del índice de representación sea una página HTML completa. Para hacernos la vida más fácil, a menudo usamos plantillas para crear esas páginas HTML.

Vamos a crear una nueva vista. Cree lib/hello_web/controllers/hello_html.ex y haga que se vea así:

defmodule HelloWorldWeb.HelloHTML do
  use HelloWorldWeb, :html
end

Para agregar plantillas a esta vista, podemos definirlas como componentes de función en el módulo o en archivos separados.

Comencemos definiendo un componente de función:

defmodule HelloWorldWeb.HelloHTML do
  use HelloWorldWeb, :html

  def index(assigns) do
    ~H"""
    Hello!
    """
  end
end

Definimos una función que recibe asignaciones como argumentos y usamos el sigilo ~H para poner los contenidos que queremos representar. Dentro del sigilo ~H, usamos un lenguaje de plantillas llamado HEEx, que significa "HTML+EEx". EEx es una biblioteca para incrustar Elixir que se distribuye como parte del propio Elixir. "HTML+EEx" es una extensión Phoenix de EEx compatible con HTML, con soporte para validación HTML. Este último lo protege de vulnerabilidades de seguridad como Cross-Site-Scripting sin trabajo adicional de su parte.

Un archivo de plantilla funciona de la misma manera. Los componentes de función son excelentes para plantillas más pequeñas y los archivos separados son una buena opción cuando tiene mucho marcado o sus funciones comienzan a parecer inmanejables.

Probémoslo definiendo una plantilla en su propio archivo. Primero elimine nuestra función def index(assigns) de arriba y reemplácela con una declaración embed_templates:

defmodule HelloWorldWeb.HelloHTML do
  use HelloWorldWeb, :html

  embed_templates "hello_html/*"
end


Aquí le estamos diciendo a Phoenix.Component que incruste todas las plantillas .heex que se encuentran en el directorio hermano hello_html en nuestro módulo como definiciones de funciones.

A continuación, debemos agregar archivos al directorio lib/hello_web/controllers/hello_html.

Tenga en cuenta que el nombre del controlador (HelloController), el nombre de la vista (HelloHTML) y el directorio de la plantilla (hello_html) siguen la misma convención de nomenclatura y se nombran uno tras otro. También se colocan juntos en el árbol de directorios:


lib/hello_web
├── controllers
│   ├── hello_controller.ex
│   ├── hello_html.ex
│   ├── hello_html
 |         ├── index.html.heex

Un archivo de plantilla tiene la siguiente estructura: NOMBRE.FORMATO.TEMPLATING_LANGUAGE. En nuestro caso, creemos un archivo index.html.heex en lib/hello_web/controllers/hello_html/index.html.heex:

<section>
  <h2>Hello World, from Phoenix!</h2>
</section>

Los archivos de plantilla se compilan en el módulo como componentes de función en sí mismos, no hay diferencia de tiempo de ejecución o rendimiento entre los dos estilos.

Ahora que tenemos la ruta, el controlador, la vista y la plantilla, deberíamos poder dirigir nuestros navegadores a http://localhost:4000/hello.

Para reiniciar el server hacemos : 

mix phx.server

viernes, 24 de marzo de 2023

Primeros pasos con Phoenix parte 4


El directorio lib/hello_web contiene las partes relacionadas con la web de nuestra aplicación. Se ve así cuando se expande:

lib/hello_web

├── controllers

│   ├── page_controller.ex

│   ├── page_html.ex

│   ├── error_html.ex

│   ├── error_json.ex

│   └── page_html

│       └── home.html.heex

├── components

│   ├── core_components.ex

│   ├── layouts.ex

│   └── layouts

│       ├── app.html.heex

│       └── root.html.heex

├── endpoint.ex

├── gettext.ex

├── router.ex

└── telemetry.ex


Todos los archivos que se encuentran actualmente en los directorios de controladores y componentes están ahí para crear el mensaje "¡Bienvenido a Phoenix!" página que vimos en http://localhost:4000/

Al observar los directorios de controladores y componentes, podemos ver que Phoenix proporciona funciones para manejar diseños y HTML y páginas de error listas para usar.

Además de los directorios mencionados, lib/hello_web tiene cuatro archivos en su raíz. lib/hello_web/endpoint.ex es el punto de entrada para las solicitudes HTTP. Una vez que el navegador accede a http://localhost:4000, el punto final comienza a procesar los datos, lo que finalmente conduce al enrutador, que se define en lib/hello_web/router.ex. El enrutador define las reglas para enviar solicitudes a los "controladores", que llama a un módulo de vista para devolver las páginas HTML a los clientes. 

A través de Telemetry, Phoenix puede recopilar métricas y enviar eventos de monitoreo de su aplicación. El archivo lib/hello_web/telemetry.ex define al supervisor responsable de administrar los procesos de telemetría. 

Finalmente, hay un archivo lib/hello_web/gettext.ex que proporciona internacionalización a través de Gettext. Si no le preocupa la internacionalización, puede omitir con seguridad este archivo y su contenido.

El directorio de assert contiene archivos de origen relacionados con los activos front-end, como JavaScript y CSS. Desde Phoenix v1.6, usamos esbuild para compilar activos, que es administrado por el paquete esbuild Elixir. La integración con esbuild está integrada en su aplicación. La configuración relevante se puede encontrar en su archivo config/config.exs.

Sus otros activos estáticos se colocan en la carpeta priv/static, donde se guarda priv/static/assets para los activos generados. Todo en priv/static es atendido por el complemento Plug.Static configurado en lib/hello_web/endpoint.ex. Cuando se ejecuta en modo dev (MIX_ENV=dev), Phoenix observa cualquier cambio que realice en el directorio de activos y luego se encarga de actualizar su aplicación fronend en su navegador mientras trabaja.

Tenga en cuenta que cuando crea su aplicación Phoenix por primera vez usando mix phx.new, es posible especificar opciones que afectarán la presencia y el diseño del directorio assert. De hecho, las aplicaciones de Phoenix pueden traer sus propias herramientas de front-end o no tener un front-end en absoluto (útil si está escribiendo una API, por ejemplo). 

Si la integración predeterminada de esbuild no cubre sus necesidades, por ejemplo, porque desea utilizar otra herramienta de compilación, puede cambiar a una compilación de activos personalizados.

En cuanto a CSS, Phoenix incluye Tailwind CSS Framework, que proporciona una configuración básica para los proyectos. Puede pasar a cualquier marco CSS de su elección. 

sábado, 18 de marzo de 2023

Primeros pasos con Phoenix parte 3

Seguimos con phoenix. Cuando usamos mix phx.new para generar una nueva aplicación Phoenix, crea una estructura de directorio como esta:

├── _build

├── assets

├── config

├── deps

├── lib

│   ├── hello

│   ├── hello.ex

│   ├── hello_web

│   └── hello_web.ex

├── priv

└── test

Repasaremos esos directorios uno por uno:

  • _build: un directorio creado por la herramienta de línea de comando mix que se incluye como parte de Elixir y que contiene todos los artefactos de compilación. Como hemos visto en "Up and Running", mix es la interfaz principal de su aplicación. Usamos Mix para compilar nuestro código, crear bases de datos, ejecutar nuestro servidor y más. Este directorio no debe registrarse en el control de versiones y puede eliminarse en cualquier momento. Eliminarlo obligará a Mix a reconstruir su aplicación desde cero.
  • assets: un directorio que guarda el código fuente de sus activos front-end, normalmente JavaScript y CSS. La herramienta esbuild agrupa automáticamente estas fuentes. Los archivos estáticos como imágenes y fuentes van en priv/static.
  • config: un directorio que contiene la configuración del proyecto. El archivo config/config.exs es el punto de entrada para la configuración. Al final de config/config.exs, importa la configuración específica del entorno, que se puede encontrar en config/dev.exs, config/test.exs y config/prod.exs. Finalmente, se ejecuta config/runtime.exs.
  • deps - un directorio con todas nuestras dependencias Mix. Puede encontrar todas las dependencias enumeradas en el archivo mix.exs, dentro de la definición de la función defp deps do. Este directorio no debe registrarse en el control de versiones y puede eliminarse en cualquier momento. Eliminarlo obligará a Mix a descargar todas las versiones desde cero.
  • lib: un directorio que contiene el código fuente de su aplicación. Este directorio se divide en dos subdirectorios, lib/hello y lib/hello_web. El directorio lib/hello será responsable de alojar toda su lógica de negocio y dominio y por lo general, interactúa directamente con la base de datos. Este es el "Modelo" en la arquitectura Model-View-Controller (MVC). lib/hello_web se encarga de exponer el dominio de tu negocio al mundo, en este caso, a través de una aplicación web. Contiene tanto la vista como el controlador de MVC. 
  • priv: un directorio que guarda todos los recursos que son necesarios en producción pero que no forman parte directamente de su código fuente. Por lo general, guarda scripts de bases de datos, archivos de traducción, imágenes, etc. Los activos generados, creados a partir de archivos en el directorio de activos, se colocan en priv/static/assets de forma predeterminada.
  • test - un directorio con todas nuestras pruebas de aplicaciones. A menudo refleja la misma estructura que se encuentra en lib.


El directorio lib/hello alberga todo el dominio de su negocio. Dado que nuestro proyecto aún no tiene ninguna lógica de negocio, el directorio está casi vacío. Solo encontrarás tres archivos:


lib/hello

├── application.ex

├── mailer.ex

└── repo.ex


El archivo lib/hello/application.ex define una aplicación Elixir llamada Hello.Application. Esto se debe a que las aplicaciones de Phoenix son simplemente aplicaciones de Elixir. El módulo Hello.Application define qué servicios forman parte de nuestra aplicación:


children = [

  # Start the Telemetry supervisor

  HelloWeb.Telemetry,

  # Start the Ecto repository

  Hello.Repo,

  # Start the PubSub system

  {Phoenix.PubSub, name: Hello.PubSub},

  # Start the Endpoint (http/https)

  HelloWeb.Endpoint

  # Start a worker by calling: Hello.Worker.start_link(arg)

  # {Hello.Worker, arg}

]


Por ahora, baste decir que nuestra aplicación inicia un repositorio de base de datos, un sistema PubSub para compartir mensajes entre procesos y nodos, y el punto final de la aplicación, que atiende de manera efectiva las solicitudes HTTP. Estos servicios se inician en el orden en que se definen y, cada vez que cierra su aplicación, se detienen en el orden inverso.

El archivo lib/hello/mailer.ex contiene el módulo Hello.Mailer, que define la interfaz principal para enviar correos electrónicos:

defmodule Hello.Mailer do

  use Swoosh.Mailer, otp_app: :hello

end


En el mismo directorio lib/hello, encontraremos un lib/hello/repo.ex. Define un módulo Hello.Repo que es nuestra interfaz principal para la base de datos. Si está utilizando Postgres (la base de datos predeterminada), verá algo como esto:


defmodule Hello.Repo do

  use Ecto.Repo,

    otp_app: :hello,

    adapter: Ecto.Adapters.Postgres

end


Como nosotros usamos mysql vemos esto: 


defmodule HelloWorld.Repo do

  use Ecto.Repo,

    otp_app: :hello_world,

    adapter: Ecto.Adapters.MyXQL

end



jueves, 16 de marzo de 2023

Primeros pasos con Phoenix parte 2


Tema que en el post anterior cree un hola mundo pero con postgres y no tengo instalado postgres así que tiraba error por todos lados. 

Vamos hacer un hola mundo con mysql : 

 mix phx.new hello_world --module HelloWorld --database mysql

Y luego hacemos : 

 cd hello_world

Y para configurar la base usamos :

 mix ecto.create

A mi me tira este error : 

00:07:59.485 [error] GenServer #PID<0.297.0> terminating

** (MyXQL.Error) (1045) (ER_ACCESS_DENIED_ERROR) Access denied for user 'root'@'localhost' (using password: NO)

    (db_connection 2.4.3) lib/db_connection/connection.ex:100: DBConnection.Connection.connect/2

    (connection 1.1.0) lib/connection.ex:622: Connection.enter_connect/5

    (stdlib 4.2) proc_lib.erl:240: :proc_lib.init_p_do_apply/3

Last message: nil

State: MyXQL.Connection


Porque mi base mysql tiene password y no existe la base que esta queriendo consultar. Por ende vamos a el archivo hello_world/config/dev.exs y vamos a configurar los datos : 

config :hello_world, HelloWorld.Repo,
  username: "root",
  password: "acaVaElPassword",
  hostname: "localhost",
  database: "hello_world_dev",
  stacktrace: true,
  show_sensitive_data_on_connection_error: true,
  pool_size: 10

Como vimos la base se llama hello_world_dev y la creamos con el sql : 

CREATE SCHEMA `hello_world_dev` ;

O de forma visual con el workbeach. 

Ahora si ejecutamos : mix ecto.create obtendremos la siguiente salida: 

Compiling 15 files (.ex)

Generated hello_world app

The database for HelloWorld.Repo has already been created


Ahora podemos levantar el server sin problemas :

mix phx.server


Y si vamos a http://127.0.0.1:4000/ obtendremos la pagina de inicio :D 



jueves, 9 de marzo de 2023

Gleam, un lenguaje funcional que corre en la Vm de Erlang.


Gleam es un lenguaje funcional que corre sobre la maquina virtual de Erlang. Es de tipado estatico, funcional y sintaxis similar a Erlang y Elixir.   

Gleam se ejecuta en la máquina virtual Erlang que impulsa sistemas a escala planetaria como WhatsApp y Ericsson, está listo para cargas de trabajo de cualquier tamaño. Gracias a un sistema de simultaneidad basado en múltiples núcleos que puede ejecutar millones de tareas simultáneas, estructuras de datos rápidas e inmutables y un recolector de basura simultáneo, su servicio puede escalar y mantenerse con facilidad.

Gleam viene con compilador, herramienta de compilación, formateador, integraciones de editor y administrador de paquetes, todo integrado, por lo que crear un proyecto Gleam es simplemente ejecutar gleam new.

Como parte del ecosistema BEAM más amplio, los programas Gleam pueden usar miles de paquetes publicados, ya sea que estén escritos en Gleam, Erlang o Elixir.

Sin valores nulos, sin excepciones, mensajes de error claros y un sistema de tipo práctico. Ya sea que esté escribiendo código nuevo o manteniendo código antiguo, Gleam está diseñado para hacer que su trabajo sea lo más divertido y libre de estrés posible.

Gleam también puede compilar en JavaScript, lo que le permite usar su código en el navegador o en cualquier otro lugar donde se pueda ejecutar JavaScript. También genera definiciones de TypeScript, por lo que puede interactuar con su código Gleam con confianza, incluso desde el exterior.


Veamos un pequeño hola mundo hecho en Gleam:

import gleam/io


pub fn main() {

  io.println("hello, friend!")

}


Por ejemplo veamos código asincrono: 


fn spawn_task(i) {

  task.async(fn() {

    let n = int.to_string(i)

    io.println("Hello from " <> n)

  })

}


pub fn main() {

  // Run a million threads, no problem

    list.range(0, 1_000_000)

  |> list.map(spawn_task)

  |> list.each(task.await_forever)

}

Dejo link: https://gleam.run/

domingo, 5 de marzo de 2023

Primeros pasos con Phoenix


Antes de empezar de manera muy rápida aclaremos que Phoenix es un framework web o para hacer API en Elixir. 

Phoenix está escrito en Elixir, y nuestro código de aplicación también estará escrito en Elixir. Por ende el primer paso es instalar Elixir , en mi caso lo voy a instalar con asdf

asdf plugin-add elixir https://github.com/asdf-vm/asdf-elixir.git

asdf install elixir 1.14.3-otp-25

El código de Elixir se compila en el código de bytes de Erlang para ejecutarse en la máquina virtual de Erlang. Sin Erlang, el código de Elixir no tiene una máquina virtual para ejecutarse, por lo que también debemos instalar Erlang. 

asdf plugin add erlang https://github.com/asdf-vm/asdf-erlang.git

asdf install erlang 25.0.3

Y ahora vamos a setear las versiones: 

asdf global erlang 25.0.3

asdf global elixir 1.14.3-otp-25

Pero pueden ver como instalar en su equipo en el siguiente link : https://elixir-lang.org/install.html

Cuando instalamos Elixir siguiendo las instrucciones de la página de instalación de Elixir, normalmente también obtendremos Erlang. Para checkear esto hacemos : 

emanuel@crespo:~$ elixir --version

Erlang/OTP 25 [erts-13.1.5] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns]


Elixir 1.14.3 (compiled with Erlang/OTP 25)


También podemos escribir erl que es el comando para la relp de Erlang. 

Si acabamos de instalar Elixir por primera vez, también necesitaremos instalar el administrador de paquetes Hex. Hex es necesario para ejecutar una aplicación de Phoenix (mediante la instalación de dependencias) y para instalar cualquier dependencia adicional que podamos necesitar en el camino. En mi caso es : 

mix local.hex


Ahora debemos instalar phoenix, en mi caso voy a instalar la ultima versión

mix archive.install hex phx_new 

Por lo visto, ya esta todo instalado, ahora vamos a crear nuestro primer proyecto: 

mix phx.new hello_world --module HelloWorld

Y si todo salio bien vamos a ejecutarlo: 

cd hello_world/
mix phx.server

Si vamos a http://localhost:4000/ nos aparecerá una pagina. 

Van a ver que tira como 5000 errores porque no configuramos la base de datos, pero eso lo vamos hacer en el proximo post. 

Dejo link; https://www.phoenixframework.org/

martes, 3 de noviembre de 2020

Elixir School


Elixir School es el primer destino para personas que buscan aprender y dominar el lenguaje de programación Elixir

Ya seas un veterano experimentado o esta es tu primera vez, vas a encontrar lo que necesitas en las lecciones y en los recursos auxiliares

Mediante el trabajo duro de voluntarios Elixir School ha sido traducido a muchos idiomas. Algunas de estas traducciones incluyen: Việt ngữ, 简体中文, 繁體中文, English, Slovenčina, 日本語, Polski, Português, Русском, Bahasa Indonesia, Bahasa Melayu, Українською, 한국어, Italiano, Deutsch, বাংলা, Türkçe, y ภาษาไทย.

Te damos la bienvenida y te motivamos a continuar haciendo Elixir School grandioso involucrándote en elixirschool/elixirschool!

De esta manera se presenta Elixir school que es un excelente sitio para comenzar con Elixir. 

Y sin más dejo link: https://elixirschool.com/es/

viernes, 28 de agosto de 2020

Que lenguaje de programación debo aprender?


Este es un post de opinión no me apoyo en ninguna encuesta o nada, es opinión de lo que voy leyendo. A la vez ya hice post similares pero lo actualice a 2020. 

Dicho esto, me pongo a opinar. Si queres aprender un lenguaje de programación, lo que primero que debes hacer es pensar a que te queres dedicar. Dado que la programación tiene varios objetivos y si bien hay lenguajes que son buenos para todo pero no son populares en todo, por lo tanto, dependiendo a que te queres dedicar es el lenguaje que debes aprender. 

Voy a listar temas y poniendo los lenguajes. 

Backend : Java, C#, Kotlin, Scala, Groovy, PHP, Python, Haskell, Go, SQL, Ruby

Frontend : Javascript, Typescript, Elm

Mobile : Java, Kotlin, C#, Dart

Data science : SQL, Python, Julia, R

Sistemas (bajo nivel) : Rust, Go, C

Sistemas concurrentes : Rust, Go, Scala, Haskell, Erlang, Elixir

Juegos : C, C++, Rust, Go, Lua, Elm, C#



sábado, 8 de agosto de 2020

Programación funcional, pros y contras

Lei un articulo y me gusto mucho, por lo tanto les dejo un resumen, al final esta el articulo original :

Como saben, los programadores son personas creativas, pero al mismo tiempo se adhieren celosamente a ciertas ideas, por ejemplo, la elección de un lenguaje de programación. PHP se considera un "lenguaje vago" y JavaScript es magia "difícil de predecir". Y en medio de la gran abundancia de lenguajes, los lenguajes funcionales están ganando cada vez más seguidores y cada vez más se están abriendo camino en la mayoría de las empresas de todo el mundo. Según la analítica RedMonk. Desde junio de 2017 y la evaluación combinada de la popularidad de los lenguajes en GitHub y Slack Overflow, los lenguajes funcionales (Elm, Elixir) están creciendo lenta pero seguramente. El gran aumento en la popularidad de JavaScript también está impulsando un mayor interés en FP. Además, los desarrolladores con experiencia en programación funcional posteriormente comenzaron a trabajar en frameworks y como resultado, tenemos Redux, React, MobX y otras librerías que usan millones de personas.

Entonces, ¿qué es la programación funcional, por qué hay tanto auge y por qué vale la pena considerar aprenderla? Vamos a resolverlo.

El mundo de JavaScript está hirviendo. Hace unos años, solo unos pocos desarrolladores entendían la programación funcional, pero en los últimos tres años, casi todas las bases de código de grandes aplicaciones han estado utilizando activamente ideas tomadas del mundo de la programación funcional. Y por una buena razón: la programación funcional le permite escribir código más conciso y predecible, y es más fácil de probar (aunque aprender desde cero no es fácil).

Las principales características distintivas del desarrollo de software con FP:
  • funciones puras;
  • evitar el estado compartido, datos mutables y efectos secundarios;
  • La prevalencia de un enfoque declarativo más que imperativo.
La programación funcional se basa inherentemente en los principios fundamentales y definitorios enumerados anteriormente. Y para comenzar a comprenderlos, primero debe cambiar al modo "académico" y cómo debe estudiar las definiciones de términos que lo seguirán implacablemente en FP: funciones puras, composición de funciones, evitar el estado compartido, etc. Esto es más como volver a la escuela. a una lección de matemáticas, pero después de eso verás tanto la funcionalidad como la programación de una manera completamente diferente.

Profundicemos un poco más en los términos de FP y, al menos superficialmente, comprendamos lo que significan.

Las funciones puras  son funciones deterministas sin efectos secundarios. Una función determinista significa que para el mismo conjunto de valores de entrada, devuelve el mismo resultado. Para FP, las propiedades de tales funciones son muy importantes: por ejemplo, las funciones puras tienen transparencia referencial: puede reemplazar una llamada de función con su valor final sin cambiar el valor del programa.

La composición de funciones se refiere al proceso de combinar dos o más funciones para crear una nueva función o realizar cálculos.

El principal problema con los estados compartidos es que para comprender los efectos de una función, debe conocer el historial completo de cada variable compartida que utiliza la función. Por lo tanto, la programación funcional evita estados compartidos, confiando en cambio en estructuras de datos inmutables y computación sin procesar para extraer nuevos datos de los existentes. Otro matiz que surge cuando se trabaja con estados compartidos es que cambiar el orden de las llamadas a funciones puede provocar una avalancha de errores. En consecuencia, al evitar estados compartidos, también evita este problema.

Subyacente a toda la programación funcional está la inmutabilidad (inmutabilidad). Y aquí es importante no confundirse const con la inmutabilidad. const crea un enlace de nombre variable que no se puede reasignar después de la creación, pero no crea objetos inmutables. No podrá cambiar el objeto al que pertenece el enlace, pero aún puede cambiar las propiedades de este objeto const, por lo tanto , los enlaces creados no son inmutables. Los objetos inmutables no se pueden cambiar en absoluto. Esto se logra mediante la congelación profunda de las variables.

Los efectos secundarios significan que, además de devolver un valor, la función también interactúa con el estado mutable externo. ¿Por qué FP los evita? Porque de esta manera los efectos del programa son mucho más fáciles de entender y probar. Haskell, por ejemplo, usa mónadas para aislar los efectos secundarios de las funciones puras.

El punto es que el enfoque imperativo funciona según el principio de control de flujo y responde a la pregunta "cómo hacerlo". El enfoque declarativo describe el flujo de datos y responde a la pregunta "qué hacer". Además, el código imperativo a menudo se basa en instrucciones (operadores), mientras que el código declarativo se basa más en las expresiones.

Entonces, descubrimos qué es la programación funcional y qué necesita saber al respecto. Y, antes de pasar a discutir sus ventajas, propongo pasar primero por las desventajas, más precisamente, para comprender la esencia del estereotipo "la programación funcional no es natural".

A juzgar por lo que escribí anteriormente, los seguidores de la programación funcional ya deberían haber surgido entre los lectores. Sin embargo, a pesar de la gran cantidad de artículos laudatorios, no hay menos artículos titulados "La programación funcional es extraña y no tiene futuro" (por ejemplo). ¿Esto significa que estoy equivocado? No. ¿Hay alguna razón para pensar que la FA es extraña? Por supuesto.

Permíteme darte una cita de Internet que refleja completamente la actitud de muchos desarrolladores hacia FP:

"Escribir código funcional es como escribir al revés y la mayoría de las veces es como resolver un rompecabezas en lugar de explicar el proceso a una computadora".
De hecho, esta es una actitud bastante subjetiva hacia la FP para aquellos que no quieren dedicar suficiente tiempo para comprender los matices de la programación funcional y simplemente intentarlo. Pero, como prometí, veamos las desventajas de FP y luego veamos las ventajas.

Primero, no existe un vocabulario eficiente desordenado y configurado para lenguajes funcionales. Los diccionarios puramente funcionales son más lentos que las tablas hash, y esto puede ser crítico para algunas aplicaciones. En segundo lugar, no hay tablas hash débiles puramente funcionales, aunque para la mayoría de los desarrolladores esta falla puede pasar desapercibida.

Además, FP no es adecuado para algoritmos en gráficos (debido a su funcionamiento lento) y, en general, para aquellas soluciones que se han basado en programación imperativa durante décadas.

De acuerdo, el último punto suena más como una queja: no podemos culpar a FP por lo que no estaba destinado. Por lo tanto, propongo recurrir a lo agradable, es decir, a las ventajas de FP y su uso en proyectos reales por parte de compañías internacionales reales.

Uno de los beneficios más obvios de la programación funcional son las abstracciones de alto nivel que ocultan muchos de los detalles de las operaciones de rutina, como la iteración. Debido a esto, el código es más corto y, como resultado, garantiza menos errores que se pueden cometer.

Además, el FP contiene menos primitivas de lenguaje. Las clases bien conocidas en FP simplemente no se usan: en lugar de crear una descripción única de un objeto con operaciones en forma de métodos, la programación funcional utiliza varias primitivas básicas del lenguaje que están bien optimizadas internamente.

Además, la programación funcional permite al desarrollador acercar el lenguaje al problema, en lugar de viceversa, todo a expensas de las estructuras flexibles y la flexibilidad del lenguaje. Además, FP ofrece a los desarrolladores nuevas herramientas para resolver problemas complejos que los programadores de POO a menudo descuidan.

De hecho, es demasiado largo para enumerar todas las ventajas de la programación funcional; realmente hay muchas de ellas. Puedo decir esto: trabajar con lenguajes funcionales proporciona una escritura de código precisa y rápida, facilita las pruebas y la depuración, los programas son de nivel superior y las firmas de funciones son más informativas.

Por supuesto, uno no puede negar las ventajas de POO, pero vale la pena recordar que los lenguajes funcionales están a la par con muchos otros en términos de conveniencia y merecen su atención.

En el mundo de TI, nada sucede. Una cosa se aferra a la otra, y ahora todas las tendencias más actuales están interconectadas.

Si recordamos las tendencias más sensacionales de 2016-2017, estas, por supuesto, serán AI, IoT, Big Data y Blockchain. Están en boca de todos, todos conocen su potencial y sus características clave. Y son algunas de estas tendencias las que han catalizado la creciente popularidad de la programación funcional entre los desarrolladores.

Actualmente, el problema del procesamiento paralelo y el trabajo con grandes flujos de datos es muy grave, en otras palabras, trabajar con Big Data. Y, paralelizando el procesamiento de estos datos, puede obtener el resultado deseado en una fracción de segundo, lo cual es muy crítico en el mundo real. Además, no se olvide de la informática descentralizada (distribuida): blockchains y otras, que, en esencia, son un mecanismo bastante complejo. Y para tales cálculos, el código funcional es más adecuado debido a todos los principios de la programación funcional (como las funciones puras, por ejemplo). El uso de todas las técnicas básicas de FP facilita la ejecución y el mantenimiento de código paralelo.

Además, si la programación funcional anterior se usaba solo para resolver problemas específicos, ahora incluso se aplica a proyectos clásicos. 

Como probablemente ya haya entendido, no debe temer la programación funcional. Un poco de diligencia y curiosidad, y ahora has dominado la FP. Aquí hay algunos consejos para aquellos que han decidido probarse en un nuevo género y aprender algo radicalmente nuevo:
  • Relájate :) Al principio será muy complicado, teniendo en cuenta que tendrás que dejar atrás lo que sabes y aprender nuevos enfoques y principios. Y eso esta bien. Piense en la primera vez que aprendió a codificar. Nada malo sucederá.
  • Comience con micro tareas para tenerlo en sus manos.
  • Comience a aprender Haskell y luego pase a Scala (o F #) para comenzar a comprender los principios de programación funcional (y al mismo tiempo comenzar a pensar más "funcional").
Dada la prevalencia de la programación funcional, puede estar seguro de su futuro profesional (con la debida diligencia), ya que seguramente puede usar sus habilidades recién adquiridas. ¡No tengas miedo de intentarlo!

lunes, 1 de junio de 2020

repl.it, Una super IDE online


repl.it es un IDE gratuito, colaborativo y en el navegador para codificar en más de 50 lenguajes, sin gastar un segundo en la configuración.

Les cuento, quería probar algo en Haskell y me encontré con esta joya. Esta muy bueno, te haces un usuario si queres, codeas y si configuraste un repo en github te guarda los archivos ahí. Podes compartir codigo, trabajar en equipo...

Podes programar en : 

Python, Nodejs, C, Java, C++, Ruby, HTML, CSS, JS, Lisp, Go, Rust, Roy, kotlin, Swift, F#, C#, etc...

Punto bajo, no permite ni Scala, ni Grovyy... 


Dejo link: https://repl.it/

lunes, 9 de marzo de 2020

HTML + javascript + Haskell = ELM, parte 4


Seguimos con el post anteriro.

Como con cualquier lenguaje funcional, la base de Elm es la función. Definir una es trivial. Veamos algunas funciones :

> add x y = x + y
<function> : number -> number -> number
> double x = x * 2
<function> : number -> number
> anonymousInc = \x -> x + 1
<function> : number -> number
> double (add 1 2)
6 : number
> List.map anonymousInc [1, 2, 3]
[2,3,4] : [number]

La sintaxis para crear funciones es muy simple e intuitiva. add es una función con nombre con dos argumentos, x e y. Las funciones anónimas expresan parámetros como \ x, y el cuerpo de la función sigue los caracteres ->.
Como Elixir, Elm tiene el operador de tubería que permite componer funciones, de esta manera:


Tomamos 5 y lo pasamos como el primer argumento a anonymousInc, para obtener 6. Luego, lo pasamos como el primer argumento para duplicar. También podemos hacer que esa expresión se ejecute de derecha a izquierda:

> double <| anonymousInc <| 5
12 : number

Evan Czaplicki, creador de Elm, dice que obtuvo esta función de F#, que a su vez obtuvo la idea de las tuberías de Unix, por lo que esta idea ha existido por un tiempo, ¡pero es buena!
Al igual que con cualquier lenguaje funcional, hay muchas funciones que le permitirán trabajar con funciones de todo tipo de formas:

> List.map double [1..3]
[2,4,6] : List number
> List.filter (\x -> x < 3) [1..20]
[1,2] : List comparable

[1..3] es un rango. Puede explorar más funciones de la Lista con la biblioteca de listas.

Cuando está componiendo una solución con Elm, puede tener la tentación de codificar cada caso como un cuerpo de función separado como lo haría en Haskell, Erlang o Elixir, pero no se puede :( :

> factorial 1 = 1
<function> : number -> number'
> factorial x = x * factorial (x - 1)
<function> : number -> number
RangeError: Maximum call stack size exceeded

Parece que la segunda llamada reemplazó a la primera. En cambio, debe usar el mismo cuerpo de función y dividir el problema usando mayúsculas y minúsculas o si, de esta manera:

> factorial x = \
|  if | x == 0 -> 1 \
|      | otherwise -> x * factorial (x - 1)
<function> : number -> number
> factorial 5
120 : number

Suficientemente simple. factorial 0 es 1; de lo contrario, factorial x es x * factorial (x-1). Manejaría la recursividad de la lista de la misma manera:

> count list = \
| case list of \
| [] -> 0 \
| head::tail -> 1 + count tail
<function> : [a] -> number
> count [4, 5, 6]
3 : number

La cantidad de elementos de una lista vacía es cero y la cantidad de elementos de cualquier otra lista es 1 más la cantidad del resto. Veamos cómo atacar problemas similares con la coincidencia de patrones.

Por ahora vamos bien, pero seguimos en otro post... 


sábado, 2 de noviembre de 2019

Resultados de la encuesta de Stackoverflow 2019



Stackoverflow publico los resultados de su encuesta 2019, la verdad todo normal nada que me llame la atención excepto:


  • Lenguaje más amado Rust, ya me tengo que poner a estudiar este lenguaje. 
  • Lenguajes mejor pagos, del top 5, 4 son funcionales. Así que es buena idea aprender programación funcional. 




Dejo link : https://insights.stackoverflow.com/survey/2019