メインコンテンツに移動

オニオンアーキテクチャとは?依存関係を中心へ向けるアーキテクチャ設計を徹底解説

ソフトウェア開発では、機能を素早く実装するだけでなく、長期的に保守しやすく、変更に強い構造を作ることが重要です。特に業務システムやSaaS、長期運用されるWebアプリケーションでは、要件変更、技術変更、外部サービス変更、データベース変更などが継続的に発生します。そのため、ビジネスロジックが特定のフレームワークやデータベース、外部APIに強く依存していると、変更のたびに大きな修正が必要になります。

このような課題に対して有効な設計思想の一つが、オニオンアーキテクチャです。オニオンアーキテクチャは、ドメインモデルをシステムの中心に置き、依存関係を常に内側へ向けるアーキテクチャパターンです。外側にはデータベース、UI、外部サービス、フレームワークなどの技術的な実装を配置し、中心にあるビジネスルールがそれらに依存しないように設計します。

オニオンアーキテクチャでは、システムを同心円状の層として考えます。中心にはドメイン層があり、その外側にアプリケーション層、さらに外側にインフラ層やプレゼンテーション層が配置されます。重要なのは、外側の層は内側の層を知ってよいが、内側の層は外側の層を知らないという依存関係ルールです。このルールによって、ビジネスロジックを技術的な詳細から守ることができます。

本記事では、オニオンアーキテクチャの基本概念、誕生の背景、基本構造、各レイヤーの役割、ドメインモデルを中心に置く理由、依存関係ルール、依存性逆転の原則、リポジトリパターン、ドメイン駆動設計との関係、クリーンアーキテクチャやヘキサゴナルアーキテクチャとの違い、メリットとデメリット、実装時の注意点、実務でのベストプラクティスまで体系的に解説します。

1. オニオンアーキテクチャとは?

オニオンアーキテクチャとは、ドメインモデルを中心に置き、依存関係を外側から内側へ向けるアーキテクチャ設計です。名前の通り、玉ねぎのような同心円状の層構造でシステムを捉えます。中心にはビジネスルールを表すドメイン層があり、その外側にアプリケーション層、インフラ層、プレゼンテーション層などが配置されます。

この設計の最大の特徴は、ビジネスロジックを技術的な実装から切り離す点にあります。従来の設計では、ドメインロジックがデータベースやフレームワークに依存しやすく、技術変更時にビジネスロジックまで影響を受けることがありました。オニオンアーキテクチャでは、中心のドメインを守ることで、変更に強いシステムを作ります。

主な特徴

項目内容
日本語名オニオンアーキテクチャ
英語名Onion Architecture
中心概念ドメインモデル
依存方向外側から内側
主な目的ビジネスロジックを技術的詳細から保護する

1.1 オニオンアーキテクチャの概要

オニオンアーキテクチャでは、システムを複数の層に分けて設計します。最も内側にあるのはドメイン層であり、ここにはエンティティ、値オブジェクト、ドメインルールなど、業務上の重要な概念が配置されます。ドメイン層は、データベースやUI、外部サービスなどに依存しません。

外側の層は、内側の層を利用して具体的な処理を実現します。たとえば、アプリケーション層はユースケースを管理し、インフラ層はデータベースや外部APIとの接続を担当します。プレゼンテーション層は、ユーザーからの入力を受け取り、アプリケーション層に処理を依頼します。このように役割を分けることで、責務が明確になります。

1.2 誕生の背景

オニオンアーキテクチャが注目されるようになった背景には、従来のレイヤードアーキテクチャにおける依存関係の問題があります。一般的なレイヤードアーキテクチャでは、上位層が下位層に依存する構造になりやすく、ビジネスロジックがデータアクセス層やインフラ実装に影響されることがあります。

たとえば、ドメインロジックが特定のORMやデータベース構造に依存していると、データベース変更やORM変更が難しくなります。オニオンアーキテクチャは、この問題を解決するために、ドメインを中心に置き、技術的な詳細を外側へ追い出す設計思想として発展しました。

1.3 なぜ注目されているのか

オニオンアーキテクチャが注目されている理由は、保守性、テスト容易性、技術変更への強さを高められるためです。ドメインロジックが外部技術に依存しないため、データベースやUI、外部APIを変更しても、中心の業務ルールを守りやすくなります。

また、ドメイン層やアプリケーション層を独立してテストしやすくなる点も大きなメリットです。外部サービスやデータベースに接続しなくても、ビジネスルールやユースケースを検証できるため、品質の高いシステムを作りやすくなります。

2. オニオンアーキテクチャが生まれた理由

オニオンアーキテクチャが生まれた理由は、ビジネスロジックを技術的な実装から守る必要があったためです。ソフトウェア開発では、フレームワーク、データベース、外部API、UI技術などは時間とともに変化します。しかし、ビジネスルールはシステムの価値の中心であり、技術変更のたびに大きく影響を受けるべきではありません。

従来の設計では、ドメインロジックがインフラ層やデータアクセス層に依存しやすい構造になっていました。その結果、技術変更やテストの際に大きな負担が発生していました。オニオンアーキテクチャは、依存関係の向きを見直すことで、この問題を解決しようとするアプローチです。

2.1 レイヤードアーキテクチャの課題

レイヤードアーキテクチャは、プレゼンテーション層、アプリケーション層、ドメイン層、データアクセス層のようにシステムを層に分ける設計です。役割分担が分かりやすく、多くのシステムで利用されてきました。しかし、実装によっては上位層が下位層に強く依存し、ドメイン層がデータアクセス層に引きずられる問題が発生します。

たとえば、ドメインオブジェクトがORMのアノテーションやデータベースの都合に強く依存している場合、ドメインモデルが純粋な業務概念ではなく、永続化のための構造になってしまいます。これにより、ビジネスロジックの保守性が低下し、テストも難しくなります。

2.2 ドメインロジック保護の必要性

ドメインロジックは、システムの中で最も重要な価値を持つ部分です。注文、契約、請求、承認、在庫、会員管理など、業務上の判断やルールは、企業やサービスの価値そのものに関わります。そのため、ドメインロジックは技術的な詳細から保護する必要があります。

