もう迷わない！ドメイン駆動開発をベースにクリーンアーキテクチャを取り入れたPython最強フォルダ構成ガイド


アプリケーションを開発していると、いつの間にかコードがごちゃごちゃになっている、なんて経験はありませんか？
ビジネスロジックやデータベース、外部サービスへの接続コードが一箇所に混ざり合い、変更を加えるたびに「あれ、どこを直せばいいんだっけ？」と戸惑う――こんな状況は、多くの開発者が通る道です。

**ここで頼りになるのが、ドメイン駆動開発(DDD)とクリーンアーキテクチャの考え方です。どちらも「重要なビジネスロジックを明確にし、外部の技術的要素から切り離す」ことを目指しており、その組み合わせはコードベースの見通しを劇的に改善します。本記事では、これらの考え方をふまえたPythonプロジェクトのフォルダ構成例を紹介します。**

「次の機能追加はどうレイヤーに分けよう？」「DBを変えてもビジネスロジックに影響が出ないようにしたい」――そんなときに立ち戻れる、一つの指針として参考にしてください。

## なぜDDDとクリーンアーキテクチャを組み合わせるのか？

- **DDD (ドメイン駆動開発)：ソフトウェアの「本当に重要な部分」、すなわちビジネスロジック（ドメイン）を中心に据え、チームが理解しやすいモデルとして定義していく手法です。**
- **クリーンアーキテクチャ：コアのロジックを外部技術から独立させ、依存関係を内側から外側へ一方向に保ちます。これにより、UI、DB、フレームワークなどを取り替えても、ビジネスロジックが簡単には揺らぎません。**

両者を組み合わせることで、ドメインモデルを中心とした明確な構造をつくりやすくなります。ドメインをしっかり定義し、その周囲にアプリケーション層、インフラ層、インターフェース層を配していくことで、どこに何を書くべきかが自然に決まってきます。

## Pythonプロジェクトの基本スタイル

最近のPythonプロジェクトでは、src/ 配下にコードをまとめ、pyproject.tomlで依存管理をするパターンがよく使われます。PoetryやPipenvとの相性も良く、CI/CDパイプライン構築もやりやすいのがメリットです。

ここで紹介する分割は大きく4つのレイヤーです。

- domain：ビジネスロジックの本体（エンティティ、値オブジェクト、ドメインサービス、リポジトリの抽象インターフェース）
- application：ユースケース（ビジネスロジックを活用して、アプリケーションとしての操作・振る舞いを定義）
- infrastructure：DBや外部APIアクセスなど、環境依存の実装部分
- interface：WebフレームワークやCLIなど、ユーザーや外部からの入力・出力部分

## フォルダ構成例

以下は一つの参考例です。プロジェクト規模や要件に合わせてアレンジできますが、この構成を押さえておくと迷いにくくなります。

```
project_name/
├─ pyproject.toml
├─ README.md
├─ docs/
├─ tests/
└─ src/
    ├─ domain/
    │   ├─ entities/
    │   │   ├─ user.py
    │   │   └─ order.py
    │   ├─ value_objects/
    │   │   └─ email_address.py
    │   ├─ services/
    │   │   └─ order_service.py
    │   └─ repositories/
    │       └─ user_repository.py   # 抽象インターフェースのみ定義
    │
    ├─ application/
    │   ├─ use_cases/
    │   │   ├─ create_user.py
    │   │   ├─ get_user.py
    │   │   └─ update_order.py
    │   ├─ dtos/
    │   │   └─ user_dto.py
    │   └─ interfaces/
    │       └─ user_repository_if.py # domainの抽象Repoを参照
    │
    ├─ infrastructure/
    │   ├─ persistence/
    │   │   ├─ orm_user.py     # DB接続によるUserRepo実装
    │   │   └─ db_config.py
    │   ├─ external_services/
    │   │   └─ payment_gateway.py
    │   └─ config/
    │       └─ settings.py
    │
    └─ interface/
        ├─ web/
        │   ├─ fastapi_app.py
        │   ├─ routes.py
        │   └─ controllers/
        │       └─ user_controller.py
        ├─ cli/
        │   └─ cli_commands.py
        └─ presenters/
            └─ user_presenter.py
```

