はじめに
フロントエンド開発の複雑性が増す中、コードの保守性と拡張性を確保することは重要な課題です。本記事では、レイヤードアーキテクチャを採用することで、責務を明確に分離し、テスタブルで保守しやすいフロントエンドアプリケーションを構築する方法を解説します。
レイヤードアーキテクチャとは
レイヤードアーキテクチャは、アプリケーションを複数の層(レイヤー)に分割し、各層に明確な責務を割り当てる設計手法です。これにより:
- 関心の分離: 各レイヤーが特定の責務に集中
- 依存関係の管理: 上位レイヤーから下位レイヤーへの単一方向の依存
- テスタビリティの向上: 各レイヤーを独立してテスト可能
- 保守性の向上: 変更の影響範囲を限定
5層アーキテクチャの構成
アーキテクチャ全体像
┌─────────────────────────────────────┐
│ Presentation Layer │ ← イベントハンドリング
├─────────────────────────────────────┤
│ Application Layer │ ← ユースケース実装
├─────────────────────────────────────┤
│ UI Layer │ ← UIコンポーネント
├─────────────────────────────────────┤
│ Infrastructure Layer │ ← 外部通信・副作用
├─────────────────────────────────────┤
│ Domain Layer │ ← ビジネスロジック・型定義
└─────────────────────────────────────┘
各レイヤーの詳細
このテックブログの5層アーキテクチャを、コードなしでわかりやすく説明しますね!
レイヤードアーキテクチャの5つの層
フロントエンドアプリケーションを5つの役割に分けて整理する方法です。それぞれの層は特定の仕事を担当します。
Domain Layer(ドメイン層)
何をする層? ビジネスのルールや規則を決める層
-
具体例:
- 「メールアドレスの形式をチェックする」
- 「管理者だけが削除できる」
- 「アカウント開設から1年経ったらプレミアム機能が使える」
- 特徴: 外部のシステムに一切依存しない、純粋なルール集
Infrastructure Layer(インフラ層)
何をする層? 外部との通信や、データの保存・読み込みをする層
-
具体例:
- サーバーからユーザー情報を取得する
- ローカルストレージにデータを保存する
- APIを呼び出してデータを送信する
- 特徴: 「外の世界」とのやり取りを全て担当
Application Layer(アプリケーション層)
何をする層? 実際の業務の流れを制御する層
-
具体例:
- 「プロフィール更新」の一連の流れ
- まずキャッシュをチェック
- バリデーション実行
- 権限確認
- サーバーに保存
- ローカルキャッシュ更新
- 「プロフィール更新」の一連の流れ
- 特徴: 他の層を組み合わせて、実際の機能を実現
UI Layer(UI層)
何をする層? 見た目の部品を作る層
-
具体例:
- ユーザーカード
- 入力フォーム
- ボタンやアイコン
- 特徴: 再利用できる部品を作る。ロジックは持たない
Presentation Layer(プレゼンテーション層)
何をする層? ユーザーの操作を受け取って、画面を制御する層
-
具体例:
- ボタンをクリックしたら編集モードに切り替える
- ローディング状態を表示する
- エラーメッセージを表示する
- 特徴: ユーザーの操作と画面の状態を管理
層同士の関係
ユーザーの操作 → Presentation → Application → Infrastructure
↓ ↓
UI ←----------- Domain
ポイント:
- Application Layerのサービスを利用してユースケースを実行
- UI状態の管理(loading、error、編集モードなど)
- ユーザーイベントのハンドリング
ディレクトリ構成
src/
├── domain/ # ビジネスロジック・型定義
│ ├── user/
│ │ ├── user.ts
│ │ ├── user-validator.ts
│ │ └── user-business-rules.ts
│ └── shared/
│ └── value-objects.ts
│
├── infrastructure/ # 外部通信・副作用
│ ├── api/
│ │ ├── user-api-client.ts
│ │ └── api-error-handler.ts
│ ├── storage/
│ │ └── user-storage.ts
│ └── monitoring/
│ └── error-tracker.ts
│
├── application/ # ユースケース実装
│ ├── user/
│ │ ├── user-profile-service.ts
│ │ └── user-analytics-service.ts
│ └── shared/
│ └── notification-service.ts
│
├── ui/ # UIコンポーネント
│ ├── components/
│ │ ├── user-profile-card.tsx
│ │ └── user-form.tsx
│ └── shared/
│ └── loading-spinner.tsx
│
└── presentation/ # 画面制御・イベント処理
├── pages/
│ └── user-profile-page.tsx
└── hooks/
└── use-user-profile.ts
まとめ
レイヤードアーキテクチャを採用することで、以下のメリットが得られます:
- 責務の明確化: 各レイヤーが特定の役割に集中
- 高いテスタビリティ: 各レイヤーを独立してテスト可能
- 変更に強い設計: 影響範囲を限定的にできる
- チーム開発の効率化: 並行作業が容易
- 技術的負債の抑制: 構造化により混乱を防ぐ
成功のポイント:
- 依存関係の方向を守る: 上位から下位への単方向のみ
- 各レイヤーの責務を厳守: 責務の混在を避ける
- ドメインロジックの純粋性: 外部依存を持たせない
- 適切な抽象化: 過度な抽象化は避ける
- テストファースト: 各レイヤーでテストを書く
このアーキテクチャは、中規模以上のアプリケーションで特に効果を発揮します。プロジェクトの規模や要件に応じて、必要なレイヤーを選択・調整することで、最適な構成を実現できるでしょう。