戦略と戦術、目的と手段という観点からモジュール分割を捉え直し、feature単位でまとめよう
前提
(web)アプリケーションを作りたい
コードを書く
なんらかのフレームワークなどを使う
モジュールはfeatureで分けよう
このとき、フレームワーク上のパーツの名前などをフォルダの分け方として採用しないほうがいい
例
MVC
こうじゃない
model
TaskModel
View
TaskView
Controller
TaskController
代わりにこう
Task
TaskModel
TaskView
TaskController
フロントエンドではMVCではなく、hooks, components, ...といった名前が出てくる
後者のほうがいいよね、という主張に対して、わかりやすい命名がない
以下のような名前がネット上で見受けられる
とりあえずこれが一番いいかな?miyamonz.icon
「関心事で分ける」
モジュール(MODULES)(別名 パッケージ(PACKAGES))
10年以上前から概念はあります
ただし、この概念自体に広く知れ渡った固有名詞が与えられてないように見える
最近の記事でfolder-by-featureとかは観測され始めたかな、といった印象miyamonz.icon
miyamonz.iconは、この「Task」に相当する部分の名前をfeatureと呼ぶのが適切ではないかと思ってる see
featureでまとめる上でのプログラミング上のメリット
まずどんな登場人物、構成要素(feature)がいるのかがすぐに分かる
さっきの図で言うところの設計を先に読める
オンボーディングが早い
仕事の分割がしやすい
例えば新人に「まずはこの期日コンポーネントのレイアウト調整やってみようか」というような依頼をしやすい
DueDateというフォルダの中のどっかにあることは明確だから
新人がMVCだとかhooksだとかで右往左往する量を減らせる(かも)
依存関係が明確になる
feature間のimport, export関係がそのまま、実際の要件上の依存関係として表出する
TaskとAssigneeの関係は、間違いなく、これらのフォルダをまたいだimport上に現れるはず
依存関係の可視化ツールとか、ちょっとしたスクリプトでこれを追うだけで、全体の複雑さを把握できる
featureごとのアーキテクチャの変更が(ある程度)できる
個別のfeatureをどう実装しても良い
境界をまたぐ部分や、速度的な性能等、境界条件を壊さない限りは
「新しい状態管理ライブラリ、まずAssigneeのfeatureの中で使ってみて、良さそうだったら他のfeatureでも使おうか」といったことができる
このfeatureって見た目がないからコンポーネントは存在しない(必要ない)よね、
ということをそのfeatureのフォルダ内のファイルリストで表明できる
妥協もする
無理に全部をfeature単位でまとめる必要はなく、
一部分だけちょっとずつfeatureにまとめたり、
やってみて違和感が強かったらやめて戻す
といった現実的対処も良いと思う
逆に、個人開発や少人数の初期段階なら
お互いにfolder by featureの考えを共有してから、ガンガン使うと良いと思う
書きながら設計を考える、とかがやりやすい
個人の場合、かつ、作りたいものを書きながら考える場合は、そもそもfeatureが何なのかが分からないので、フォルダ分けはかなりあとになると思う
とりあえず一つのフォルダにどんどんつっこんで、後から抽出するといいのでは
自分はそうしてる
既存のプロジェクトに入れる場合
なんらかの技術選定のせいで自由なフォルダ構成が取れないようなケースでない限り、feature単位でまとめるのは、オプショナルでインクリメンタルに導入ができるはず、というのも良いところである
ただし、以降の途中段階において
探している要素が、従来のフォルダ構成とfeature単位のフォルダのどっちにあったっけ、と迷うことがある
ので、ファイルの移動やコード分割程度くらいのリファクタリングは呼吸するようにやるべき
そのような開発体制が条件として要求される
フレームワークが満たすべき要件
以上の要求から、(この要求と衝突しないための)フレームワークが満たすべき最低限の要件というものが生まれる
フォルダ構成が自由である
任意のフォルダの下に、フレームワークが要求する構成を配置できる
最近の例で似ているものだと、Next.jsのappフォルダのルーティングが挙げられる
featureという単位ではなく、urlという単位ではあるが
ただ、たいていfeatureごとにそれをCRUD等するurlがあるので、だいたい近い構造になる
pagesだと、エントリポイントのファイルの隣に、そこで使うファイルが置けなかった(ルーティングとして認識されてしまうため)
hooks, componentsみたいなフォルダをsrcの下において、すべてのhooksやcomponentsをこのフォルダに入れるのは、典型的な技術駆動パッケージングである
どこからでも使われるutil的なものなら、このように置いてもいいとは思う
ただ、特定のpageでしか使わないものは、そのpageの横に置いたほうが断然わかりやすい
rails等でも設定をしたらできたと思うが
{{feature name}}/{model,view,controller}的なフォルダ構成
そもそもrails系のgenerateコマンドは指定したフォルダ化にMVC等のファイルを新規作成するので、割れ窓になりがち
逆に、この自由度が無いフレームワークやライブラリを使うこと、使わざるを得ないことが決定してるなら、コードがそれらのライブラリの都合で構成の自由度が無い前提下にあることを認めよう
自由度のないライブラリは、常に認知コストを払い続けることになる
他に選択肢が無いなら仕方ない
そのことを忘れないようにしましょう(または、ライブラリに対してissueを立てよう)
領域をまたぐ
MVCの例は、素朴なRails的なwebアプリケーションを想定していたが、現代は、扱う領域が広い
Taskというものが
フロントエンド
コンポーネント
hooks
バックエンド
DBのModel
controller、あるいはapiエンドポイント
さらにこれからはエッジ
というふうに、扱う範囲が広い。これをまるっとまとめられると良いと思う