[連載] Erlangプロジェクトでもmixを使うべきか（１）

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

```
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`に書かれています。

```erlang: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"}}
       ]}.
```

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

```bash
$ ./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は

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

sample_sub2のrebar.configは

```erlang: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`は

```erlang: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_sub1`と`sample_sub2`という**同一階層内**のアプリケーションがcowboyに依存しているため、このアプリケーション全体としてはcowboyをダウンロードせざるを得ません。早速、

```bash
$ ./rebar get-deps
```

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

```erlang: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.config`の`deps`オプションに先に書いた方が優先される**

# まとめ

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


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

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

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

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

**つづく。**