ドメインロジックがフレームワークやデータベースに依存していると、技術変更の影響を受けやすくなります。オニオンアーキテクチャでは、ドメイン層を中心に置き、外側の技術要素から分離することで、ビジネス価値を守ります。

2.3 保守性向上への取り組み

保守性を高めるには、変更されやすい部分と安定している部分を分離することが重要です。技術的な実装は変更されやすい一方で、ドメインルールは比較的安定した中心になります。オニオンアーキテクチャは、この違いを構造として表現します。

外側の層に技術的な詳細を配置し、内側の層に業務ルールを配置することで、変更の影響を局所化できます。これにより、長期的に保守しやすく、拡張しやすいシステムを構築できます。

3. オニオンアーキテクチャの基本構造

オニオンアーキテクチャの基本構造は、同心円状のレイヤーで表現されます。中心にはドメイン層があり、その外側にアプリケーション層、さらに外側にインフラ層やプレゼンテーション層があります。各層は明確な責務を持ち、依存関係は常に内側へ向かいます。

この構造は、単なるフォルダ分けではありません。重要なのは、依存関係の方向と責務の分離です。外側の層は内側の層を利用できますが、内側の層は外側の層を知ってはいけません。このルールによって、ドメインロジックを技術的な実装から独立させます。

3.1 同心円構造

オニオンアーキテクチャでは、システムを玉ねぎのような同心円構造として考えます。最も内側にはドメインモデルがあり、外側へ行くほど技術的な実装や入出力に近づきます。中心に近いほど重要で安定したルールを持ち、外側ほど変更されやすい詳細を持ちます。

この同心円構造により、システムの中心が何であるかが明確になります。中心はフレームワークやデータベースではなく、ビジネスルールです。これは、技術ではなくドメインを中心に設計するための重要な考え方です。

3.2 中心と外側の役割

中心の役割は、ドメインルールを表現することです。エンティティ、値オブジェクト、ドメインサービスなどがここに配置されます。これらは、業務上の概念や制約を表すため、外部技術に依存しない形で設計されます。

外側の役割は、中心のルールを実際のシステムとして動かすための詳細を担当することです。データベースアクセス、外部API連携、UI、Webフレームワーク、メッセージキューなどは外側に配置されます。外側は交換可能な実装詳細として扱われます。

3.3 レイヤーの考え方

オニオンアーキテクチャのレイヤーは、責務ごとに分けられます。ドメイン層は業務ルール、アプリケーション層はユースケース、インフラ層は技術実装、プレゼンテーション層はユーザーとの接点を担当します。

レイヤーを分ける目的は、単にコードを整理することではありません。変更理由を分離し、各層が自分の責務に集中できるようにすることです。これにより、変更時の影響範囲を小さくできます。

4. ドメインモデルを中心に置く理由

オニオンアーキテクチャでドメインモデルを中心に置く理由は、ビジネス価値を守るためです。システムの本質的な価値は、データベースやフレームワークではなく、業務上のルールや判断にあります。これらを中心に置くことで、技術変更に左右されにくい設計を作れます。

ドメインモデルを中心に置く設計では、技術的な都合よりも業務上の意味を優先します。これにより、コードが業務を表現しやすくなり、仕様変更にも対応しやすくなります。特にドメイン駆動設計と組み合わせると、より強力な設計になります。

4.1 ビジネス価値の保護

ビジネスロジックは、システムの価値を生み出す中心部分です。注文の成立条件、契約の有効性、料金計算、承認ルールなどは、企業やサービスの業務に直結しています。これらが技術的な詳細に依存していると、変更やテストが難しくなります。

オニオンアーキテクチャでは、ビジネス価値を持つドメインモデルを中心に置きます。これにより、外部技術が変わっても、中心の業務ルールを守りやすくなります。

4.2 技術依存の排除

ドメインモデルが技術に依存すると、モデルが業務ではなく技術の都合に引きずられます。たとえば、データベースのテーブル構造に合わせすぎたモデルは、業務上の意味を表現しにくくなることがあります。

技術依存を排除することで、ドメインモデルは純粋に業務概念を表現できます。データベースや外部サービスへの接続は外側の層に任せ、中心のドメインは技術詳細を知らない状態に保ちます。

4.3 長期的な保守性

長期運用されるシステムでは、技術スタックが変わる可能性があります。データベースの変更、フレームワークの更新、クラウドサービスの差し替え、UIの刷新などが発生しても、ドメインロジックを守れる構造が必要です。

オニオンアーキテクチャでは、ドメインモデルを中心に独立させることで、長期的な保守性を高めます。技術変更が外側の層に限定されれば、中心の業務ルールへの影響を抑えられます。

5. ドメイン層

ドメイン層は、オニオンアーキテクチャの中心に位置する最も重要な層です。ここには、業務上の概念、ルール、制約、振る舞いが配置されます。ドメイン層は、データベース、外部API、UI、フレームワークなどの外部技術に依存しません。

ドメイン層の目的は、ビジネスの本質をコードで表現することです。エンティティ、値オブジェクト、ドメインサービス、ドメインイベントなどを使って、業務ルールを明確に表現します。この層が健全であれば、システム全体の保守性も高まりやすくなります。

5.1 エンティティ

エンティティは、識別子によって同一性を持つドメインオブジェクトです。注文、顧客、契約、請求、商品など、業務上重要な対象物がエンティティとして表現されます。エンティティは単なるデータ構造ではなく、状態や振る舞いを持つことがあります。

たとえば、注文エンティティであれば、注文状態、注文明細、合計金額、キャンセル可能かどうかなどの業務ルールを持つことができます。エンティティに適切な振る舞いを持たせることで、業務ルールが外部に散らばることを防げます。

5.2 値オブジェクト

値オブジェクトは、識別子ではなく値そのものに意味を持つオブジェクトです。金額、住所、期間、数量、メールアドレス、電話番号などが代表例です。値オブジェクトは不変として扱われることが多く、整合性のある値を表現するために利用されます。