### 各ディレクトリの役割

- domain/：ビジネスモデルが純度100%で存在する場所。外部には依存せず、エンティティや値オブジェクトを定義します。
- application/：ユースケース単位でビジネスロジックを呼び出す層。domainには依存しますが、infrastructureやinterfaceには直接依存しないようにします。
- infrastructure/：具体的なDBアクセスや外部サービスへの接続処理など、技術的な詳細を実装する層です。
- interface/：Web APIやCLIなど、外部からアプリケーションを操作する際の入り口。コントローラやルーティング、プレゼンテーション周りの処理をまとめます。

## 依存関係の流れ

クリーンアーキテクチャでは、ドメインが一番内側に位置します。

- domainはどこにも依存しない
- applicationはdomainへ依存するが、infrastructureやinterfaceには依存しない（抽象経由で接続）
- infrastructureとinterfaceはapplicationやdomainの抽象を実装し、外側から内側を参照しない

こうすることで、たとえばDBを変えたくなったときでもdomainやapplicationには手を入れず、infrastructure側だけで対応できます。テスト時にはMockリポジトリを簡単に差し替えることも容易です。

## 簡単な例：UserエンティティとUseCase

### domain層

```python
# src/domain/entities/user.py
class User:
    def __init__(self, user_id: str, email: "EmailAddress"):
        self.user_id = user_id
        self.email = email
```

```python
# src/domain/value_objects/email_address.py
class EmailAddress:
    def __init__(self, value: str):
        # メール形式の簡易チェックなど
        self.value = value
```

```python
# src/domain/repositories/user_repository.py
from abc import ABC, abstractmethod
from domain.entities.user import User

class UserRepository(ABC):
    @abstractmethod
    def find_by_id(self, user_id: str) -> User:
        pass

    @abstractmethod
    def save(self, user: User) -> None:
        pass
```

### application層

```python
# src/application/use_cases/create_user.py
from domain.repositories.user_repository import UserRepository
from domain.value_objects.email_address import EmailAddress
from domain.entities.user import User

class CreateUserUseCase:
    def __init__(self, user_repo: UserRepository):
        self.user_repo = user_repo

    def execute(self, user_id: str, email_str: str):
        email = EmailAddress(email_str)
        user = User(user_id, email)
        self.user_repo.save(user)
```

### infrastructure層（DB実装例）

```python
# src/infrastructure/persistence/orm_user.py
from domain.repositories.user_repository import UserRepository
from domain.entities.user import User

class ORMUserRepository(UserRepository):
    def find_by_id(self, user_id: str) -> User:
        # DB検索処理（ORMによる実装）
        ...

    def save(self, user: User) -> None:
        # DBへINSERT/UPDATE
        ...
```

### interface層（Webエンドポイント例）

```python
# src/interface/web/user_controller.py
from fastapi import APIRouter
from application.use_cases.create_user import CreateUserUseCase
from infrastructure.persistence.orm_user import ORMUserRepository

router = APIRouter()

@router.post("/users")
def create_user(user_id: str, email: str):
    uc = CreateUserUseCase(ORMUserRepository())
    uc.execute(user_id, email)
    return {"status": "ok"}
```

このようにドメインやアプリケーション層では具体的なORMやWebフレームワークに依存していないため、外側の技術を置き換えるのも比較的容易です。

## まとめ

- **DDDでビジネスロジック（ドメイン）をしっかり定義**
- **クリーンアーキテクチャで依存関係を整理してテストしやすいコード構成へ**
- **Pythonで src/ 以下にレイヤー分割すると、変更容易性・保守性が大幅に向上**

この構成を導入すれば、「またDBを変えるの？」「フレームワークをアップデートするの面倒だな」といった局面でも、コアなビジネスロジックは手を加えずに済むはずです。日々の開発で悩むことが少しでも減り、あなたのチームがよりスムーズにプロダクトを成長させていくためのヒントになれば幸いです。