レイヤードアーキテクチャ#

概要#

レイヤードアーキテクチャ(Layered Architecture)は、システムを複数の階層(レイヤー)に分割する最も一般的なアーキテクチャパターンの一つ。

各レイヤーは特定の役割と責任を持ち、上位のレイヤーは下位のレイヤーのみに依存する。

典型的な4層構造#

┌─────────────────────────────┐
│   プレゼンテーション層        │  ← UI、Webコントローラー
├─────────────────────────────┤
│   ビジネスロジック層          │  ← ドメインロジック、サービス
├─────────────────────────────┤
│   データアクセス層            │  ← Repository、DAO
├─────────────────────────────┤
│   データベース層             │  ← データベース、ファイルシステム
└─────────────────────────────┘

各層の役割#

  1. プレゼンテーション層(Presentation Layer)

    • ユーザーインターフェース

    • リクエストの受付とレスポンスの返却

    • 入力検証

  2. ビジネスロジック層(Business Logic Layer)

    • ビジネスルールの実装

    • データの変換と処理

    • トランザクション管理

  3. データアクセス層(Data Access Layer)

    • データの永続化

    • データベース操作の抽象化

    • クエリの最適化

  4. データベース層(Database Layer)

    • データの物理的な保存

    • データの整合性維持

クラス名について

※レイヤーの名前と、実装で使う名前(role)はあえて分けて抽象化する慣習がある

Layer

Role(よく使われる名前)

Presentation

Controller / Router / Presenter

Business Logic

Service / UseCase

Data Access

Repository / DAO

Infrastructure

DB / API Client

実装例(Python)#

# プレゼンテーション層
class UserController:
    def __init__(self, user_service):
        self.user_service = user_service
    
    def get_user(self, user_id):
        user = self.user_service.get_user(user_id)
        return {"id": user.id, "name": user.name}

# ビジネスロジック層
class UserService:
    def __init__(self, user_repository):
        self.user_repository = user_repository
    
    def get_user(self, user_id):
        user = self.user_repository.find_by_id(user_id)
        if not user:
            raise ValueError("User not found")
        return user

# データアクセス層
class UserRepository:
    def __init__(self, db):
        self.db = db
    
    def find_by_id(self, user_id):
        return self.db.query("SELECT * FROM users WHERE id = ?", user_id)

FastAPIによるAPI設計の例#

FastAPIで実践する「レイヤードアーキテクチャ」の基本設計

メリット / デメリット#

メリット#

  • 関心の分離: 各層が明確な責任を持つ

  • 理解しやすさ: 構造が単純で直感的

  • テスタビリティ: 各層を独立してテスト可能

  • 保守性: 変更の影響範囲が限定される

  • 再利用性: 下位層のコンポーネントを再利用できる

デメリット#

  • パフォーマンス: 層を跨ぐ呼び出しによるオーバーヘッド

  • 密結合のリスク: 下位層への依存が強くなりがち

  • 柔軟性の欠如: 厳格な階層構造により、変更が困難な場合がある

  • モノリシックになりがち: すべてが一つのデプロイメントユニットになる

ベストプラクティス#

  1. 依存関係は一方向に: 上位層から下位層への依存のみを許可

  2. インターフェースの活用: 層間の結合度を下げる

  3. DTOの使用: 層間でのデータ転送にはDTOを使用

  4. トランザクション境界の明確化: ビジネスロジック層でトランザクションを管理

  5. 例外処理の統一: 各層で適切なレベルの例外処理を行う

適用場面#

レイヤードアーキテクチャが適している場合:

  • 中小規模のWebアプリケーション

  • CRUD操作が中心のシステム

  • チームが伝統的なアーキテクチャに慣れている場合

  • シンプルな構造が求められる場合