モジュール分割の判断基準
https://guide.elm-lang.jp/webapps/modules.html
アプリケーションが複雑になれば、それにつれてモジュールにもいろいろ追加が必要になります。もちろん、そうやってモジュールを拡張していって行数が増えること自体は問題ありません。Elmにとってモジュールの行数が400行から1000行くらいになるのはふつうのことです。それについてはThe Life of a Fileという動画で説明しています。ですから行数が増えること自体は問題ないのですが、「モジュールが複数ある場合にどこに新しいコードを追加するか」という問いが生まれます。
この問いへの答えとして、私は追加するコードの特性によって以下のような経験則で判断しています。
-
コードがその場所でしか使われていないとき — もしもそのロジックがそこでしか使われていないのであれば、私はそのロジックを独立したトップレベルの補助関数として抜き出します。そしてその関数を利用している箇所となるべく近い所に置きます。その際、
-- POST PREVIEW
(この下に投稿の表示に関わる定義が書かれてるよ)といった見出しをコメントで付けることもあります。
-
似たようなコードがあるとき — 例として投稿をあらわす
Post
をトップページと投稿者のページに表示することを考えましょう。トップページでは内容に興味を持ってもらうことを重視して、長めの抜粋を表示します。一方で投稿者のページでは幅広い内容の記事を書いていることを示すために、タイトルが目立つようにします。そう考えると、これらは同じコードではなく、似ているだけのコードだと言えます。ですから「コードがその場所でしか使われていないとき」の経験則にしたがいましょう。単に別々の独立したコードとしてそれぞれのロジックを実装すれば良いのです。
-
コードがまったく同じとき — 「コードがその場所でしか使われていないとき」の経験則にしたがってコードを管理していると、そのうち同じコードが複数箇所にあらわれてきます。それ自体は悪いことではありません! でももしかしたらその中に完全に同じ意味合いを持つ同じ内容のコードが見つかるかもしれません。そうなって初めて、そのロジックを共通の補助関数としてくくりだせばいいのです! 例えばその補助関数が記事を読むためにかかる時間を導出する関数なら、
-- READ TIME
(読むのにかかる時間)といった見出しをコメントとしてつけておいても構いません。もしそのロジックを使っているモジュールが1つだけなら、やることはたったそれだけです。
さて、ここで紹介した方法はどれも1つのファイル内に補助関数を作るものばかりです。新しいモジュールを作ったりはしていません。ではどんなときに新しいモジュールを作るべきなのでしょうか? それは、上記の経験則にしたがって抜き出した補助関数のうちいくつかが全て特定のカスタム型に関わるものだった場合です。ですから、例えば投稿者ページを管理するPage.Author
モジュールを作り始めたら、Post
型に関連した補助関数が十分に溜まるまではPost
モジュールを作りません。そこまでちゃんと我慢してからPost
モジュールを作ったのであれば、コードはより流れを追いやすく、また理解しやすくなっているはずです。逆にもしもPost
モジュールを作ったのにそういった効果が得られなかったとしたら、それはまだその時期でなかったということです。モジュールを作る前の、もっとコードがわかりやすかった時代のものに戻しましょう。このように、なんでもモジュールをたくさん作ればいいというわけではありません! 「コードをシンプルで分かりやすく保つ」という初心を忘れないことです。
話が長くなったので一旦整理しましょう。まず似ているコードがあっても、それぞれ別の独立したコードであると見なします。こういう似て非なるコードはだいたいユーザーインターフェイスに関わる部分で発生するものです。次に、もし完全に同じロジックが別々の場所にあるのを見つけたら、そこで初めて共通の補助関数としてそのロジックをくくりだします。この際、内容が分かるように見出しをコメントで付けておいてもいいでしょう。そして最後に、そういった補助関数の中に同じ特定の型に関するものがいくつか見つかったら、そこで初めて新しくモジュールを作るべきか検討するのです。そうすることでコードが分かりやすくなるなら万々歳。そうでないならもとに戻しましょう。ファイルがたくさんあることと、コードがシンプルで分かりやすいことは、本質的に異なるのです。
モジュールについて失敗するよくあるケースは、最初同じだったものが後から似ているコードに変わってしまう場合です。こういう事件はユーザーインターフェイスに関わる部分で本当によく起きます! そうして気付けば、様々なケースに対応するためにつぎはぎだらけのおぞましい関数を作り出してしまっているのです。「引数が足りなぁ〜い!」「こんな単純な引数じゃ制御しきれない! もっと複雑怪奇にしなくては……」。マッドサイエンティストのうめき声がこだまします。そんな狂気の改造手術をやめて、2つの独立した別々のコードがあるという状況を許容しましょう。それぞれの場所に同じコードをコピーすることを受け入れるのです。そうすることで余計な条件分岐などを書かずに済み、本業に集中できます。その結果全く同じロジックが出てきたら、その段階になって初めて共通の補助関数としてくくりだせば良いのです。そうすれば長大な関数は複数の小さな関数に分割されます。無駄な分岐処理が入って複雑になることはありません。