とあるプロジェクトでは、Container-PresentationalパターンとReduxを採用しており、ロジックは関数に切り出してindex.tsx
に集約されていました。とはいえ、Reduxへの副作用、Reduxからの副作用、Reactに閉じた副作用の分離は出来ている状態でした。この設計をどう思うかという問いに対し、あるGeminiは安易に「hooks.ts
ファイルを作成してロジックを分離すれば良い」と提案してきました。
もちろん、この提案は危険な罠でした。AIがそれらしいことを言うからといって鵜呑みにしてはいけません。Reduxを使用するプロジェクトでは、useSelector
(Redux → React)とuseDispatch
(React → React)といった、異なる副作用の方向性を持つフックが混在します。これらを無秩序に一つのファイルに詰め込むことは、hooks.ts
をカオスの温床に変え、コードの意図を曖昧にしてしまうのです。
原則の確立:副作用の方向性を理解する
秩序を取り戻すための最初のステップは、 「その副作用は何から何に影響を与えるか」 という文脈に基づいて副作用を分類する原則を確立することです。この原則に基づき、副作用の方向性を以下の3つに明確に定義します。
-
React → Redux
: ユーザーの操作やライフサイクルイベントに応じて、Reduxストアに影響を与える(出力)。 -
Redux → React
: Reduxストアの状態変更が、コンポーネントに影響を与える(入力)。 -
React → React
: コンポーネント内のローカルな状態やDOMに閉じた振る舞いを管理する。
この方向性を理解することが、我々のプロジェクトにおいては健全なカスタムフックの設計における後の羅針盤となります。
ファイル分割のパターンとトレードオフ
私たちは、この原則を現実のファイル構造に落とし込むための複数のパターンを検討し、それぞれのトレードオフを分析しました。
- マイクロファイル症候群:責務ごとに細かくフックファイルを分割するパターンです。これは「単一責任の原則」を徹底できますが、ファイルの数が過剰に増え、ナビゲーションと認知負荷が増大するというデメリットがあります。
-
3ファイルに集約:マイクロファイル症候群を避けるため、副作用の方向性に応じて、
useActions.ts
、useStates.ts
、useFeature.ts
の3つのファイルにロジックをまとめるパターンです。
結論:アーキテクチャという生殺与奪の権利をAIに握らせるな
最終的な結論として、 「3ファイルに集約する」 というアプローチは、無秩序なカオスと過剰なファイル分割という二つの極端な問題を同時に解決するという予測と、実際にいくつかのコンポーネントでAIに改修をさせてみて現実的なプランであることを確認出来ました。
-
useActions.ts
:React → Redux
の副作用を担い、命令を明確にします。 -
useStates.ts
:Redux → React
の副作用を担い、情報フローを明確にします。 -
useFeature.ts
: ローカルな副作用と、上記のフックを統合するビジネスロジックをカプセル化します。
今回の教訓は、いかなる解決策も絶対的なものではないということです。AIが提案してくるのは、サンプルコードを綺麗に見せる最大公約数のソリューションでしかありません。一方で、特殊な仕様や肥大化する一方の要件を受け入れざるを得ない状況では、最大公約数のソリューションは無力です。
最終的な判断は、プロジェクトの成長 を見据え、「今日のシンプルさ」と「将来のスケーラビリティ」のバランスをどう取るかにかかっています。
技術選定において最も賢明なのは、特定のパターンを盲信することではなく、その背景にある原則とトレードオフを理解し、目の前のプロジェクトに最適な答えを見出すことです。自分たちのプロジェクトを守るためには、アーキテクチャという生殺与奪の権利をAIに握らせてはならないのです。