Spec-Zone.ru › Elixir 1.17

Источник Зависимости и проекты-зонтики

В этой главе мы обсудим, как управлять зависимостями в Mix.

Наш kv проект завершен, поэтому пришло время реализовать сервер, который будет обрабатывать запросы, определенные в первой главе:

CREATE shopping
OK

PUT shopping milk 1
OK

PUT shopping eggs 3
OK

GET shopping milk
1
OK

DELETE shopping eggs
OK

Однако вместо добавления дополнительного кода в kv приложение, мы собираемся создать TCP-сервер как другое приложение, которое является клиентом kv приложения. Поскольку весь запуск и экосистема Elixir ориентированы на приложения, имеет смысл разбить наши проекты на меньшие приложения, которые работают вместе, а не создавать одно большое, монолитное приложение.

Прежде чем создавать наше новое приложение, мы должны обсудить, как Mix обрабатывает зависимости. На практике мы обычно работаем с двумя типами зависимостей: внутренними и внешними. Mix поддерживает механизмы работы с обоими типами.

Внешние зависимости

Внешние зависимости — это те, которые не связаны с вашей предметной областью. Например, если вам нужен HTTP-API для вашего распределенного приложения KV, вы можете использовать проект Plug как внешнюю зависимость.

Установка внешних зависимостей проста. Чаще всего мы используем Hex Package Manager, указав зависимость внутри функции deps в нашем mix.exs файле:

def deps do
  [{:plug, "~> 1.0"}]
end

Эта зависимость относится к последней версии Plug в серии версий 1.x.x, которая была загружена в Hex. Это обозначено ~> перед номером версии. Дополнительную информацию о задании требований к версиям см. в документации модуля Version.

Обычно стабильные релизы загружаются в Hex. Если вы хотите зависеть от внешней зависимости, которая все еще находится в разработке, Mix может управлять зависимостями Git:

def deps do
  [{:plug, git: "https://github.com/elixir-lang/plug.git"}]
end

Вы заметите, что при добавлении зависимости в проект Mix генерирует файл mix.lock, гарантирующий повторяемость сборки. Файл блокировки необходимо включить в систему управления версиями, чтобы гарантировать, что все, кто использует проект, будут использовать те же версии зависимостей, что и вы.

Mix предоставляет множество задач для работы с зависимостями, которые можно увидеть в mix help:

$ mix help
mix deps              # Lists dependencies and their status
mix deps.clean        # Deletes the given dependencies' files
mix deps.compile      # Compiles dependencies
mix deps.get          # Gets all out of date dependencies
mix deps.tree         # Prints the dependency tree
mix deps.unlock       # Unlocks the given dependencies
mix deps.update       # Updates the given dependencies

Наиболее распространенными задачами являются mix deps.get и mix deps.update. После получения зависимости автоматически компилируются для вас. Вы можете узнать больше о deps, набрав mix help deps, и в документации модуля Mix.Tasks.Deps.

Внутренние зависимости

Внутренние зависимости — это те, которые специфичны для вашего проекта. Обычно они не имеют смысла за пределами вашего проекта/компании/организации. Чаще всего вы хотите сохранить их конфиденциальными, будь то по техническим, экономическим или бизнес-причинам.

Если у вас есть внутренняя зависимость, Mix поддерживает два метода работы с ними: репозитории Git или проекты-зонтики.

Например, если вы загрузите kv проект в репозиторий Git, вам нужно будет указать его в вашем коде deps, чтобы использовать его:

def deps do
  [{:kv, git: "https://github.com/YOUR_ACCOUNT/kv.git"}]
end

Однако, если репозиторий приватный, вам может потребоваться указать приватный URL git@github.com:YOUR_ACCOUNT/kv.git. В любом случае, Mix сможет его получить, если у вас есть соответствующие учетные данные.

Использование репозиториев Git для внутренних зависимостей несколько не рекомендуется в Elixir. Помните, что среда выполнения и экосистема Elixir уже предоставляют понятие приложения. Поэтому мы ожидаем, что вы будете часто разбивать свой код на приложения, которые могут быть логически организованы, даже в рамках одного проекта.

Однако, если вы загружаете каждое приложение как отдельный проект в репозиторий Git, ваши проекты могут стать очень сложными для поддержки, так как вы потратите много времени на управление этими репозиториями Git вместо написания кода.

По этой причине Mix поддерживает «проекты-зонтики». Проекты-зонтики используются для сборки приложений, которые работают вместе в одном репозитории. Именно этот подход мы собираемся изучить в следующих разделах.

Давайте создадим новый проект Mix. Мы творчески назовем его kv_umbrella, и этот новый проект будет содержать как существующее kv приложение, так и новое kv_server приложение. Структура каталогов будет такой:

