В этом руководстве мы научимся создавать полноценные приложения на Эликсире. В них будут использоваться супервизоры, конфигурация, тесты и многое другое.
Приложение работает в качестве распределенного хранилища ключ-значение. Мы собираемся организовать пары ключ-значение в корзины и распространять эти корзины по нескольким нодам. Мы также построим простой клиент, который позволит подключаться к любому из узлов, а также посылать запросы, такие как:
CREATE shopping
OK
PUT shopping milk 1
OK
PUT shopping eggs 3
OK
GET shopping milk
1
OK
DELETE shopping eggs
OK
Для того, чтобы создать наше приложение, мы будем использовать три основных инструмента, идущих в коробке с Эликсиром:
-
OTP
(Open Telecom Platform) – набор библиотек из арсенала Эрланга. Эрлангисты используютOTP
для построения надёжных, отказоустойчивых приложений. В этой главе будет рассмотрено как много аспектовOTP
интегрируются с Эликсиром, включая деревья супервизоров, менеджеры событий и многое другое; -
Микс – инструмент для сборки, решающий задачи по созданию, компиляции, тестированию приложения, управлению его зависимостями и многому другому;
-
ExUnit
– фреймворк для модульного тестирования.
В этой главе мы создадим наш первый проект с использованием Микса и исследуем различные особенности в OTP, Микс и ExUnit
.
Давайте начнем!
Примечание: это руководство требует Эликсир (версии 1.2.0 или более поздней). Вы можете проверить свою версию Эликсира, введя в терминале
elixir ‐‐version
, и установить более свежую версию, если требуется. Выполните действия, описанные во «Введении».Полный код для этого руководства вы можете найти в репозитории
Наш первый проект
При установке Эликсира, кроме получения исполняемых файлов elixir
, elixirc
и iex
, вы также получите исполняемый Эликсиром сценарий mix
.
Давайте создадим наш первый проект с помощью вызова mix new
из командной строки. Передадим в нее имя проекта в качестве аргумента (kv
в данном случае), и скажем Миксу, что наш главный модуль должен состоять из прописных букв KV
, вместо Kv
по умолчанию:
$ mix new kv --module KV
Микс создаcт директорию kv
с несколькими файлами в ней:
* creating README.md
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/kv.ex
* creating test
* creating test/test_helper.exs
* creating test/kv_test.exs
Давайте кратко рассмотрим эти сгенерированные файлы.
Примечание: Микс представляет собой исполняемый файл для Эликсира. Это означает, что для работы команды
mix
вы должны иметь его в вашей переменнойPATH
. Если он там отсутствует, вы можете запустить его из директории сценария, используя в качестве аргументаelixir
:$ bin/elixir bin/mix new kv --module KV
Обратите внимание, что директория Эликсира находится в переменной
PATH
. Вы также можете выполнить любой скрипт с помощью опции-S
:$ bin/elixir -S mix new kv --module KV
При использовании опции
-S
командаelixir
находит сценарий, где бы он ни находился в переменнойPATH
и выполняет его.
Компиляция проекта
Файл mix.exs
был сгенерирован внутри папки проекта kv
, и его основной задачей является конфигурирование проекта. Давайте взглянем на него:
defmodule KV.Mixfile do
use Mix.Project
def project do
[app: :kv,
version: "0.1.0",
elixir: "~> 1.3",
start_permanent: Mix.env == :prod,
deps: deps()]
end
def application do
[extra_applications: [:logger]]
end
defp deps do
[]
end
end
Файл mix.exs
определяет две публичные функции: project
, которая возвращает конфигурацию проекта, содержащую имя проекта, версию приложения, версию Эликсира; и application
, которая используется для генерации файла приложения.
В этом файле также представлена вызываемая из функции project
приватная функция deps
, которая определяет зависимости проекта. Определение deps
как отдельной функции не является обязательным, но это помогает держать конфигурацию проекта в аккуратном виде.
Микс также создает файл lib/kv.ex
, в котором просто определяется модуль приложения:
defmodule KV do
end
Этой структуры достаточно для компиляции проекта:
$ cd kv
$ mix compile
На выходе:
Compiling 1 file (.ex)
Generated kv app
Файл lib/kv.ex
был скомпилирован, манифест приложения kv.app
– создан, и все протоколы объединены, как описано в руководстве по «Протоколам». Все артефакты компиляции помещаются в директорию _build
, используя параметры из файла mix.exs
.
После того, как проект скомпилирован, можно запустить сессию IEx
внутри проекта:
$ iex -S mix
Выполнение тестов
Микс также подготавливает структуру для запуска тестов проекта. Такие проекты обычно следуют договоренности наличия файлов <filename>_test.exs
в директории test
для каждого файла в директории lib
. По этой причине мы уже можем найти файл test/kv_test.exs
, соответствующий файлу lib/kv.ex
. Пока он почти ничего не делает:
defmodule KVTest do
use ExUnit.Case
doctest KV
test "the truth" do
assert 1 + 1 == 2
end
end
Важно отметить пару вещей:
-
Тестовый файл – это файл сценария на Эликсире с расширением
.exs
. Благодаря этому соглашение не нужно компилировать тестовые файлы перед их запуском; -
Мы определяем тестовый модуль с названием
KVTest
, используем модульExUnit.Case
для добавления к нему API тестирования и определяем простой тест с помощью макросаtest/2
;
Микс также создает файл с названием test/test_helper.exs
, который отвечает за настройку тестового фреймворка:
ExUnit.start()
Этот файл будет автоматически подключаться Миксом каждый раз перед запуском тестов. Мы можем запустить тесты с помощью команды mix test
:
Compiled lib/kv.ex
Generated kv app
[...]
.
Finished in 0.04 seconds (0.04s on load, 0.00s on tests)
1 test, 0 failures
Randomized with seed 540224
Обратите внимание, что при запуске команды mix test
, Микс компилирует исходные файлы и генерирует файл приложения еще раз. Это происходит, потому что Микс поддерживает несколько окружений, которые мы будем изучать в следующем разделе.
Кроме того, вы можете увидеть, что ExUnit
печатает точку для каждого успешного теста и автоматически рандомизирует тесты. Давайте сделаем ошибочный тест и посмотрим, что произойдет.
Изменим утверждение в файле test/kv_test.exs
на следующее:
assert 1 + 1 == 3
Теперь запустите команду mix test
снова (заметьте, в этот раз не будет никакой компиляции):
1) test the truth (KVTest)
test/kv_test.exs:5
Assertion with == failed
code: 1 + 1 == 3
lhs: 2
rhs: 3
stacktrace:
test/kv_test.exs:6
Finished in 0.05 seconds (0.05s on load, 0.00s on tests)
1 test, 1 failure
Для каждой ошибки ExUnit
печатает подробный отчет, содержащий имя теста, причину падения, непрошедший успешно код, и значения выражения для левой стороны (lhs
) и правой стороны (rhs
) для оператора ==
.
Во второй строке падения теста, сразу под названием тестового файла, есть место, где тест был определен. Если вы скопируете расположение теста на второй линии (в том числе файл и номер строки) и добавите его в команду mix test
, Микс загрузит и выполнит только этот тест:
$ mix test test/kv_test.exs:5
Такое сокращение чрезвычайно полезно для быстрого запуска конкретного теста.
Наконец, трассировка стека во время падения дает информацию о тесте и часто о месте падения в исходном файле.
Окружения
Микс поддерживает концепцию «окружений». Они позволяют разработчику настроить компиляцию и другие опции для конкретных сценариев. По умолчанию, Микс понимает три окружения:
:dev
– в которой задачи Микса (такие какcompile
) запускаются по умолчанию;:test
– используется командойmix test
;:prod
– используется для запуска проекта в продакшне.
Окружения применяется только к текущему проекту. Как мы увидим позже, любые зависимости, которые вы добавляете в проект по умолчанию будут работать в окружении :prod
.
Настройки окружения могут быть сделаны путем доступа к функции Mix.env
в файле mix.exs
, которая возвращает текущее окружение в виде атома. Это используется в функции :start_permanent
:
def project do
[...,
start_permanent: Mix.env == :prod,
...]
end
При истинности опции :start_permanent
приложение будет запущено в перманентном режиме, в котором виртуальная машина Эрланга упадёт, при отключении дерева супервизоров. Заметьте, мы не хотим, чтобы такое поведение было в режимах разработки и тестирования, потому что нужно оставить работающий экземпляр виртуальной машины для устранения неполадок.
Микс по умолчанию работает в :dev
окружении, за исключением тестовых задач, которые будут работать по умолчанию в среде :test
. Окружение может быть изменено через переменную среды MIX_ENV
:
$ MIX_ENV=prod mix compile
или для Виндоус:
> set "MIX_ENV=prod" && mix compile
Микс – это инструмент сборки, и он не всегда будет доступен в продакшнe, особенно если ваша команда использует явные шаги сборки приложений. Поэтому рекомендуется использовать
Mix.env
только в файлах конфигурации и внутриmix.exs
. И никогда в коде приложения (внутри директорииlib
).
Исследование
Есть очень много всего, чего хотелось бы сказать о Миксе. Узнать больше можно в документации.
Имейте в виду, что список всех существующих задач можно вызвать командой:
$ mix help
Вы можете получить дополнительную информацию о конкретной задаче, вызвав команду mix help TASK
.
Давайте уже напишем немного кода!