値オブジェクトを使うことで、業務上意味のある値を単なる文字列や数値として扱うことを避けられます。たとえば、金額オブジェクトに通貨や計算ルールを持たせれば、金額に関するロジックを一箇所に集約できます。

5.3 ドメインルール

ドメインルールとは、業務上守るべき制約や判断基準のことです。たとえば、「支払い済みの注文はキャンセルできない」「在庫が不足している商品は注文確定できない」「契約終了日は開始日より後でなければならない」といったルールが該当します。

オニオンアーキテクチャでは、このようなドメインルールを中心のドメイン層に配置します。ドメインルールがアプリケーション層やインフラ層に散らばると、仕様変更時に修正漏れが発生しやすくなります。

6. アプリケーション層

アプリケーション層は、ユースケースを実行するための層です。ユーザーや外部システムからの要求に対して、どのドメインオブジェクトを使い、どの順序で処理を行うかを管理します。ドメイン層のルールを使いながら、アプリケーションとしての処理フローを制御します。

アプリケーション層は、ビジネスルールそのものを持つ層ではありません。ビジネスルールはドメイン層に置き、アプリケーション層はそれらを組み合わせてユースケースを実現します。この分離により、業務ルールと処理フローを整理できます。

6.1 ユースケース管理

アプリケーション層では、ユースケースを管理します。たとえば、注文を作成する、注文をキャンセルする、請求を発行する、会員情報を更新するなど、ユーザーや外部システムが実行したい処理がユースケースになります。

ユースケースは、複数のドメインオブジェクトやリポジトリを利用して処理を進めます。ただし、業務判断そのものをアプリケーション層に書きすぎると、ドメイン層が弱くなります。アプリケーション層は、処理の流れを管理する役割に集中することが重要です。

6.2 処理フロー制御

アプリケーション層は、処理フローを制御します。たとえば、入力値を受け取り、対象のドメインオブジェクトを取得し、ドメインメソッドを呼び出し、結果を保存し、必要に応じて通知を行うといった流れを管理します。

この層に処理フローを集約することで、プレゼンテーション層に業務処理が入り込むことを防げます。また、同じユースケースをAPI、バッチ、管理画面など複数の入口から再利用しやすくなります。

6.3 ドメイン層との関係

アプリケーション層は、ドメイン層を利用します。ドメイン層のエンティティや値オブジェクト、ドメインサービスを組み合わせて、ユースケースを実現します。ただし、ドメイン層はアプリケーション層を知りません。

この依存関係により、ドメイン層はアプリケーションの具体的な実行方法から独立できます。アプリケーション層は外側に位置し、中心のドメイン層へ依存する形になります。

7. インフラ層

インフラ層は、データベース、外部サービス、ファイルシステム、メッセージキュー、クラウドサービスなど、技術的な実装を担当する層です。オニオンアーキテクチャでは、インフラ層は外側に配置され、中心のドメイン層に依存します。

インフラ層は変更されやすい層です。データベースを変更したり、外部APIを差し替えたり、クラウドサービスを変更したりする可能性があります。そのため、ドメイン層がインフラ層に直接依存しないように設計することが重要です。

7.1 データベースアクセス

データベースアクセスは、インフラ層の代表的な責務です。リポジトリの実装、ORMの利用、SQLの実行、トランザクション管理などが含まれます。これらは技術的な詳細であり、ドメイン層に直接持ち込むべきではありません。

たとえば、ドメイン層ではリポジトリの抽象に依存し、インフラ層で具体的なデータベースアクセスを実装します。これにより、ドメイン層はデータベースの種類やORMの詳細を知らずに済みます。

7.2 外部サービス連携

外部サービス連携もインフラ層の役割です。決済API、メール配信サービス、認証プロバイダー、ストレージサービス、外部業務システムなどとの接続は、技術的な実装に該当します。

外部サービスは仕様変更や障害の影響を受けやすいため、アダプタやクライアントクラスで分離することが重要です。アプリケーション層やドメイン層が外部サービスの詳細に依存しないようにします。

7.3 技術実装の配置

インフラ層には、フレームワーク固有の処理、ファイル操作、ログ出力、キャッシュ、キュー、通知、外部APIクライアントなどを配置します。これらはシステムを動かすために必要ですが、ビジネスロジックそのものではありません。

技術実装を外側に配置することで、中心のドメインを守れます。技術要素が変わっても、ドメインモデルやユースケースへの影響を小さくできる点が、オニオンアーキテクチャの大きな価値です。

8. プレゼンテーション層

プレゼンテーション層は、ユーザーや外部システムとの接点を担当する層です。Web画面、APIコントローラー、モバイルアプリの画面、CLI、バッチの入口などが含まれます。この層は、外部からの入力を受け取り、アプリケーション層へ処理を依頼します。

プレゼンテーション層の役割は、入力と出力を扱うことです。業務ルールをここに書きすぎると、UIやAPIの変更がビジネスロジックに影響しやすくなります。業務処理はアプリケーション層やドメイン層に委譲することが重要です。

8.1 UI層

UI層は、ユーザーが操作する画面を担当します。入力フォーム、一覧画面、詳細画面、操作ボタン、エラーメッセージ表示などが含まれます。UI層はユーザー体験に近い層であり、変更頻度が高い傾向があります。

UI層にビジネスロジックを入れすぎると、画面変更のたびに業務処理へ影響が出る可能性があります。UI層は入力の受け取りや表示に集中し、処理はアプリケーション層へ委譲する設計が望ましいです。

8.2 API層

API層は、外部クライアントやフロントエンドからのリクエストを受け付ける層です。リクエストの受信、入力形式の変換、認証情報の受け渡し、レスポンス形式の整形などを担当します。

API層もプレゼンテーション層の一部として扱えます。ここに業務判断を直接書くのではなく、アプリケーション層のユースケースを呼び出す形にすると、API仕様変更と業務ルールを分離しやすくなります。

8.3 ユーザーとの接点

プレゼンテーション層は、ユーザーや外部システムとの接点です。そのため、入力形式や表示形式、エラーレスポンス、画面遷移など、外部とのやり取りに関する責務を持ちます。

