クリーンアーキテクチャをAIと実装
クリーンアーキテクチャは複雑に見えますが、AIと一緒に進めれば効率的に実装できます。レイヤーごとに役割を理解し、段階的に構築していきましょう。
クリーンアーキテクチャの基本
レイヤー構成
Entities(エンティティ)
ビジネスルールを表現。最も内側で、他に依存しない
Use Cases(ユースケース)
アプリケーション固有のビジネスロジック
Interface Adapters(インターフェースアダプター)
コントローラー、プレゼンター、ゲートウェイ
Frameworks & Drivers(フレームワーク)
DB、Web、外部サービスなど。最も外側
依存関係のルール
内側のレイヤーは外側のレイヤーを知らない。依存は常に外から内へ向かう。
外側 → → → 内側
DB → Repository → Service → Entity
DB → Repository → Service → Entity
FastAPIでの実装例
AIへの指示:プロジェクト構造の作成
FastAPIでクリーンアーキテクチャを採用したプロジェクト構造を作成してください。 【機能】 タスク管理システム(CRUD) 【要件】 - ドメイン層:Task エンティティ - ユースケース層:タスクの作成、取得、更新、削除 - インフラ層:SQLAlchemy を使用したリポジトリ - プレゼンテーション層:FastAPI エンドポイント まず、フォルダ構造と各ファイルの役割を説明してください。
推奨フォルダ構造
app/
├── main.py # FastAPIアプリ起動
├── domain/ # ドメイン層
│ ├── entities/
│ │ └── task.py # Taskエンティティ
│ └── repositories/
│ └── task_repository.py # リポジトリインターフェース(抽象)
├── application/ # ユースケース層
│ └── use_cases/
│ └── task_use_cases.py # ビジネスロジック
├── infrastructure/ # インフラ層
│ ├── database/
│ │ ├── connection.py # DB接続
│ │ └── models.py # SQLAlchemyモデル
│ └── repositories/
│ └── task_repository_impl.py # リポジトリ実装
└── presentation/ # プレゼンテーション層
├── api/
│ └── tasks.py # エンドポイント
└── schemas/
└── task_schema.py # リクエスト/レスポンス
AIと段階的に実装する
1 ドメインエンティティを作成
「domain/entities/task.py を作成してください。 Task エンティティには id, title, description, status, created_at, updated_at を含めます。 ビジネスルールとして、status は "todo", "in_progress", "done" のいずれかです。 フレームワークに依存しない純粋なPythonクラスで実装してください。」
# domain/entities/task.py
from dataclasses import dataclass
from datetime import datetime
from enum import Enum
class TaskStatus(Enum):
TODO = "todo"
IN_PROGRESS = "in_progress"
DONE = "done"
@dataclass
class Task:
id: str
title: str
description: str
status: TaskStatus
created_at: datetime
updated_at: datetime
def mark_as_done(self) -> None:
self.status = TaskStatus.DONE
self.updated_at = datetime.now()
2 リポジトリインターフェースを定義
「domain/repositories/task_repository.py を作成してください。 TaskRepository の抽象基底クラス(ABC)を定義し、 save, find_by_id, find_all, delete メソッドを宣言してください。 この時点ではDBに依存しません。」
# domain/repositories/task_repository.py
from abc import ABC, abstractmethod
from typing import Optional, List
from domain.entities.task import Task
class TaskRepository(ABC):
@abstractmethod
def save(self, task: Task) -> Task:
pass
@abstractmethod
def find_by_id(self, task_id: str) -> Optional[Task]:
pass
@abstractmethod
def find_all(self) -> List[Task]:
pass
@abstractmethod
def delete(self, task_id: str) -> None:
pass
3 ユースケースを実装
「application/use_cases/task_use_cases.py を作成してください。 TaskRepository をコンストラクタで受け取り(依存性注入)、 CreateTask, GetTask, UpdateTask, DeleteTask のユースケースを実装してください。」
4 インフラ層(リポジトリ実装)
「infrastructure/repositories/task_repository_impl.py を作成してください。 TaskRepository インターフェースを実装し、SQLAlchemy を使ってDBアクセスします。 エンティティとDBモデルの変換も行ってください。」
5 プレゼンテーション層(API)
「presentation/api/tasks.py を作成してください。 FastAPI の Router を使い、CRUD エンドポイントを実装します。 ユースケースを依存性注入で受け取り、Pydanticスキーマで入出力を定義してください。」
依存性注入の設定
AIへの指示
「FastAPI の Depends を使って依存性注入を設定してください。 - TaskRepository の実装を TaskRepositoryImpl に差し替え可能にする - テスト時にモックリポジトリを注入できるようにする - main.py でのワイヤリング方法を示してください」
依存性注入のコード例
# main.py
from fastapi import FastAPI, Depends
from infrastructure.repositories.task_repository_impl import TaskRepositoryImpl
from application.use_cases.task_use_cases import TaskUseCases
from presentation.api.tasks import router
app = FastAPI()
def get_task_repository():
return TaskRepositoryImpl()
def get_task_use_cases(repo = Depends(get_task_repository)):
return TaskUseCases(repo)
app.include_router(router)
クリーンアーキテクチャのメリット
メリット
- ✓ テストが書きやすい(モック注入可能)
- ✓ フレームワークの変更に強い
- ✓ ビジネスロジックが明確に分離
- ✓ チーム開発で責任範囲が明確
注意点
- △ 小規模プロジェクトには過剰かも
- △ ファイル数が増える
- △ 学習コストがある
- △ シンプルなCRUDには向かない場合も
まとめ
- ✓ レイヤーを理解する - エンティティ→ユースケース→アダプター→フレームワーク
- ✓ 内側から外側へ実装 - エンティティ→リポジトリIF→ユースケース→実装
- ✓ 依存性注入を活用 - テスト容易性と柔軟性を確保
- ✓ AIに段階的に依頼 - レイヤーごとに指示を出す