M

コロケーション

Jan 14, 2023

これは、Kent C. Dodds 氏のブログ記事であるColocationを日本語訳してみたものです。

誤訳などあればIssueや PR を頂けると幸いです。


誰もがコードベースをメンテナンスしやすい状態に保ちたいので、コードベース(もしくはその一角)をメンテナンスしやすく理解しやすくなるように最善の努力を持って始めます。 時が経って、コードベースが大きくなるにつれて、依存関係(JS、CSS、画像など)を管理するのは、より一層難しくなります。 プロジェクトが大きくなるにつれて、コードベースが"チーム固有の知識"(あなたや他の数名に限られた知識)になってしまうことは往々にしてあり、 このような知識が”技術的負債”(言葉の正確性はともかく)の原因となります。

私は、コードベースを私自身(筆者)だけではなくチームメンバー、未来のメンテナー、そして半年後の自分自身にも扱いやすい状態に保ちたいです。これがコードベースにおける目指すべき状態であることについて誰もが同意するものと、私は考えています。 その実現のために、さまざまなツールやテクニックが存在します。

コードコメントについて話しましょう

私は、コメントを書く(べき)かについてだったり、コメントがどうあるべきか(予想外のことをする理由をコメントで記述して、後から来る人に予想外なコードや奇妙なコードができあがった決定について理解できるようにする)について議論したくありません。 (OK、少しは話したかったのかもしれません)。その代わりに、コードコメントをどこに配置するかについて焦点を当てたいと思います。私たちは一般的に、可能な限りコメントが説明しているコードに近い場所に”コロケーションします”。

異なる形にしたらどうか、少し考えてみてください。このようなコードコメントを完全に別のファイルへ配置したらどうでしょうか。大量の DOCUMENTATION.mddocs/ ディレクトリが src/ディレクトリにマッピングされます。 面白そうですか?そうですね、私も面白く感じません。説明するコードに対してコメントをコロケーションしないことで、いくつかの深刻な問題に直面します。

  • メンテナビリティ: (今以上に)より早く同期が取れず、古い状態になりやすいでしょう。対応する docs/ のファイルを更新することなく src/ のファイルを移動したり、削除したりするようになるでしょう。
  • 適用性: src/ のコードを見ている人が、src/ のファイルに対する docs/ のファイルがあることに気付かず、 docs/ の重要なコメントを見逃したり、コメントを書かなかったりするかもしれません。
  • 使いやすさ: このような設定では、ある場所から別のところへのコンテキストスイッチが難しいでしょう。ファイルが複数の場所で扱われると、コンポーネントをメンテナンスするのに必要なものを把握することが難しくなります。

確かにこのようなコードコメントのスタイルの規約を作ることはできますが、そうしたいでしょうか? コメントは、説明するコードの近くにコロケーションしておく方がよりシンプルではないでしょうか?

それがどうしたというのか?

さて、おそらくあなたはこう思っていることでしょう: ”そうですね、だから皆 docs/ のようなものではなくてコードとコメントをコロケーションするようにしています。それは分かりきったことです。言いたいことは何なのですか?” と。 私が主張したいのは、コロケーションの利点はどこにでもあるということです。

HTML/View

HTML を例にとってみましょう。コメントのコロケーションの利点はテンプレートに対しても全て適用されます。React のようなモダンなフレームワークの以前は、ビューロジックやビューのテンプレートを完全に分離していました。 この場合、上述の問題が発生します。例えば React や Vue においてはこれらを 完全に同じファイルに 記述することが、最近ではより一般的になっています。Angular では、テンプレートファイルを同じファイルではなくても、少なくとも関連するファイルのすぐ近くに置きます。

CSS

この概念について、よく当てはまるのが CSS です。CSS-in-JS(ファンタスティックですね)のメリットについてここで議論するつもりはありませんが、得られるものはこの世のものとは思えません。 詳しくはこちらを確認してください

テスト

ユニットテストについてもファイルのコロケーションの考え方が良く当てはまります。 src/ ディレクトリと src/ ディレクトリをミラーすることを試みたユニットテストのファイルでいっぱいの test/ ディレクトリとを持つプロジェクトは、 よくあるものでしょうか? 上述の落とし穴がここにもあるのです。私はユニットテストを全く同じファイルに記述しないかもしれませんが、興味深いアイディアとして排除しないでおきます(実装は読者の方にお任せします)。