ただし、ユーザーとの接点であるからといって、すべての処理をこの層に書くべきではありません。プレゼンテーション層は外側にある変更されやすい層であり、中心のドメインロジックから分離することが重要です。

9. 依存関係ルール

オニオンアーキテクチャで最も重要なのが、依存関係ルールです。依存関係は常に外側から内側へ向かいます。内側の層は外側の層を知ってはいけません。つまり、ドメイン層はアプリケーション層やインフラ層、プレゼンテーション層に依存しません。

このルールによって、中心のドメインロジックを技術的な詳細から守ることができます。外側の技術実装は交換可能な部品として扱われ、中心の業務ルールは安定して保たれます。

9.1 内側への依存

オニオンアーキテクチャでは、外側の層が内側の層に依存します。プレゼンテーション層はアプリケーション層を呼び出し、アプリケーション層はドメイン層を利用します。インフラ層も、ドメイン層やアプリケーション層で定義された抽象を実装する形になります。

内側への依存にすることで、システムの中心が外側の詳細に振り回されにくくなります。ビジネスルールがデータベースやUIに依存しないため、技術変更への耐性が高まります。

9.2 外側への依存禁止

内側の層が外側の層に依存してはいけません。たとえば、ドメイン層がデータベース接続クラスを直接呼び出したり、Webフレームワークのクラスを参照したりする設計は避けるべきです。

外側への依存が発生すると、ドメイン層が技術的な詳細に引きずられます。これでは、オニオンアーキテクチャの目的であるドメインロジックの保護が実現できません。

9.3 依存方向の統一

依存方向を統一することで、アーキテクチャの理解がしやすくなります。どの層がどの層を知ってよいのかが明確であれば、コードの配置や責務の判断も行いやすくなります。

依存方向が曖昧になると、レイヤー違反が発生しやすくなります。実務では、コードレビューや静的解析を使って、依存関係が正しく保たれているかを継続的に確認することが重要です。

10. 依存性逆転の原則との関係

オニオンアーキテクチャは、依存性逆転の原則と深く関係しています。依存性逆転の原則は、上位モジュールが下位モジュールの具体実装に依存せず、抽象に依存するべきだという考え方です。オニオンアーキテクチャでは、この原則を使ってインフラ層への直接依存を避けます。

たとえば、アプリケーション層が具体的なデータベース実装に依存するのではなく、リポジトリのインターフェースに依存します。そして、インフラ層がそのインターフェースを実装します。これにより、依存関係の向きを内側へ保ちながら、外部技術を利用できます。

10.1 抽象への依存

抽象への依存とは、具体的な実装ではなく、インターフェースや抽象クラスに依存することです。オニオンアーキテクチャでは、ドメイン層やアプリケーション層が外部技術に直接依存しないように、抽象を定義します。

たとえば、注文を保存する処理では、具体的なORMクラスではなく、OrderRepositoryという抽象に依存します。これにより、データベース実装を変更しても、アプリケーション層やドメイン層への影響を抑えられます。

10.2 実装の分離

依存性逆転を使うことで、実装を外側の層へ分離できます。インターフェースは内側の層に置き、具体的な実装はインフラ層に置く構成がよく使われます。これにより、中心の層は外側の詳細を知らずに処理できます。

実装の分離は、テスト容易性にもつながります。テスト時には、実際のデータベースではなくモックやスタブを使ってリポジトリを差し替えられます。これにより、ユースケースやドメインロジックを独立して検証できます。

10.3 疎結合化

依存性逆転の原則を適用すると、システムの結合度を下げられます。具象実装への直接依存が減るため、変更時の影響範囲が小さくなります。これは、オニオンアーキテクチャの大きな目的の一つです。

疎結合な設計では、外部サービスやデータベースを差し替えやすくなります。また、各層の責務が明確になるため、コードの理解や保守もしやすくなります。

11. ドメインモデルとの関係

オニオンアーキテクチャは、ドメインモデルを中心に置く設計です。ドメインモデルとは、業務上の概念やルールをソフトウェア上で表現したものです。エンティティ、値オブジェクト、集約、ドメインサービスなどがドメインモデルを構成します。

ドメインモデルを中心に置くことで、システムの設計が技術ではなく業務に沿ったものになります。これは、ドメイン駆動設計とも非常に相性が良い考え方です。技術的な都合でモデルを歪めるのではなく、業務上の意味を表現することを重視します。

11.1 ドメイン中心設計

ドメイン中心設計では、データベースや画面からではなく、業務上の概念から設計を始めます。注文、契約、請求、在庫、顧客などの概念を理解し、それらのルールや関係性をモデルとして表現します。

オニオンアーキテクチャは、このドメイン中心設計を構造として支えます。中心にドメインを置くことで、業務ルールがシステムの中核として扱われるようになります。

11.2 ビジネスロジックの集約

ビジネスロジックは、できるだけドメインモデルに集約することが望ましい場合があります。注文の状態遷移、契約の有効性、金額計算、在庫引当など、業務上の重要なルールは、ドメイン層に置くことで一貫性を保ちやすくなります。

ビジネスロジックがプレゼンテーション層やインフラ層に散らばると、仕様変更時に修正漏れが発生しやすくなります。オニオンアーキテクチャでは、ドメインロジックを中心に集約することで、この問題を防ぎます。

11.3 DDDとの親和性

オニオンアーキテクチャは、ドメイン駆動設計と非常に親和性が高いです。DDDでは、ドメインモデルを中心に設計し、業務知識をコードに反映することを重視します。オニオンアーキテクチャは、そのドメインモデルを技術的な詳細から守る構造を提供します。

特に、複雑な業務ルールを持つシステムでは、DDDとオニオンアーキテクチャを組み合わせることで、保守性と表現力の高い設計を実現しやすくなります。

12. リポジトリパターンとの関係

リポジトリパターンは、オニオンアーキテクチャでよく使われる設計パターンです。リポジトリは、ドメインオブジェクトの保存や取得を抽象化する役割を持ちます。ドメイン層やアプリケーション層は、具体的なデータベース実装ではなく、リポジトリの抽象を通じてデータを扱います。

