2018年12月版mix newした後に必ずやること

私が `$ mix new foo` でライブラリを新規作成したあとに毎回必ずやっていること。
2018年12月現在は以下の4つだ。

- ドキュメント生成ツール ex_doc 追加
- 静的解析ツール dialyxir 追加(型チェック)
- 静的解析ツール credo 追加(Lint)
- フォーマッタで折り返される1行あたりの文字数を120にする

# ドキュメント生成ツール ex_doc

[ex_doc](https://github.com/elixir-lang/ex_doc) は Elixir を用いたプロジェクトのドキュメントを生成してくれるライブラリ。それだけでなく Elixir 自身のドキュメントも ex_doc を用いて出力されている。

## mix.exs に追加する

```diff
diff --git a/mix.exs b/mix.exs
index f6d766a..d18402d 100644
--- a/mix.exs
+++ b/mix.exs
@@ -21,8 +21,7 @@ defmodule Foo.MixProject do
   # 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"},
+      {:ex_doc, "~> 0.19", only: :dev, runtime: false}
     ]
   end
 end
```

## 使う

`mix deps.get` と `mix deps.compile` の両方を行ってからでないと `mix docs` コマンドが出てこないので注意すること。

```shell
$ mix deps.get
$ mix deps.compile
$ mix docs
Compiling 1 file (.ex)
Generated foo app
Docs successfully generated.
View them at "doc/index.html".
```

`doc/index.html` を開くと

<img width="941" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/20546/eef3092c-76fb-3dd2-9026-8eea99e8495c.png">

このようなドキュメントが表示できる。

# 静的解析ツール dialyxir

[dialyxir](https://github.com/jeremyjh/dialyxir) は ErlangVM 向け静的解析ツール [dialyzer](http://erlang.org/doc/man/dialyzer.html) を mix コマンドから簡潔に使えるようにしたもの。

## mix.exs に追加する

```diff
diff --git a/mix.exs b/mix.exs
index d18402d..5f588ae 100644
--- a/mix.exs
+++ b/mix.exs
@@ -21,7 +21,8 @@ defmodule Foo.MixProject do
   # Run "mix help deps" to learn about dependencies.
   defp deps do
     [
-      {:ex_doc, "~> 0.19", only: :dev, runtime: false}
+      {:ex_doc, "~> 0.19", only: :dev, runtime: false},
+      {:dialyxir, "~> 1.0.0-rc.4", only: :dev, runtime: false}
     ]
   end
 end
```

## 使う

`mix deps.get` と `mix deps.compile` の両方を行ってからでないと `mix dialyzer` コマンドが出てこないので注意すること。

`mix dialyzer` は初回実行にすごく時間がかかる。これはそういうものなのであきらめよう。2回目以降は1回目に生成したPLTと呼ばれるキャッシュを利用するのでかなり改善される。

```shell
$ mix deps.get
$ mix deps.compile
$ time mix dialyzer
Total errors: 0, Skipped: 0
done (passed successfully)
      337.91 real       805.19 user        41.86 sys
$ time mix dialyzer
Total errors: 0, Skipped: 0
done in 0m1.02s
done (passed successfully)
        1.62 real         1.70 user         0.32 sys
```

誤りを検出した場合にどう動作するか

`lib/foo/foo.ex` を以下のように書き換えて試す。`add` という関数を追加した。
Elixir 界では `+` が使えるのは `number` 型のみなのでエラーが検出できるはず。

```elixir
defmodule Foo do
  @moduledoc """
  Documentation for Foo.
  """

  @doc """
  Hello world.

  ## Examples

      iex> Foo.hello()
      :world

  """
  def hello do
    result = add("x", "y")
    :world
  end

  def add(a, b) do
    a + b
  end
end
```

```shell
$ mix dialyzer
Total errors: 2, Skipped: 0
done in 0m1.18s
lib/foo.ex:15:no_return
Function hello/0 has no local return.
________________________________________________________________________________
lib/foo.ex:16:call
The call:
Foo.add("x", <<_::8>>)

will never return since it differs in arguments with
positions 1st and 2nd from the success typing arguments:

(number(), number())
________________________________________________________________________________
done (warnings were emitted)
```

Foo.add の引数の型は `number()` と `number()` であるはずだと言われている。
うまく動作しているようだ。

(`lib/foo/foo.ex` を元に戻す)

# 静的解析ツール credo

[credo](https://github.com/rrrene/credo) も先程の dialyxir と同様に静的解析ツールだ。ただ着目しているところが異なり credo はコードの一貫性を保つことや、より望ましいコードとなるよう手引きするためにある。いわゆる Lint ツールだ。

## mix.exs に追加する

```diff
diff --git a/mix.exs b/mix.exs
index 5f588ae..ad6948a 100644
--- a/mix.exs
+++ b/mix.exs
@@ -22,7 +22,8 @@ defmodule Foo.MixProject do
   defp deps do
     [
       {:ex_doc, "~> 0.19", only: :dev, runtime: false},
-      {:dialyxir, "~> 1.0.0-rc.4", only: :dev, runtime: false}
+      {:dialyxir, "~> 1.0.0-rc.4", only: :dev, runtime: false},
+      {:credo, "~> 1.0.0", only: :dev, runtime: false}
     ]
   end
 end
```

## 使う

`mix deps.get` と `mix deps.compile` の両方を行ってからでないと `mix credo` コマンドが出てこないので注意すること。

```shell
$ mix deps.get
$ mix deps.compile
$ mix credo
Checking 3 source files ...

Please report incorrect results: https://github.com/rrrene/credo/issues

Analysis took 0.1 seconds (0.01s to load, 0.1s running checks)
3 mods/funs, found no issues.

Use `--strict` to show all issues, `--help` for options.
```

mix credo するとき、[チェック設定を `.credo.exs` というファイルから自動的に読み込んでくれる](https://github.com/rrrene/credo#configuration-via-credoexs)。ファイルを置ける有効な場所はルートディレクトリか、`config/` だ。昨今のルートディレクトリは様々な物が置かれて混雑するので、私は `config/` に置いている。

またそのチェック設定のファイルを `mix credo.gen.config` で生成できる。

そこで生成して `config/` に置く。

```shell
$ mix credo.gen.config
$ mv .credo.exs config/
```

望ましくないコードを検出したらどう動くか。

`lib/foo/foo.ex` を以下のように書き換えて試す。`@moduledoc` という、モジュールに対するドキュメントを取り去った。

```elixir
defmodule Foo do
  @doc """
  Hello world.

  ## Examples

      iex> Foo.hello()
      :world

  """
  def hello do
    :world
  end
end
```

そうすると

```shell
$ mix credo
Checking 3 source files ...

  Code Readability
┃
┃ [R] → Modules should have a @moduledoc tag.
┃       lib/foo.ex:1:11 #(Foo)

Please report incorrect results: https://github.com/rrrene/credo/issues

Analysis took 0.1 seconds (0.00s to load, 0.1s running checks)
3 mods/funs, found 1 code readability issue.
```

という形式で望ましくない部分が検出される。

(`lib/foo/foo.ex` を元に戻す)

# フォーマッタで折り返される1行あたりの文字数を120にする

Elixir1.6 からはフォーマッタが標準添付されており `mix format` でフォーマットできる。デフォルト時に何文字で折り返すかは [Code.format_string!/2](https://hexdocs.pm/elixir/1.7/Code.html#format_string!/2) に書かれているとおり 98 文字だ。私はこれだと少し短く感じたので 120 文字にしている。120 文字は credo で文字の横幅が長すぎるときに出すデフォルト値でもあるので丁度よい。

1行あたりの文字数、他にどんな候補があるかは [Elixirでは行の最大長をいくつにするべきか](https://qiita.com/niku/items/2e25823cf1198fce45f9) をみてほしい。

変更するには `.formatter.exs` に設定を追加すればよい。

```diff
diff --git a/.formatter.exs b/.formatter.exs
index d2cda26..0a70dc0 100644
--- a/.formatter.exs
+++ b/.formatter.exs
@@ -1,4 +1,5 @@
 # Used by "mix format"
 [
-  inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
+  inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"],
+  line_length: 120
 ]
```