ひとことで言うと#
アプリケーションを同心円状のレイヤーに分割し、依存の方向を「外側→内側」に限定することで、ドメインロジックを外部技術(DB・フレームワーク等)から独立させるアーキテクチャパターン。
押さえておきたい用語#
- Domain Model(ドメインモデル)
- ビジネスルールとロジックを表現するアプリケーションの中核のこと。最内周に位置する。
- Domain Service(ドメインサービス)
- 単一のエンティティに属さないドメイン固有のビジネスロジックを担うサービス。
- Application Service(アプリケーション サービス)
- ユースケースの調整役を指す。ドメインモデルのメソッドを呼び出し、トランザクション制御を行う。
- Infrastructure Layer(インフラストラクチャ レイヤー)
- DB接続・外部API呼び出し・ファイルI/Oなど技術的な実装の詳細を担う最外周レイヤー。
- Dependency Inversion(依存性逆転)
- 上位レイヤーが下位レイヤーに依存するのではなく、インターフェースを通じて依存方向を逆転させる原則である。
オニオンアーキテクチャの全体像#
こんな悩みに効く#
- ドメインロジックとDBアクセスが混在して、ビジネスルールの変更が怖い
- フレームワークのバージョンアップでアプリケーション全体に影響が出る
- ドメインロジックの単体テストが書けない(DBが必要になる)
基本の使い方#
OrderRepositoryインターフェースをDomain層に定義し、PostgresOrderRepository実装をInfrastructure層に配置する。Dependency Inversionにより、ドメインはDBの種類を知らない状態にする。具体例#
エンジニア45名のEC。注文処理のバリデーションがSQLクエリの中に埋め込まれており、「在庫引当ルール」の変更に毎回3日以上かかっていた。テストも本番DBのコピーが必要で、CI実行に 25分 を要していた。
オニオンアーキテクチャを導入し、注文ドメインを3層に再設計。
| レイヤー | 内容 |
|---|---|
| Domain | Order, OrderItem, 在庫引当ルール, 割引計算 |
| Application | CreateOrderUseCase, CancelOrderUseCase |
| Infrastructure | PostgresOrderRepository, StripePaymentGateway |
ドメインモデルのユニットテストがDBなしで実行可能に。テスト時間が 25分 → 3分 に短縮。在庫引当ルールの変更は 3日 → 半日 で完了するようになった。
エンジニア30名のBtoB SaaS。Expressで構築したAPIをNestJSに移行する計画があったが、ドメインロジックがExpressのミドルウェアに散在しており、移行すると全機能のテストが必要だった。
まずオニオンアーキテクチャにリファクタリングし、ドメインロジックをフレームワーク非依存のTypeScriptクラスに抽出。その後、InfrastructureレイヤーのみをNestJSに差し替え。
ドメインモデルのコードは 1行も変更せず にフレームワーク移行を完了。移行にかかった期間は当初見積もりの 6ヶ月 → 2ヶ月 に短縮された。
エンジニア12名の医療系スタートアップ。診療報酬計算のロジックが複雑で、バグが見つかるたびに「テストを書こうとするとDB・外部APIのモックが大量に必要」で断念していた。テストカバレッジは 18%。
診療報酬計算をDomain層のPure Functionとして再実装。外部依存をすべてインターフェースに切り出し、テスト時はインメモリ実装を注入する設計に変更。
3ヶ月でDomain層のテストカバレッジが 18% → 92% に向上。診療報酬の計算ミスが 月4件 → 月0.3件 に減少し、保険請求の差し戻し率も大幅に下がった。
やりがちな失敗パターン#
- ドメインモデルがアネミック(貧血)になる — Domainにデータだけ置いてロジックをApplication Serviceに書くのは本末転倒。ビジネスルールは必ずDomain層に実装する
- レイヤーが多すぎて開発速度が落ちる — 小規模なCRUDアプリに4層のオニオンは過剰。ドメインロジックが複雑な場合にのみ適用する
- 依存方向の違反を許容する — 「この1箇所だけ」が積み重なると構造が崩壊する。ArchUnit等で自動検出する
- インターフェースを作りすぎる — 実装が1つしかないインターフェースを大量に作るのはボイラープレート。テスト時に差し替えが必要な箇所だけにインターフェースを切る
まとめ#
オニオンアーキテクチャは同心円状のレイヤーで依存方向を 「外→内」 に限定し、ドメインロジックを外部技術から独立させる設計パターン。Dependency Inversionを使ってリポジトリのインターフェースを内側に、実装を外側に配置する。テスタビリティの向上・フレームワーク移行の容易さ・ビジネスルール変更の安全性が主な利点であり、ドメインロジックが複雑なアプリケーションで特に効果を発揮する。