この設計により、データベースやORMの詳細をインフラ層に隠せます。ドメイン層は、どのデータベースに保存されているか、どのようなSQLが実行されるかを知る必要がありません。これは、依存関係を内側へ向けるために重要です。

12.1 永続化の抽象化

リポジトリパターンの主な役割は、永続化を抽象化することです。ドメインオブジェクトを保存する、取得する、検索する、といった操作を抽象的なインターフェースとして定義します。

これにより、アプリケーション層はデータベースの詳細を意識せずにユースケースを実行できます。実際の保存処理はインフラ層に配置されるため、データベース変更の影響を限定できます。

12.2 インフラ層との分離

リポジトリのインターフェースと実装を分けることで、インフラ層との分離が可能になります。内側の層にはリポジトリの抽象を置き、外側のインフラ層に具体的な実装を置きます。

この構造により、ドメイン層やアプリケーション層はインフラ層へ直接依存しません。依存性逆転の原則を使って、外側の実装が内側の抽象に従う形になります。

12.3 保守性向上

リポジトリパターンを適切に使うと、保守性が向上します。データアクセス処理が一箇所に整理され、業務ロジックと永続化処理が混ざりにくくなるためです。

また、テスト時にはリポジトリをモックに差し替えることができます。これにより、データベースに依存しないユースケーステストやドメインテストが実行しやすくなります。

13. ドメイン駆動設計との関係

オニオンアーキテクチャは、ドメイン駆動設計と組み合わせて使われることが多い設計です。ドメイン駆動設計では、業務上の概念を中心にモデルを作り、そのモデルに業務ルールを表現します。オニオンアーキテクチャは、そのモデルを中心に据え、外部技術から守る構造を提供します。

DDDでは、エンティティ、集約、ドメインサービスなどの概念が重要になります。これらをドメイン層に配置し、アプリケーション層やインフラ層と分離することで、より保守しやすい設計になります。

13.1 Entity

エンティティは、識別子によって同一性を持つドメインオブジェクトです。業務上重要な対象物を表し、状態や振る舞いを持つことがあります。DDDでは、エンティティに業務ルールを適切に持たせることが重要です。

オニオンアーキテクチャでは、エンティティをドメイン層に配置します。これにより、エンティティはデータベースやUIに依存せず、業務上の意味を中心に設計できます。

13.2 Aggregate

集約は、関連するエンティティや値オブジェクトを一つの整合性境界としてまとめる考え方です。集約ルートを通じて内部オブジェクトを操作することで、業務ルールの一貫性を保ちます。

オニオンアーキテクチャでは、集約もドメイン層に配置されます。集約を適切に設計することで、データ整合性や状態変更のルールを中心に集約できます。

13.3 Domain Service

ドメインサービスは、特定のエンティティや値オブジェクトに自然に置けない業務処理を表現するために使われます。複数のドメインオブジェクトにまたがるルールや判断を扱う場合に有効です。

ただし、ドメインサービスにロジックを集めすぎると、エンティティが貧血化する可能性があります。オニオンアーキテクチャでは、ドメインサービスもドメイン層に置きつつ、責務の配置を慎重に考えることが重要です。

14. クリーンアーキテクチャとの違い

オニオンアーキテクチャとクリーンアーキテクチャは、非常に似た設計思想を持っています。どちらも、ビジネスルールを中心に置き、依存関係を内側へ向け、技術的な詳細を外側に配置します。そのため、実務ではほぼ同じ方向性のアーキテクチャとして扱われることもあります。

一方で、クリーンアーキテクチャはより一般化された考え方として説明されることが多く、ユースケース層やインターフェースアダプタ層などの役割が強調されます。オニオンアーキテクチャは、ドメインモデルを中心にした同心円構造として説明されることが多いです。

14.1 共通点

両者の共通点は、依存関係を内側へ向けることです。中心にはビジネスルールやドメインモデルがあり、外側にフレームワーク、データベース、UI、外部サービスなどが配置されます。

また、どちらも依存性逆転の原則を活用します。内側の層が外側の具体実装に依存しないように、インターフェースや抽象を使って依存関係を整理します。

14.2 設計思想の違い

オニオンアーキテクチャは、ドメインモデルを中心とした構造を強調します。ドメイン層を最も重要な中心に置き、その周囲にアプリケーション層やインフラ層を配置する考え方です。

クリーンアーキテクチャは、より広くビジネスルール、ユースケース、インターフェースアダプタ、フレームワークという分離を強調します。実装上の違いはプロジェクトによって異なりますが、どちらも目的は保守性と独立性の向上です。

14.3 適用場面の違い

オニオンアーキテクチャは、ドメインモデルを重視する業務システムやDDD採用プロジェクトと相性が良いです。複雑な業務ルールを中心に設計したい場合に適しています。

クリーンアーキテクチャは、より広範なアプリケーション設計に適用できます。Webアプリケーション、モバイルアプリ、APIサーバー、業務システムなど、さまざまな環境で利用できます。

15. ヘキサゴナルアーキテクチャとの違い

ヘキサゴナルアーキテクチャも、オニオンアーキテクチャと近い考え方を持つ設計です。ポートとアダプタという概念を使い、アプリケーションの中心を外部の入出力から分離します。外部システムやUI、データベースはアダプタとして扱われ、中心のアプリケーションはポートを通じて外部と接続します。

オニオンアーキテクチャが同心円構造で依存関係を説明するのに対し、ヘキサゴナルアーキテクチャは境界と接続点を強調します。どちらも、中心のビジネスロジックを外部の詳細から守ることを目的としています。

15.1 ポートとアダプタ

ヘキサゴナルアーキテクチャでは、ポートとアダプタが重要な概念です。ポートはアプリケーションが外部とやり取りするための抽象的な入口や出口であり、アダプタは具体的な外部技術との接続を担当します。

たとえば、APIコントローラー、データベースリポジトリ、外部サービスクライアントはアダプタとして扱えます。中心のアプリケーションは、具体的なアダプタではなくポートに依存します。

