ドリコム社のエントランス

Elixirハンズオン

ドリコム社さんが開催してくださった【サーバーサイド講義&実技】Elixirハンズオンに参加してきました。そこでの感想やElixirの感想などを書こうと思います。

Elixirとは

Elixirは拡張性と保守性の高いアプリケーションを構築するためにデザインされた、動的で関数型のプログラミング言語です。

https://elixir-lang.jp/

ElixirはErlang VM上で動く言語で、フォールトトレランスやホットスワップが可能なErlangをRuby風の言語で利用しようと設計されたものらしいです。
サーバーサイド言語ではPHPしか扱ったことしかなかった私は、Elixirを使ってみたいなぁと思ってたわけですが、Ruby風の記述がどうも苦手で(つまり{}を使わない言語系)、手こずっている間に色々しないといけないことに追われて後回しになっていたのですが、幸いドリコム社さんのElixir ハンズオンに参加させてもらえることになり参加しました。

やったこと

Elixirはmixというパッケージ管理システムを使ってます。
アプリを新規作成するときは
$ mix new test_app
とやります。
こうすることで

test_app
├── README.md
├── config
│   └── config.exs
├── lib
│   └── test_app.ex
├── mix.exs
└── test
    ├── test_app_test.exs
    └── test_helper.exs

と言うような構成になります。
設定ファイルがmix.exs で実際にコードを書くのが lib/test_app.ex らしいです。
mix.exsには依存ライブラリなどの記述をします。

今回のハンズオンでは大量のJSONデータを処理するコードをやりました。
JSONの取扱はPoisonというライブラリを使うらしいのでmix.exsに

  defp deps do
    [
      {:poison, "~> 4.0"},
      # {:dep_from_hexpm, "~> 0.3.0"},
      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
    ]
  end

と記述します。
依存関係をダウンロードするために
test_app $mix deps.get
としてlib/test_app.exのdefmodule test_appの中に

def main do
  json_text = File.stream!("d.json")
  json_data = Enum.map(data, fn d -> Poison.decode!(d) end)
  result = Enum.filter(json_data, fn d -> d["age"] <= 20 end)
  Enum.count(result)
end

と書きtest_app/d.jsonを

{"age":39,"name":"aaa"}
{"age":47,"name":"bbb"}
{"age":46,"name":"ccc"}
{"age":13,"name":"ddd"}
{"age":45,"name":"eee"}
{"age":18,"name":"fff"}
{"age":22,"name":"ggg"}
{"age":15,"name":"hhh"}
{"age":24,"name":"iii"}
...

と置きます。
その後、ターミナルにて
test_app $ iex -S mix
iex(1)>test_app.main
と打つと、20歳以下の人数が出てきます。

さて、Elixirにはパイプ演算子というのがあるらしく、前の関数の返数を第一引数として渡したい時に使えるらしいです。上のコードは以下のように書き直せます。

def main do
  "d.json"
  |> File.stream!
  |> Enum.map(fn d -> Poison.decode!(d) end)
  |> Enum.filter(fn d -> d["age"] <= 20 end)
  |> Enum.count
end

まあ、このように色々教えてもらってEnumじゃなくてStreamやFlow使うと良いよなど教えてもらいました。

感想

Elixir本を読んだときは、「他言語とは違うぞ〜」ということが非常に多く書かれてましたが、ドリコム社さんのおかげでスムーズに理解できました。もちろんElixirの一角だと思いますが、少しずつやっていこうと思います。
ただ、関数っぽい部分とそうでない部分とが妙に突っ掛かると言うか…まあ慣れかな…

あと今回の件で、map=>filterを行いましたが、filter一個でも行けるんじゃないかなと思って少し疑問…具体的には

  def is_adult (json_text) do
    data = Poison.decode!(json_text)
    data["age"] <= 20
  end

  def main do
    "data.json"
    |> File.stream!
    |> Enum.filter(fn d -> is_adult(d) end)
    |> Enum.count
  end

て書いても動くのでどうかな〜と、よく分かってない。
まあ、これからボチボチやっていきます。