開発プロセスにおいて、ビジネスニーズはさまざまで頻繁に変化する可能性があるため、柔軟で拡張可能かつメンテナンスしやすいアーキテクチャを作成することが非常に重要です。同様に重要なのは、チームメンバーやクライアントなど、すべての人がプロジェクトを明確に理解していることです。大量のドキュメント、頻繁な会議、絶え間ない改善を避けるために、私たちは以下のアーキテクチャアプローチを採用しました。本記事では、人気のあるアーキテクチャの利点を探り、独自のニーズを満たすための最適なソリューションを選択する手助けをします。
多くの人は、以下に示すアーキテクチャが単なる「フォルダ構造」であると考えていますが、これは一つの見方に過ぎません。実際には、深く掘り下げると、いくつかの重要な側面があります:
- モジュールの協力:アプリケーション内の異なるモジュール / コンポーネント間の効率的な通信と相互作用(コンポーネントベースのアーキテクチャ、再利用可能なコードを使用)。
- プロジェクトナビゲーションの改善:ナビゲートしやすく、メンテナンスしやすい方法でプロジェクトを構築する(明確なフォルダ階層、命名規則、関心の分離)。
- ビジネスロジックとユーザーインターフェースコンポーネントの分離:ビジネスロジック(データ取得、状態管理)をユーザーインターフェースコンポーネントから分離し、メンテナンス性と再利用性を向上させる(例:Redux、Context API などのサービスやストレージを使用)。
- DRY: Don’t repeat yourself 繰り返さない
- DAC: Divide and conquer 分割して征服する
下の図をご覧ください -- 私たちの焦点は右下の領域で、ここがこれらの原則が最も効果的に結合されるポイントです:
理想的な結果(例)
私たちはこれらの側面を実現するためにアーキテクチャを活用したいと考えています。さて、各アーキテクチャを詳細に分析し、具体的な状況に応じて最適なアーキテクチャを選択しましょう。
クラシックアーキテクチャ(無アーキテクチャ)- Classic architecture (without architecture)#
クラシックアーキテクチャは、多くの人がすでに使用している方法です。私たちは通常、基本的な概念に焦点を当て、「ページ」、「コンポーネント」、「ヘルパー」などにプロジェクトを分割します。しかし、問題はアプリケーションが成長するにつれて、構造が崩れ始め、正しいコンポーネントやそのビジネスロジックを見つけることがますます難しくなることです。例を挙げて説明しましょう:
コンポーネントの過剰使用(例)
この例では、3 つのページがあり、明らかに過剰使用されていません。しかし、これらは下に示すすべてのコンポーネントを含む可能性があります。これらのコンポーネントを観察すると、本当の「混乱」が見えてきます🤯:各コンポーネントは他のコンポーネントを積極的に使用し、依存関係が生じています。これにより、拡張性と再利用性が低下します。
以下は、Redux 状態管理者を使用した別の例です:
散発的なアプリケーションロジック - Redux 状態管理者(例)
私たちの設定では、各コンポーネントは指定された「リデューサー」によって管理され、そのリデューサーは特定のロジックを処理します。しかし、いくつかのコンポーネントのロジックが誤って不適切なリデューサーに配置されています。このような状況が発生する理由は、開発者が既存のファイルに気づかなかったり、その時点で必要なロジックの量が限られていたために新しいファイルを作成することを考慮しなかったりすることです。そのため、いくつかのコンポーネントのロジックがプロジェクト全体に散在し、明確さが欠け、メンテナンスが難しくなっています。
下の図は、欠落したアーキテクチャを示しています:
破壊的なデカップリングの図(例)
このアプローチ(またはより正確には、アーキテクチャの欠如)は、依存関係を追跡するのが難しい混乱した環境を引き起こし、混乱を招き、プロジェクトのサポートを困難にします。ただし、このアプローチは特定の状況では有用である場合があります。たとえば:
- 小規模なチーム(1-2 人の開発者)
- MVP プロジェクト
- 長期的な支援が必要ないプロジェクト
- 学習プロジェクトやテンプレート
モジュラー構造 - Modular architecture#
モジュラーアーキテクチャは、アプリケーションをいくつかの層(pages、modules、components、UI など)に分割する方法であり、これらの層には独立したモジュールがあり、それぞれに独自のロジックと責任範囲があります。
モジュラーアーキテクチャ - 層構造(例)
この例では、アプリケーション層の配置方向が一貫していることがわかります:pages → modules → components → ui(反対側から見ると逆になります)。これは、層が高くなるほど(たとえば、pages)、使用できる下層の数が少なくなることを意味します -- コンポーネントはモジュールを使用できませんが、ユーザーインターフェース層のすべてを使用できます。一方、モジュールはコンポーネントを使用できますが、ページを使用することはできません。そして、ページはすでにモジュールのみを使用できる状態です。
モジュラーアーキテクチャ - モジュールと公共 API(例)
前述のように、各モジュールには独自の責任範囲があります。同様に重要なのは、各モジュールが独自の公共 API(index.ts ファイル)を持つべきであり、これはモジュールのすべての内部ロジックをカプセル化し、外部に必要な部分のみを提供します。(これは OOP 原則に非常に似ています:クラスに多くのプライベートメソッドがある場合、これらのメソッドは外部からアクセスできませんが、クラス内部で使用できます)pages ファイルについては、実際には非常にシンプルです:理想的には、モジュールとコンポーネントのカプセル化に過ぎず、アプリケーションのすべてのビジネスロジックはモジュールとコンポーネントのレベルに配置されるべきです。
(⚠️) 重要:モジュールは他のモジュールを使用すべきではなく、コンポーネントは複雑なロジックを含むべきではありません。もしロジックが必要な場合は、できるだけシンプルでメンテナンスしやすいものでなければなりません。さもなければ、それはモジュールです!
下の図をご覧ください:
近似理想図(例)
しかし、私たちは依然として components / や ui / のようなグローバルディレクトリを持っており、これらは過剰使用される可能性があります。特定の状況では、ロジックが増加し、コンポーネントとモジュールの違いが常に明確でなくなることがあります。さらに、アプリケーションが成長するにつれて、開発者が他のモジュール内でモジュールを使用し始めることがよく見られ、これがアーキテクチャの原則を破り、不必要な依存関係を引き起こします。それにもかかわらず、私たちのアーキテクチャは以下の機能を提供します:
- シングルスレッド
- 異なるレベルでコンポーネントを再利用する能力
- ほぼ完璧な階層感
- カプセル化
機能分割設計(FSD)アーキテクチャ - Feature Sliced Design#
概要 - https://feature-sliced.design/
機能分割設計(FSD)アーキテクチャは、モジュラーアーキテクチャに多くの類似点がありますが、上記で議論した状況を回避します。このアプローチは、層ではなく機能領域(特徴)に基づいてプロジェクトを構築します。この組織方法は、モジュラーアーキテクチャの components や UI のようなグローバルディレクトリの増加を避け、コンポーネント、モジュール、層間の明確な責任分担を提供します。
FSD - 層の例
アーキテクチャの構築方法は、最上層の pages がすべてのサブモジュールとコンポーネントの作業を統合し、整理することです。そして各層は、より詳細で具体的な機能と要素を提供します。はい、ここでも同じルールに従います -- 層が高くなるほど(たとえば、pages)、使用できる下層の層が少なくなります:
- ページ - 最上層にはアプリケーション内で表示される pages が含まれます。
- プロセス - このアーキテクチャでは廃止されているため、スキップできます。
- 機能 / ウィジェット - pages の下には、ページのコア機能を構築し、管理可能性と独立性を持たせる主要な features ブロックがあります。
- エンティティ(Entities)-- 機能モジュールの下の entities は、「共有」層で利用可能なよりシンプルなユーザーインターフェースコンポーネントから構成されています。
- 共有 - 最下層には、アプリケーションの異なる部分で使用できる一般的なユーザーインターフェースコンポーネントが含まれています。
(⚠️) 重要:モジュラーアーキテクチャと同様に、各層間での過剰使用は避けてください。
概要(スライス / セグメント) - https://feature-sliced.design/
FSD アーキテクチャは、モジュラー要素を特徴としており、「スライス」と「セグメント」と呼ばれています。「スライス」は各層内のモジュールを指し、各モジュールは異なるビジネスエンティティを表します。同時に、「セグメント」には、api/
、components/
、config/
、constants/
などのさまざまな構造コンポーネントが含まれ、アーキテクチャをより明確で管理しやすい部分に整理します。
最後に、私たちは目標結果に達しました:
理想 - 図(例)
このアプローチをプロジェクトに統合することは簡単でも迅速でもありません。最低限のアーキテクチャ知識が必要であり、時間がかかる可能性があることを常に念頭に置かなければなりません。しかし、FSD の使い方をマスターすることで:
- 構造が明確
- 階層が明確
- 柔軟なコンポーネント
- 独立したモジュール
- 再利用性のバランス
ちなみに、このアーキテクチャはファイル名に「ケバブケース」を使用することを推奨しています👀。
product-description.vue
/shopping-cart.tsx
/get-base-url.ts
/ など。
「モジュラーアーキテクチャ」を使用した例:
「FSD アーキテクチャ」を使用した例:
- クラシック React アプリケーションにおける FSD
- Vue3 アプリケーションにおける FSD
- Next.js アプリケーションにおける FSD
- React Native アプリケーションにおける FSD
結論#
本記事では、クラシックアーキテクチャ、モジュラーアーキテクチャ、FSD アーキテクチャの違いを探り、それらの用途について議論しました。