15.2 境界設計

ヘキサゴナルアーキテクチャでは、中心のアプリケーションと外部世界の境界設計が重視されます。外部からの入力や外部への出力をポートとして定義し、具体的な技術はアダプタで扱います。

オニオンアーキテクチャでも境界は重要ですが、説明の中心は同心円状の層構造です。ヘキサゴナルアーキテクチャは、より入出力の境界に注目した設計と考えると理解しやすいです。

15.3 依存管理の違い

両者とも依存関係を中心へ向ける点では共通しています。ただし、オニオンアーキテクチャは層の内外関係を強調し、ヘキサゴナルアーキテクチャは外部との接続点を強調します。

実務では、両者の考え方を組み合わせることも多くあります。中心にドメインやユースケースを置き、外部との接続をポートとアダプタで管理する設計は、どちらの思想にも沿っています。

16. オニオンアーキテクチャのメリット

オニオンアーキテクチャの主なメリットは、保守性向上、テスト容易性向上、技術変更への強さです。中心のドメインロジックを外部技術から切り離すことで、変更に強く、理解しやすい構造を作れます。

また、レイヤーごとの責務が明確になるため、チーム開発でも役割分担がしやすくなります。ドメイン層、アプリケーション層、インフラ層、プレゼンテーション層が分かれていれば、変更時の影響範囲も把握しやすくなります。

16.1 保守性向上

オニオンアーキテクチャでは、ビジネスロジックが中心に集約され、外部技術から分離されます。そのため、仕様変更時にどこを修正すべきか分かりやすくなります。

また、技術的な実装が外側に配置されるため、フレームワークやデータベースの変更が中心のドメインに影響しにくくなります。これは長期運用システムにおいて大きなメリットです。

16.2 テスト容易性向上

ドメイン層やアプリケーション層が外部技術に依存しないため、単体テストやユースケーステストを行いやすくなります。データベースや外部APIに接続しなくても、ビジネスロジックを検証できます。

テスト容易性が高い設計は、品質向上にもつながります。変更時にすばやくテストを実行できるため、リファクタリングや機能追加を安全に行いやすくなります。

16.3 技術変更への強さ

オニオンアーキテクチャでは、技術的な詳細を外側の層に閉じ込めます。そのため、データベース、外部API、UI、フレームワークなどを変更しても、中心のドメインロジックへの影響を抑えやすくなります。

もちろん、完全に影響をゼロにすることは難しいですが、変更の影響範囲を限定できます。これは、長期的な技術進化に対応するうえで非常に重要です。

17. オニオンアーキテクチャのデメリット

オニオンアーキテクチャには多くのメリットがありますが、デメリットもあります。代表的なものは、学習コスト、設計の複雑化、小規模開発との相性です。特に、単純なCRUD中心の小規模アプリケーションでは、導入コストがメリットを上回る場合があります。

また、層を分けること自体が目的になってしまうと、コード量が増え、かえって開発しにくくなることがあります。オニオンアーキテクチャは、ドメインが複雑で長期保守が必要なシステムほど効果を発揮します。

17.1 学習コスト

オニオンアーキテクチャを理解するには、依存関係ルール、依存性逆転の原則、ドメインモデル、リポジトリパターンなどの知識が必要です。そのため、チーム全体で共通理解を持つまでに時間がかかることがあります。

特に、従来のシンプルなレイヤード構成に慣れているチームでは、最初は抽象やインターフェースの配置に迷うことがあります。導入時には、設計方針やサンプルコードを整備することが重要です。

17.2 設計の複雑化

オニオンアーキテクチャでは、層やインターフェースを分けるため、コード構造が複雑になることがあります。単純な処理でも複数のファイルやクラスを経由するため、慣れていないと全体の流れを追いにくく感じる場合があります。

設計を複雑化しすぎないためには、必要な部分から段階的に導入することが重要です。すべての処理を過剰に抽象化するのではなく、変更されやすい部分や重要なドメインロジックを優先して保護します。

17.3 小規模開発との相性

小規模なアプリケーションや単純なCRUDアプリでは、オニオンアーキテクチャが過剰になる場合があります。業務ルールが少なく、長期的な変更も限定的であれば、よりシンプルな構成の方が開発効率が高いこともあります。

ただし、小規模でも将来的に業務ロジックが増える可能性が高い場合は、最初から軽量な形でオニオンアーキテクチャの考え方を取り入れる価値があります。重要なのは、プロジェクトの規模や複雑さに応じて判断することです。

18. テスト戦略との関係

オニオンアーキテクチャは、テスト戦略とも相性が良い設計です。ドメイン層やアプリケーション層が外部技術に依存しないため、ビジネスロジックやユースケースを独立してテストできます。これは、テストの実行速度や安定性にもつながります。

また、インフラ層を抽象化しているため、テスト時にモックやスタブを使いやすくなります。これにより、データベースや外部APIに依存しないテストを作成でき、継続的インテグレーションにも組み込みやすくなります。

18.1 ドメインテスト

ドメインテストでは、エンティティ、値オブジェクト、ドメインサービスなどのビジネスルールを検証します。ドメイン層が外部技術に依存していなければ、テストは高速で安定します。

たとえば、注文のキャンセル条件、契約期間の妥当性、金額計算のルールなどを、データベースなしでテストできます。これは、ドメインロジックの品質を高めるために非常に有効です。

18.2 ユースケーステスト

ユースケーステストでは、アプリケーション層の処理フローを検証します。注文作成、請求発行、会員登録など、実際の利用シナリオに近い処理をテストします。

リポジトリや外部サービスをモック化できれば、ユースケースのロジックを独立して検証できます。これにより、外部環境に依存しない安定したテストを作成できます。

18.3 モック活用

オニオンアーキテクチャでは、抽象に依存する設計が多いため、モックを活用しやすくなります。リポジトリ、通知サービス、外部APIクライアントなどをモックに差し替えることで、テスト対象を限定できます。

モックを使うことで、テストの実行速度が上がり、外部サービス障害の影響も受けにくくなります。ただし、モックを使いすぎると実際の統合問題を見落とす可能性があるため、統合テストとのバランスも重要です。

