6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[連載] Erlangプロジェクトでもmixを使うべきか(1)

Last updated at Posted at 2015-04-30

#はじめに
あるアプリケーションが他のアプリケーション群に依存し、またそれらのアプリケーション群が各々さらに別のアプリケーション群に依存するようなとき、一般に「依存アプリケーションのバージョン管理」や「依存パッケージのバージョン管理」と呼ばれるような一連の問題が起こります。

main
  ├──app1
  |   ├─app2(ver.1)
  |   └─app3(ver.1)
  └──app2(ver.2)
      └─app3(ver.2)

上図ではmainのアプリケーションの子にあたるapp1とapp2がそれぞれ別バージョンのapp3を要求していますし、app2は子と孫の位置で別バージョンを要求しています。

こういった場合、同じアプリケーションの別バージョンを取り込むのは非効率なのでどれかのアプリケーションが依存するバージョンを取り込んで共有して使うことになります。しかし、依存アプリケーションが特定のバージョンでないと正常動作しないアプリケーションはままありますね。そうなると、どこかの依存アプリケーションが異常動作を起こし、その異常はアプリケーション全体にまで広がります。

この連載では、Erlangの標準的なビルドツールrebarの依存アプリケーション管理方法と、Elixirのビルドツールであるmixの依存アプリケーション管理方法を比較し、Erlag/Elixir系においてあるべきパッケージ管理方法を考察します。

#rebarでのバージョン衝突解決

メイン/サブ・アプリケーションの依存パッケージ衝突回避

まずメインのアプリケーションがあります。こんな感じの。

https://github.com/massn/sample_main/tree/v0.0.1

このメイン・アプリケーションが依存するアプリケーションはrebar.configに書かれています。

rebar.config
{deps, [
         {sample_sub1, ".*", {git, "https://github.com/massn/sample_sub1.git", "v0.0.1"}},
         {sample_sub2, ".*", {git, "https://github.com/massn/sample_sub2.git", "v0.0.1"}},
         {cowboy, ".*", {git, "https://github.com/ninenines/cowboy.git", "0.9.0"}}
       ]}.

早速、依存アプリケーションをダウンロードしてみましょう。

$ ./rebar get-deps

結果、depsディレクトリは以下のようになります。

deps
  ├──cowboy(0.0.9)
  ├──cowlib(0.4.0)
  ├──ranch(0.9.0)
  ├──sample_sub1(v0.0.1)
  └──sample_sub2(v0.0.1)

ここではメイン・アプリケーションの要求通りcowboyというアプリケーションの0.0.9が取り込まれていますが、実はsample_sub1、sample_sub2もcowboyを要求しています。

sample_sub1のrebar.configは

rebar.config
{deps, [
         {cowboy, ".*", {git, "https://github.com/ninenines/cowboy.git", "0.8.0"}}
        ]}.

sample_sub2のrebar.configは

rebar.config
{deps, [
         {cowboy, ".*", {git, "https://github.com/ninenines/cowboy.git", "0.10.0"}}
        ]}.

となっています。
つまりサブ・アプリケーションは別バージョンを指し示していても、メイン・アプリケーションのバージョン指定があった場合は後者が優先されるということです。つまり、

メイン・アプリケーションとサブ・アプリケーションの依存パッケージが別バージョンの場合は、メイン・アプリケーションのものが優先される

同一階層内の依存パッケージ衝突回避

では、メイン・アプリケーションが依存せず、複数のサブ・アプリケーションが依存するアプリケーションが異なるバージョンを指定していた場合、どのバージョンが選ばれるのでしょう?

https://github.com/massn/sample_main/tree/v0.0.2

rebar.config

rebar.config
{deps, [
         {sample_sub1, ".*", {git, "https://github.com/massn/sample_sub1.git", "v0.0.1"}},
         {sample_sub2, ".*", {git, "https://github.com/massn/sample_sub2.git", "v0.0.1"}}
       ]}.

となっておりcowboyに依存していません。
しかし、sample_sub1sample_sub2という同一階層内のアプリケーションがcowboyに依存しているため、このアプリケーション全体としてはcowboyをダウンロードせざるを得ません。早速、

$ ./rebar get-deps

すると、depsにはcowboyの__0.9__がダウンロードされています。つまり、sample_sub1が依存するバージョンが優先されたわけですね。ということは、、、。
rebar.configを以下のように書き換えてみましょう(https://github.com/massn/sample_main/tree/v0.0.3)。

rebar.config
{deps, [
          {sample_sub2, ".*", {git, "https://github.com/massn/sample_sub2.git    ", "v0.0.1"}},
          {sample_sub1, ".*", {git, "https://github.com/massn/sample_sub1.git    ", "v0.0.1"}}
      ]}.

このようにサブ・アプリケーションの順番を換えてみて./rebar get-depsしてみると、今度は__0.10__がダウンロードされています。つまり、

同一階層内のアプリケーションが同じアプリケーションに依存している場合は、rebar.configdepsオプションに先に書いた方が優先される

まとめ

まとめますと、rebarには2つの依存アプリケーション管理原則があるようです。再掲します。

  1. 同一階層内のアプリケーションが同じアプリケーションに依存している場合は、rebar.configdepsオプションに先に書いた方が優先される

  2. メイン・アプリケーションとサブ・アプリケーションの依存パッケージが別バージョンの場合は、メイン・アプリケーションのものが優先される

1の原則を意識するとアプリケーションが依存するすべてのアプリケーションを知らなくてはなりません(子アプリケーションの子アプリケーション。そのまた子アプリケーション。そのまた・・・。)。2の原則を意識するにはすべての依存アプリケーションのバージョンを知らなくてはならない。

これ、なかなかしんどいですよね?

つづく。

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?