+ kv_umbrella
  + apps
    + kv
    + kv_server

Интересно то, что Mix имеет много удобств для работы с такими проектами, например, возможность компилировать и тестировать все приложения внутри apps одной командой. Однако, хотя все они перечислены вместе внутри apps, они все равно де-связаны друг от друга, поэтому вы можете собирать, тестировать и развертывать каждое приложение изолированно, если захотите.

Итак, давайте начнем!

Проекты-зонтики

Давайте начнём новый проект, используя mix new. Этот новый проект будет называться kv_umbrella и нам нужно будет указать --umbrella параметр при его создании. Не создавайте этот новый проект внутри существующего kv проекта!

$ mix new kv_umbrella --umbrella
* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating apps
* creating config
* creating config/config.exs

Из выведенной информации видно, что генерируется гораздо меньше файлов. Также отличается сгенерированный файл mix.exs. Давайте посмотрим (комментарии удалены):

defmodule KvUmbrella.MixProject do
  use Mix.Project

  def project do
    [
      apps_path: "apps",
      start_permanent: Mix.env() == :prod,
      deps: deps()
    ]
  end

  defp deps do
    []
  end
end

Что отличает этот проект от предыдущего, это запись apps_path: "apps" в определении проекта. Это означает, что этот проект будет работать как зонтик. Такие проекты не имеют файлов исходного кода и тестов, хотя у них могут быть свои зависимости. Каждое дочернее приложение должно быть определено внутри каталога apps.

Давайте перейдём в каталог apps и начнём создание kv_server. На этот раз мы собираемся передать флаг --sup, который сообщит Mix сгенерировать дерево надзора автоматически, вместо того, чтобы создавать его вручную, как мы делали в предыдущих главах:

$ cd kv_umbrella/apps
$ mix new kv_server --module KVServer --sup

Сгенерированные файлы похожи на те, которые мы генерировали для kv, с некоторыми отличиями. Давайте откроем mix.exs:

defmodule KVServer.MixProject do
  use Mix.Project

  def project do
    [
      app: :kv_server,
      version: "0.1.0",
      build_path: "../../_build",
      config_path: "../../config/config.exs",
      deps_path: "../../deps",
      lockfile: "../../mix.lock",
      elixir: "~> 1.14",
      start_permanent: Mix.env() == :prod,
      deps: deps()
    ]
  end

  # Run "mix help compile.app" to learn about applications
  def application do
    [
      extra_applications: [:logger],
      mod: {KVServer.Application, []}
    ]
  end

  # Run "mix help deps" to learn about dependencies
  defp deps do
    [
      # {:dep_from_hexpm, "~> 0.3.0"},
      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
      # {:sibling_app_in_umbrella, in_umbrella: true},
    ]
  end
end

Во-первых, так как мы сгенерировали этот проект внутри kv_umbrella/apps, Mix автоматически обнаружил структуру зонтика и добавил четыре строки в определение проекта:

build_path: "../../_build",
config_path: "../../config/config.exs",
deps_path: "../../deps",
lockfile: "../../mix.lock",

Эти параметры означают, что все зависимости будут получены в kv_umbrella/deps, и они будут использовать те же файлы сборки, конфигурации и блокировки. Мы ещё не говорили о конфигурации, но отсюда мы можем предположить, что вся конфигурация и зависимости разделяются между всеми проектами в зонтике, а не по отдельным приложениям.

Второе изменение — в функции application внутри mix.exs:

def application do
  [
    extra_applications: [:logger],
    mod: {KVServer.Application, []}
  ]
end

Так как мы передали флаг --sup, Mix автоматически добавил mod: {KVServer.Application, []}, указав, что KVServer.Application — это наш модуль обратного вызова приложения. KVServer.Application запустит наше дерево надзора приложения.

Давайте откроем lib/kv_server/application.ex:

