Mix y Proyectos

La herramienta de construcción de Elixir para crear y gestionar proyectos.

¿Qué es Mix?

Mix es la herramienta oficial de Elixir para:

Crear un nuevo proyecto

# Proyecto básico
mix new mi_proyecto

# Con supervisor (aplicación OTP)
mix new mi_app --sup

# Estructura creada:
mi_proyecto/
├── lib/
│   └── mi_proyecto.ex
├── test/
│   ├── mi_proyecto_test.exs
│   └── test_helper.exs
├── mix.exs
└── README.md

El archivo mix.exs

Este es el corazón de tu proyecto:

defmodule MiProyecto.MixProject do
  use Mix.Project

  def project do
    [
      app: :mi_proyecto,
      version: "0.1.0",
      elixir: "~> 1.15",
      start_permanent: Mix.env() == :prod,
      deps: deps()
    ]
  end

  def application do
    [
      extra_applications: [:logger],
      mod: {MiProyecto.Application, []}  # Si usas --sup
    ]
  end

  defp deps do
    [
      # {:jason, "~> 1.4"},
      # {:httpoison, "~> 2.0"}
    ]
  end
end

Comandos esenciales de Mix

ComandoDescripción
mix compileCompilar el proyecto
mix testEjecutar tests
mix runEjecutar el proyecto
mix deps.getDescargar dependencias
mix deps.update --allActualizar dependencias
mix formatFormatear código
mix helpVer todos los comandos
iex -S mixIEx con tu proyecto cargado

Dependencias

Las dependencias se declaran en mix.exs y se descargan de Hex (el gestor de paquetes de Elixir):

defp deps do
  [
    # Desde Hex
    {:jason, "~> 1.4"},
    {:httpoison, "~> 2.0"},

    # Desde GitHub
    {:mi_lib, github: "usuario/mi_lib"},

    # Desde ruta local
    {:otra_lib, path: "../otra_lib"},

    # Solo para desarrollo/test
    {:credo, "~> 1.7", only: [:dev, :test], runtime: false}
  ]
end
Buscar paquetes

Visita hex.pm para buscar paquetes. También puedes usar mix hex.search nombre desde la terminal.

Entornos (environments)

Mix soporta tres entornos por defecto:

# Ejecutar en un entorno específico
MIX_ENV=prod mix compile
MIX_ENV=test mix test

# Verificar entorno actual
iex> Mix.env()
:dev

Tests con ExUnit

Elixir incluye ExUnit, un framework de testing integrado:

# test/mi_proyecto_test.exs
defmodule MiProyectoTest do
  use ExUnit.Case
  doctest MiProyecto

  describe "suma/2" do
    test "suma dos números positivos" do
      assert MiProyecto.suma(1, 2) == 3
    end

    test "suma con cero" do
      assert MiProyecto.suma(5, 0) == 5
    end

    test "suma números negativos" do
      assert MiProyecto.suma(-1, -2) == -3
    end
  end

  test "ejemplo con refute" do
    refute MiProyecto.vacia?([1, 2, 3])
  end

  test "verificar excepción" do
    assert_raise ArgumentError, fn ->
      MiProyecto.dividir(1, 0)
    end
  end
end

Ejecutar tests

# Todos los tests
mix test

# Archivo específico
mix test test/mi_proyecto_test.exs

# Línea específica
mix test test/mi_proyecto_test.exs:10

# Con más detalle
mix test --trace

# Solo tests que fallaron antes
mix test --failed

Doctests

Puedes escribir tests en la documentación:

defmodule MiProyecto do
  @doc """
  Suma dos números.

  ## Ejemplos

      iex> MiProyecto.suma(1, 2)
      3

      iex> MiProyecto.suma(-1, 1)
      0
  """
  def suma(a, b), do: a + b
end

# En el test, agregar:
doctest MiProyecto

Configuración

Configura tu aplicación en config/config.exs:

# config/config.exs
import Config

config :mi_proyecto,
  api_key: "desarrollo_key",
  timeout: 5000

# Importar configuración específica del entorno
import_config "#{config_env()}.exs"
# config/prod.exs
import Config

config :mi_proyecto,
  api_key: System.get_env("API_KEY"),
  timeout: 30000
# Acceder a la configuración
iex> Application.get_env(:mi_proyecto, :api_key)
"desarrollo_key"

Application: La aplicación OTP

Con --sup, Mix crea un módulo Application que inicia tu árbol de supervisión:

# lib/mi_proyecto/application.ex
defmodule MiProyecto.Application do
  use Application

  @impl true
  def start(_type, _args) do
    hijos = [
      # Procesos que se inician con la aplicación
      {MiProyecto.Cache, []},
      {MiProyecto.Worker, name: MiProyecto.Worker}
    ]

    opts = [strategy: :one_for_one, name: MiProyecto.Supervisor]
    Supervisor.start_link(hijos, opts)
  end
end

Releases para producción

Un release es tu aplicación empaquetada con Erlang/OTP, lista para producción:

# Crear release
MIX_ENV=prod mix release

# Ejecutar
_build/prod/rel/mi_proyecto/bin/mi_proyecto start

# Configurar release en mix.exs
def project do
  [
    # ...
    releases: [
      mi_proyecto: [
        include_executables_for: [:unix],
        steps: [:assemble, :tar]
      ]
    ]
  ]
end
Ejercicio 9.1 Crear proyecto completo Básico

Crea un nuevo proyecto con Mix que incluya:

  • Un módulo con al menos 3 funciones
  • Documentación con @doc y doctests
  • Tests unitarios para cada función
  • Asegúrate que todos los tests pasen
Ejercicio 9.2 Dependencias y configuración Intermedio

Extiende tu proyecto:

  • Agrega Jason como dependencia
  • Crea una función que serialice/deserialice mapas
  • Configura un valor en config.exs y úsalo en tu código
  • Escribe tests para la nueva funcionalidad