В этом руководстве мы научимся создавать полноценные приложения на Эликсире. В них будут использоваться супервизоры, конфигурация, тесты и многое другое.
Приложение работает в качестве распределенного хранилища ключ-значение. Мы собираемся организовать пары ключ-значение в корзины и распространять эти корзины по нескольким нодам. Мы также построим простой клиент, который позволит подключаться к любому из узлов, а также посылать запросы, такие как:
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.
Давайте уже напишем немного кода!