defmodule KVServer.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  @impl true
  def start(_type, _args) do
    # List all child processes to be supervised
    children = [
      # Starts a worker by calling: KVServer.Worker.start_link(arg)
      # {KVServer.Worker, arg},
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: KVServer.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

Обратите внимание, что он определяет функцию обратного вызова приложения, start/2, и вместо определения надзирателя с именем KVServer.Supervisor, который использует модуль Supervisor, он удобно определил надзирателя в строке! Вы можете узнать больше об этих надзирателях, прочитав документацию модуля Supervisor.

Мы уже можем опробовать наше первое дочернее приложение зонтика. Мы могли бы запустить тесты внутри каталога apps/kv_server, но это не очень интересно. Вместо этого перейдите в корень проекта зонтика и запустите mix test:

$ mix test

И всё работает!

Поскольку мы хотим, чтобы kv_server в конечном итоге использовал функциональность, определённую в kv, нам нужно добавить kv в качестве зависимости нашего приложения.

Зависимости внутри проекта-зонтика

Зависимости между приложениями в проекте-зонтике всё ещё должны быть явно определены, и Mix упрощает это. Откройте apps/kv_server/mix.exs и измените функцию deps/0 следующим образом:

defp deps do
  [{:kv, in_umbrella: true}]
end

Строка выше делает :kv доступной в качестве зависимости внутри :kv_server и автоматически запускает приложение :kv перед запуском сервера.

Наконец, скопируйте kv приложение, которое мы построили до этого момента, в каталог apps в нашем новом проекте зонтика. Конечная структура каталогов должна соответствовать структуре, которую мы упомянули ранее:

+ kv_umbrella
  + apps
    + kv
    + kv_server

Теперь нам нужно изменить apps/kv/mix.exs так, чтобы он содержал записи зонтика, которые мы видели в apps/kv_server/mix.exs. Откройте apps/kv/mix.exs и добавьте в функцию project/0:

build_path: "../../_build",
config_path: "../../config/config.exs",
deps_path: "../../deps",
lockfile: "../../mix.lock",

Теперь вы можете запускать тесты для обоих проектов из корня проекта зонтика с помощью mix test. Отлично!

Не плывите по течению

Проекты-зонтики — это удобство для организации и управления несколькими приложениями. Хотя он обеспечивает определённую степень разделения между приложениями, эти приложения не полностью де-связаны, так как они используют общую конфигурацию и те же зависимости.

Шаблон хранения нескольких приложений в одном репозитории известен как «моно-репозиторий». Проекты-зонтики максимизируют этот шаблон, предоставляя удобства для компиляции, тестирования и запуска нескольких приложений одновременно.

Если вы обнаружите, что вам нужно использовать разные конфигурации в каждом приложении для одной и той же зависимости или использовать разные версии зависимостей, то, скорее всего, ваш код перерос возможности зонтиков.

Хорошая новость заключается в том, что разделить зонтик довольно просто, так как вам просто нужно переместить приложения за пределы каталога apps/ проекта зонтика и обновить файл mix.exs проекта, чтобы больше не устанавливать конфигурацию build_path, config_path, deps_path, и lockfile. Вы можете зависеть от приватных проектов за пределами зонтика различными способами:

  1. Переместите его в отдельную папку в том же репозитории и укажите на нее с помощью зависимости пути (шаблон моно-репозитория)
  2. Переместите репозиторий в отдельный Git-репозиторий и используйте его как зависимость
  3. Опубликуйте проект в частную организацию Hex.pm

Подведение итогов

В этой главе мы узнали больше о зависимостях Mix и проектах-зонтиках. Хотя мы можем запустить kv без сервера, наша kv_server напрямую зависит от kv. Разделив их на отдельные приложения, мы получаем больший контроль над их разработкой и тестированием.

При использовании приложений-зонтиков важно иметь четкую границу между ними. Наш будущий kv_server должен получать доступ только к общедоступным API, определённым в kv. Представьте ваши приложения-зонтики как любые другие зависимости, или даже сам Elixir: вы можете получить доступ только к тому, что является общедоступным и документированным. Доступ к закрытым функциям ваших зависимостей — плохая практика, которая в конечном итоге приведёт к поломке вашего кода при обновлении до новой версии.

Приложения-зонтики также могут служить промежуточным этапом для последующей экстракции приложения из вашего кода. Например, представьте себе веб-приложение, которое должно отправлять "push-уведомления" своим пользователям. Вся "система push-уведомлений" может быть разработана как отдельное приложение в зонтике со своей собственной системой надзора и API. Если в будущем другому проекту понадобится система push-уведомлений, ее можно переместить в частный репозиторий или пакет Hex.

Наконец, помните, что все приложения в проекте-зонтике используют одни и те же конфигурации и зависимости. Если два приложения в вашем зонтике должны настраивать одну и ту же зависимость совершенно по-разному или даже использовать разные версии, значит, вы, вероятно, вышли за рамки преимуществ, предоставляемых зонтиками. Помните, что вы можете разбить зонтик и при этом использовать преимущества "моно-репозиториев".

Теперь, когда наш проект-зонтик запущен, пришло время начать писать наш сервер.

← Предыдущая страница Ускорение с ETS
Следующая страница → Задачи и gen_tcp

Скачать версию ePub

Создано с помощью ExDoc (v0.34.1) для языка программирования Elixir

© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.17.2/dependencies-and-umbrella-projects.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API