よりメンテナンスしやすいコードベースを実現するために、テスト対象のファイルとテストのファイルをコロケーションするべきです。新しい人(もしくは半年後の自分自身)がコードを読むとき、 すぐにそのモジュールがテストされていることを見て取れて、そのモジュールの理解の助けとしてテストのファイルを利用できます。変更があれば、その変更に関連するテストの更新(追加 / 削除 / 修正)のリマインドとなります。

状態

アプリケーション / コンポーネントの状態も同様の効果を得られます。その状態を反映する UI から切り離され / 間接的になればなるほど、メンテナンスは難しくなります。状態をローカライズすることはメンテナビリティの利点が得られるだけではなく、 アプリケーションのパフォーマンスの改善にもつながります。アプリケーションのコンポーネントツリーの一角で起こる状態の変化は、ツリーの最上位での状態の変化よりも少ないコンポーネントの再レンダリングで済みます。状態をローカライズしましょう。

"再利用性のある"ユーティリティのファイル

"ユーティリティ"ファイルや関数にも同様です。あるコンポーネントを書いていて、それ自体を関数として抽出できるかたまりを見つけたと、イメージしてください。 あなたはそれを抽出して考えます: "うーん、、、これは多くの人に使ってもらえるんじゃないか"と。そして、それをアプリケーションの utils/ ディレクトリに移して、人生を歩んでいきます。

しばらくして、コンポーネントは削除されましたが、ユーティリティは見えなくなって、より広範囲で利用されているものと削除した人が考えたため、残ることになりました(そのテストとともに)。 その後幾年も、エンジニアは、全くもって不要であることに気づくことなく、その関数とテストを動かし続けることを懸命に努力することになります。無駄な労力と認知負荷です。

もし、関数を使われるファイル内に直接残しておけば、話は全く異なるものになるでしょう。私が言いたいのは、複雑なユーティリティ関数をわざわざテストしないで(してください)ということではなく、 利用される場所に近づけて置いておくと問題を回避する助けになるということです。

そしてお願いだから、この ESLint のルール とそれに近似するルールを削除してください。

原則

コロケーションの概念はこの基本的な原則に集約されます:

可能な限り関連性が高いものの近くにコードを置いてください。

こうも言えます: "一緒に変化するものは、合理的な範囲で近くに置くべきです。"と。( Dan Abramov氏がかつて私にこのような話をしました。)

(より)分かりやすいオープンソース

上述の問題を避ける一方で、このようにプロジェクトを構成する利点が他にもあります。あるコンポーネントをオープンソースのプロジェクトに変換するのは、大抵、フォルダーを他のプロジェクトへコピー / ペーストして npm に公開するのと同じくらい簡単です。 そして、プロジェクトにインストールして、 require / import を更新するだけでもう大丈夫です。

例外

システムの一部かもしくは全体にまたがるドキュメントや、ものがどうやって統合されるかについてのドキュメントは、確かに良い議論の対象でしょう。そして、コンポーネントを横断したインテグレーションもしくは E2E のテストをどこに置くべきでしょう? これらは例外だと考えるかもしれません が、実のところ先ほどの原則によく合致します。

ユーザーの認証に関するアプリケーションの部分があると仮定して、そのフローについてドキュメントを持ちたいとしたら、ユーザーの認証に関する全てのモジュールを内包するフォルダーに README.md を置きます。 このフローにインテグレーションテストを必要とするのであれば、同じフォルダーにテストのファイルを置きます。

E2E テストに関しては、プロジェクトの最上位に置くのがより合理的です。プロジェクト自体に留まらず、システムの他の部分も範囲となるので、別のディレクトリに置くことが合理的だと考えられます。 src/ のファイルにマッピングされないのです。実際、E2E テストは src/ がどのように構成されるか全く気にしません。 src/ ディレクトリのリファクタリングやファイルの移動は、E2E テストへの変更を必要としないようにあるべきです。

結論

ここで私たちがゴールとするのは、可能な限りメンテナンスが容易なソフトウェアを開発することです。コメントをコロケーションすることで得られる メンテナビリティ適用性使いやすさ の利点は、 他のものをコロケーションすることでも同じように得られます。試したことがなければ、試してみることをおすすめします。

追伸: "関心の分離"に反することが気がかりであれば、 こちらの講演 を視聴して、その意味を問い直すことをおすすめします  😀。

さらに追伸: 画像や他のリソースにもよく適用できることもまた書き留めておきます。webpack のようなツールを使っている場合、このようなリソースをコロケーションするのは申し分なく簡単になります。 実際のところ、私の意見ではこれが webpack の核となる提供価値の 1 つだと思います。