19. マイクロサービスとの関係

オニオンアーキテクチャは、マイクロサービス設計とも相性があります。マイクロサービスでは、各サービスが独立したドメイン境界を持ち、他サービスと疎結合に連携することが重要です。オニオンアーキテクチャを使うことで、各サービス内のドメインロジックを保護しやすくなります。

ただし、マイクロサービス全体の設計では、サービス境界、データ所有権、API契約、イベント連携なども考える必要があります。オニオンアーキテクチャは、個々のサービス内部の設計を整えるために有効です。

19.1 サービス独立性

マイクロサービスでは、各サービスが独立して開発・テスト・リリースできることが重要です。オニオンアーキテクチャを使うと、サービス内部でドメインロジックと技術実装を分離できるため、独立性を保ちやすくなります。

サービス独立性が高ければ、外部APIやデータベース実装を変更しても、中心のドメインロジックを守りやすくなります。これは、マイクロサービスの長期運用において重要です。

19.2 ドメイン境界

マイクロサービスでは、ドメイン境界の設計が非常に重要です。どのサービスがどの業務責務を持つのかを明確にしなければ、サービス間の依存が増え、分散モノリスになってしまう可能性があります。

オニオンアーキテクチャは、サービス内部でドメインを中心に設計するため、境界の意識を高めやすくなります。ドメイン駆動設計の境界づけられたコンテキストとも相性が良いです。

19.3 拡張性向上

オニオンアーキテクチャを採用すると、サービス内部の拡張性も向上します。ドメイン層を中心に保ちながら、外側のインフラやプレゼンテーションを変更・追加しやすくなるためです。

たとえば、同じユースケースをREST API、メッセージキュー、バッチ処理から呼び出す場合でも、アプリケーション層を再利用できます。これにより、機能拡張時の重複を減らせます。

20. Webアプリケーションでの活用

オニオンアーキテクチャは、Webアプリケーション開発でも活用できます。APIサーバー、業務システム、SaaSなど、複雑なビジネスロジックを持つアプリケーションでは特に有効です。UIやAPIの変更と、ドメインロジックの変更を分離できるためです。

Webアプリケーションでは、フレームワークの都合でコントローラーやモデルに処理が集中しがちです。オニオンアーキテクチャを意識すると、コントローラーは入力の受け取りに集中し、ユースケースやドメインロジックは内側の層へ分離できます。

20.1 APIサーバー設計

APIサーバーでは、コントローラーがリクエストを受け取り、アプリケーション層のユースケースを呼び出します。レスポンスの整形はプレゼンテーション層で行い、業務処理はアプリケーション層やドメイン層に委譲します。

この構成にすると、API仕様が変わっても、中心の業務ロジックへの影響を抑えられます。また、同じユースケースを別のインターフェースから再利用しやすくなります。

20.2 業務システム

業務システムでは、複雑なルールや例外条件が多く存在します。承認フロー、請求処理、契約管理、在庫管理などは、ドメインロジックを適切に整理しないと保守が難しくなります。

オニオンアーキテクチャを使うと、業務ルールをドメイン層に集約し、画面やデータベースの都合から切り離せます。これにより、業務変更に対応しやすいシステムを作れます。

20.3 SaaS開発

SaaSでは、機能追加や仕様変更が継続的に発生します。また、テナント管理、課金、権限、通知、外部連携など、複雑なドメインが含まれることがあります。オニオンアーキテクチャは、このような長期運用型のプロダクトと相性が良いです。

中心のドメインロジックを安定させ、外側の技術やUIを柔軟に変更できる構造を作れば、プロダクトの成長に合わせて拡張しやすくなります。

21. よくある設計ミス

オニオンアーキテクチャを導入しても、設計ミスがあると本来の効果を得られません。代表的なミスには、ドメイン層からデータベースへ直接依存すること、責務が曖昧になること、レイヤー違反が発生することがあります。

これらのミスは、依存関係ルールや責務分離の理解が不十分な場合に起こりやすいです。アーキテクチャは図で説明するだけではなく、実装ルールとしてチーム全体に共有する必要があります。

21.1 ドメイン層からDBへ直接依存する

最もよくあるミスの一つが、ドメイン層からデータベースへ直接依存することです。ドメインエンティティがORMやSQL、データベース接続に依存すると、ドメイン層が技術的な詳細に引きずられます。

これを防ぐには、データアクセスをリポジトリの抽象として扱い、具体的な実装をインフラ層に配置します。ドメイン層は永続化の詳細を知らない状態に保つことが重要です。

21.2 責務が曖昧になる

レイヤーを分けても、責務が曖昧だと設計は崩れます。たとえば、アプリケーション層にドメインルールを書きすぎたり、プレゼンテーション層に業務処理を書いたりすると、層の意味が薄れます。

責務を明確にするには、各層が何を担当し、何を担当しないのかをチームで定義する必要があります。コードレビューでも、処理が適切な層に配置されているかを確認することが重要です。

21.3 レイヤー違反が発生する

レイヤー違反とは、本来依存してはいけない方向へ依存することです。たとえば、ドメイン層がインフラ層のクラスを参照したり、アプリケーション層がプレゼンテーション層の型に依存したりする状態です。

レイヤー違反が増えると、オニオンアーキテクチャの利点が失われます。静的解析、依存関係チェック、レビューを活用して、依存方向を継続的に守ることが重要です。

22. 実装時のポイント

オニオンアーキテクチャを実装する際には、インターフェースの活用、ドメインロジックの保護、依存方向の維持が重要です。単にフォルダを分けるだけでは不十分で、実際の依存関係が正しく内側へ向いている必要があります。

また、最初から大きく複雑な構成にする必要はありません。プロジェクトの規模やドメインの複雑さに応じて、必要な部分から導入することが現実的です。重要なのは、ビジネスロジックを外部技術から守るという目的を見失わないことです。

22.1 インターフェース活用

インターフェースは、依存性逆転を実現するために重要です。内側の層に必要な抽象を定義し、外側の層で具体的な実装を提供します。これにより、内側の層は外部技術に直接依存しなくなります。

