コンテンツにスキップ
検索語を入力してください

    アプリケーション配線

    ユースケースはビジネス上の順序(読み込み → 認可 → 遷移 → 永続化)を所有し、インフラの詳細はポートの背後に隠す。ハンドラや遷移関数が SQL や HTTP を直接呼ぶと、テストが実 DB に依存し、変更の影響範囲も読み取れなくなる。

    ポートの形は 永続化、集約、イベント のリポジトリ契約と、ドメインモデリング の Protocol 定義に合わせる。非同期配線とリトライはそれぞれ 並行性と非同期インフラの耐障害性 を参照する。

    デフォルト方針: DI コンテナではなく明示的引数

    Section titled “デフォルト方針: DI コンテナではなく明示的引数”

    Kamae Python は Reader モナド、サービスロケーター、重い DI フレームワークよりプレーンな関数パラメータを優先する。

    async def assign_driver_use_case(
    resolver: RequestResolver,
    store: RequestStore,
    authorizer: RequestAuthorizer,
    actor: Actor,
    request_id: UUID,
    driver_id: UUID,
    now: datetime,
    ) -> Result[EnRoute, AssignDriverError]:
    ...

    依存関係は型付きポートとしてユースケース境界に入る。純粋遷移関数はインフラに依存しないまま保たれる。完全なオーケストレーション例は 状態遷移 を参照する。

    リポジトリがすでに標準化していない限り、新規コードのために DI コンテナを採用しない。

    依存の向きは一方向に保つ。ドメインはフレームワークや ORM を知らず、アプリケーションはポート(Protocol)だけを知り、インフラが具象実装を提供する。ドメインが SQLAlchemy や FastAPI を import し始めると、単体テストがフレームワーク起動を要求し、ビジネスルールの変更がインフラ変更と絡み合う。

    レイヤー責務依存先
    Domainfrozen モデル、値オブジェクト、純粋遷移、エラーバリアントstdlib、Pydantic
    Application非同期ユースケース、オーケストレーション、認可順序ドメインポート(Protocol
    Infrastructureポートを実装する DB/HTTP/キュー/SDK アダプターフレームワーク、ドライバー
    Interfaceコントローラー、コンシューマー、CLI、コンポジションルートapplication + infrastructure

    ドメインコードはインフラパッケージをインポートしてはならない。

    ポートはユースケースが必要とするものを表す typing.Protocol 型である。正規RequestResolverRequestStore の形状: 永続化、集約、イベント。入門的なポート概念: ドメインモデリング

    アダプターはインフラモジュール内の具象実装である。

    src/
    taxi_request/
    domain.py # states, transitions, events, errors
    application.py # use cases
    ports.py # Protocol definitions (or beside use cases)
    infrastructure/
    postgres_request_store.py
    http_driver_directory.py
    api/
    routes.py # composition root for HTTP

    ポート名は汎用の get / update より、find_waitingsave_en_route のようにユースケースに沿って狭く保つ。

    依存関係の配線はフレームワークエントリポイントでのみ行う:

    • FastAPI ルートモジュールと Depends
    • ASGI lifespan 起動
    • Celery/RQ タスクファクトリー
    • CLI main
    def build_assign_driver_use_case(session: AsyncSession) -> AssignDriverUseCase:
    resolver = PostgresRequestResolver(session)
    store = PostgresRequestStore(session)
    authorizer = RequestAuthorizer(...)
    return partial(
    assign_driver_use_case,
    resolver=resolver,
    store=store,
    authorizer=authorizer,
    )

    フレームワーク固有の構築は api/ または infrastructure/ に留める。ユースケースはポートを受け取るプレーン関数または小さな呼び出し可能オブジェクトのままである。

    アプローチデフォルトにしない理由
    Reader / environment モナドPython では読みにくい。明示的引数で十分
    グローバルサービスレジストリ依存関係を隠し、テストを複雑化
    ユースケースへの ORM モデル注入永続化形状をアプリケーション層に漏らす
    ドメインコード全体への @injectドメインはフレームワークフリーであるべき

    プロジェクトがすでに FastAPI Depends を使うなら、コントローラー境界でユースケース依存関係を構築するために使う。純粋遷移の内側では使わない。

    テストは本番と同じポート型でインメモリまたはフェイクアダプターを渡すべきだ。フェイクは 永続化、集約、イベント正規ポートを実装する。

    class FakeRequestStore:
    def __init__(self) -> None:
    self.saved: list[tuple[EnRoute, tuple[DriverAssigned, ...]]] = []
    async def save_en_route(
    self,
    state: EnRoute,
    events: tuple[DriverAssigned, ...],
    *,
    expected_version: int,
    idempotency_key: str,
    ) -> None:
    self.saved.append((state, events))

    アプリケーションテストにはフェイクを使う。トランザクション、制約、ロックのテストには実データベースアダプターを使う。

    発信 HTTP、キュー、SDK 呼び出しをリトライ、タイムアウト、サーキットブレーカー方針で包むときは インフラの耐障害性 を読む。

    ユースケースは具象アダプターではなくポートに依存しているか — High

    Section titled “ユースケースは具象アダプターではなくポートに依存しているか — High”

    ポートとアダプター分離でワークフローを隔離できるのに、ハンドラ、ドメインモジュール、遷移関数が SQL、HTTP、キュー、SDK を直接呼ぶ箇所を指摘する。

    main、ブートストラップモジュール、テストでのコンポジションルート配線は指摘しない。

    オーケストレーションはユースケースに留まっているか — Medium

    Section titled “オーケストレーションはユースケースに留まっているか — Medium”

    load → authorize → transition → persist の順序を名前付きユースケース関数やクラスが所有すべきなのに、ハンドラ、自由関数、リポジトリアダプターに散らばったビジネスワークフローを指摘する。

    ポートは小さくユースケース形状か — Medium

    Section titled “ポートは小さくユースケース形状か — Medium”

    ユースケースが実際に必要とする操作ではなく、ORM テーブル、SDK 表面、フレームワークハンドラ署名を写したリポジトリやクライアントプロトコルを指摘する。

    テストは実インフラではなくポートを差し替えるか — Low

    Section titled “テストは実インフラではなくポートを差し替えるか — Low”

    フェイクポートでワークフローを検証できるのに、ライブ DB やリモートサービスを要求するユースケーステストを指摘する。ドメインとユースケースカバレッジ用のインメモリやフェイクアダプターを提案する。

    依存は明示的に注入されているか — Low

    Section titled “依存は明示的に注入されているか — Low”

    プロジェクトの前例なしに隠れたグローバル、サービスロケーター、新しい重い DI コンテナを指摘する。関数引数、構造体フィールド、フレームワーク state、コンポジションルート配線を優先する。

    プロジェクトが一貫して使っている Protocol ポートや既存フレームワーク依存パターンは指摘しない。