Elmのモジュールを作るときはどういうとき
モジュールを作るとき
いきなりですがこの動画を見てください。この動画はElmの作者のEvanさんによる発表です。
まず見て驚くのはElmの場合、一つのファイルに対してプログラムを育てていくことではないでしょうか。通常システムを作るときには責務を切り分けて責務ごとにモジュールを作成することが結果的にファイル分割につながっていました。
Elmでも同様にElm ArchitectureによりModel, Update, Subscribe, Viewにシステムが分割されています。しかし単一の責務ごとにモジュールを作成することなく一つのファイルにアプリケーションを構築していきます。
この発表いわく通常それは400から1000行くらいのコードまで成長するそうです。そのあたりからモジュール作成の兆しが訪れることが述べられています。
Modelの構築の仕方に習っていくと新しいCustom Typeを作る機会が訪れます。まずはそのCustom Typeを作成して、そのCustom Typeにまつわる関数を作ります。
こうしてできたCustom Typeとそれにまつわる関数を別モジュールに切り出します。これがElmにおけるモジュール作成のタイミングと作成方法です。
このことはドキュメントにまとまっています。
Modules · An Introduction to Elm
モジュールの変更による影響範囲を閉じ込める
またいきなりですがこの動画を見てください。この動画はEvanさんの同僚NoRedInkで働くRichardさんの発表です。
動画で述べられている通りModelに依存しているシステムは多いのでModelの変更は影響が多岐にわたることが多いです。これをModel内の変更に留めるにはどうするといいでしょうか?
積極的にOpaque Typeを使うことを主張しています。Opaque Typeについては下記の記事が参考になります。
Advanced Types in Elm - Opaque Types – Charlie Koster – Medium
Elm PackagesのAPI Documentにも記述があります。
適切なインターフェース (関数) を作成し、exposingで公開するものを絞り込むことで変更をモジュールに閉じ込めることができます。
module Post exposing (Post, fromDoc) type Post = Post doc fromDoc : doc -> Post fromDoc = Post
やりすぎないこと
Evanさんはやりすぎないことを注意としています。Custom Typeによるモジュール化を進めると最初のうちから再利用を意識して同じロジックをまとめたがります。
そんなときには一呼吸おいて問題が起きてから対処するようにしましょう。例えばページによって同じCustom Typeでもデータ構造が異なることがあります。
module PageX exposing (..) type Doc = Doc Title Content type alias Title = String type alias Content = String
module PageY exposing (..) type Doc = Doc { title : String , content : String , description : String }
早い段階から共通化を見越して過剰に手を加えるのではなく実際に重複するロジックが出てくるまで待ってみましょう。
共通したデータ構造があるのならコードを改善してシェアしましょう。このようにElmでは作っていく最中に発見してリファクタリングを積極的に繰り返すことを勧めているように感じます。
それは強力な型と言語設計によりリファクタリングをしやすい環境が整っているからでしょう。
サマリ
- Elmでは必要な時が来るまでモノリシックなモジュールでアプリケーションを育てていく
- カスタムタイプが増えてヘルパー関数ができたときがモジュールを作るサイン
- モジュールはカスタムタイプに対する責任を持つ
- Opaque Typeを積極的に使い影響範囲をなるべくモジュール内に限定する
- 過度なモジュール化はすべきではないリファクタリングすることを念頭に置く
所感
今回はElmのモジュールについて記事にしました。Elmではこのような思想がありますが、一つのファイルで1000行もコードを書いていてはチーム開発をしているとコンフリクトが多発しそうですね。
また、モジュールの作り方にこのような指針がないとチームで開発ではこの関数はどのモジュールに属するのがいいのか迷ってしまうシーンがあります。
JavaScriptとは異なるモジュールの作成プロセスですが、Elmではこのようなプロセスをおすすめしていることを紹介しました。