ただし、すべてのクラスにインターフェースを作る必要はありません。外部依存や変更されやすい部分、テストで差し替えたい部分などに絞って活用することが重要です。

22.2 ドメインロジックの保護

実装時には、ドメインロジックが外側の層に漏れないように注意します。コントローラーやインフラ層に業務判断が書かれている場合、ドメインロジックが分散している可能性があります。

ドメインロジックを保護するには、エンティティ、値オブジェクト、ドメインサービスなどに適切に配置します。業務上の判断や制約は、中心のドメイン層に集約することを意識します。

22.3 依存方向の維持

オニオンアーキテクチャでは、依存方向を維持することが非常に重要です。実装が進むと、便利さを優先して外側のクラスを内側から参照してしまうことがあります。これは長期的には設計劣化につながります。

依存方向を維持するには、パッケージ構成、依存関係チェック、コードレビューを活用します。チーム全体で依存関係ルールを理解し、継続的に守ることが重要です。

23. 実務でのベストプラクティス

オニオンアーキテクチャを実務で活用するには、ドメインを中心に考え、技術要素を外側へ配置し、継続的にアーキテクチャを改善することが重要です。設計は一度決めて終わりではなく、プロダクトの成長に合わせて見直す必要があります。

また、チーム全体で共通理解を持つことも大切です。レイヤーの役割や依存関係ルールが共有されていないと、実装者ごとに判断がばらつき、アーキテクチャが崩れやすくなります。

23.1 ドメインを中心に考える

実務では、フレームワークやデータベースから設計を始めたくなることがあります。しかし、オニオンアーキテクチャでは、まずドメインを中心に考えます。業務上の重要な概念、ルール、状態遷移を明確にし、それをドメインモデルとして表現します。

ドメインを中心に考えることで、技術都合ではなく業務価値に沿った設計ができます。これは、長期的に保守しやすいシステムを作るうえで重要です。

23.2 技術要素を外側へ配置する

データベース、外部API、UI、フレームワーク、クラウドサービスなどの技術要素は、外側の層に配置します。これらは変更されやすい詳細であり、中心のドメインモデルに直接影響を与えないようにします。

技術要素を外側へ配置することで、差し替えや変更がしやすくなります。たとえば、データベース変更や外部サービス変更が発生しても、中心の業務ルールを守りやすくなります。

23.3 継続的にアーキテクチャを改善する

アーキテクチャは、最初に決めた形を永久に守るだけではありません。仕様変更、チーム拡大、技術変更、ドメイン理解の深化に応じて改善する必要があります。

コードレビューやリファクタリングを通じて、レイヤー違反や責務の曖昧さを継続的に見直します。小さな改善を積み重ねることで、アーキテクチャの健全性を維持できます。

24. オニオンアーキテクチャが向いているケース

オニオンアーキテクチャは、すべてのプロジェクトに必要なわけではありません。特に向いているのは、大規模システム、業務ロジックが複雑なシステム、長期運用プロジェクトです。これらのシステムでは、保守性や変更への強さが重要になるため、オニオンアーキテクチャの効果が大きくなります。

一方で、単純なCRUD中心の小規模アプリケーションでは、導入コストが高く感じられる場合があります。プロジェクトの規模、複雑さ、運用期間、変更頻度を考慮して採用を判断することが重要です。

24.1 大規模システム

大規模システムでは、コード量が増え、関係者も多くなります。責務や依存関係が曖昧なまま開発を進めると、変更時の影響範囲が分かりにくくなり、保守が難しくなります。

オニオンアーキテクチャを使えば、層ごとの責務と依存方向を整理できます。これにより、大規模なコードベースでも構造を把握しやすくなります。

24.2 業務ロジックが複雑なシステム

業務ロジックが複雑なシステムでは、ドメインモデルを中心に置く価値が高くなります。承認フロー、料金計算、契約管理、在庫管理、権限管理など、複雑なルールを持つシステムでは、ドメインロジックを整理することが重要です。

オニオンアーキテクチャは、業務ルールをドメイン層に集約し、技術的な実装から守ります。これにより、仕様変更にも対応しやすくなります。

24.3 長期運用プロジェクト

長期運用されるプロジェクトでは、技術変更や要件変更が繰り返し発生します。短期的にはシンプルな実装で十分でも、数年単位で運用する場合は保守性が重要になります。

オニオンアーキテクチャは、長期運用における変更耐性を高めます。中心のドメインを安定させ、外側の技術要素を変更可能にすることで、プロジェクトの成長に対応しやすくなります。

おわりに

オニオンアーキテクチャは、ドメインモデルを中心に据えるアーキテクチャパターンです。システムを同心円状の層として捉え、中心にビジネスルールを置き、外側に技術的な実装を配置します。最大の特徴は、依存関係を常に内側へ向けることです。

この設計により、ドメインロジックをデータベース、UI、外部サービス、フレームワークなどの技術的な詳細から保護できます。技術変更が発生しても、中心の業務ルールへの影響を抑えやすくなります。これは、長期的な保守性や拡張性を高めるうえで非常に重要です。

オニオンアーキテクチャは、依存性逆転の原則、リポジトリパターン、ドメイン駆動設計と密接に関係しています。抽象に依存し、具体実装を外側に配置することで、疎結合でテストしやすい構造を作れます。また、クリーンアーキテクチャやヘキサゴナルアーキテクチャとも共通点が多く、いずれもビジネスロジックを中心に守ることを目的としています。

一方で、オニオンアーキテクチャには学習コストや設計の複雑化というデメリットもあります。小規模で単純なアプリケーションでは、過剰設計になる可能性があります。そのため、プロジェクトの規模、ドメインの複雑さ、長期運用の必要性を考慮して採用を判断することが重要です。

実務で活用する際は、ドメインを中心に考え、技術要素を外側へ配置し、依存方向を継続的に守ることが大切です。オニオンアーキテクチャを適切に導入できれば、変更に強く、テストしやすく、長期的に保守しやすいソフトウェアを構築できるでしょう。

LINE Chat