DDDは、特定の技術に依存していないため自由にアーキテクチャを選択することが可能です。
以下は、ドメイン駆動設計と同時に語られることが多いアーキテクチャです。
アーキテクチャ選定のポイント
以下の要素が判断材料になります。
- 機能要求(ユースケース、ユーザーストーリー、ドメインモデルのシナリオ)
- 品質要求(性能、エラー制御、SLA、リアルタイム性など)
レイヤードアーキテクチャ
ドメイン駆動設計の文脈で登場するアーキテクチャの中で最も伝統的でかつ有名なアーキテクチャ。昔ながらの層にしてアプリを管理する。(クラサバなど。)
メリット
誰にでも理解しやすいシンプルなアーキテクチャ
デメリット
ドメイン層がインフラ層に依存しているため、ビジネスロジックをドメイン層で管理することが難しくなる。
4つの層で考えます。上位のレイヤーは、自分より下位のレイヤーに依存することを許します。
- ユーザーインターフェース(最上位)
- アプリケーション(上位)
- ドメイン(下位)
- インフラストラクチャ(最下位)
ドメイン層
最も重要で、ドメインオブジェクトを隔離して他の層に流出しないようにします。
- ユースケースやユーザーストーリーを実装する。
- 「ファクトリ」か「集約」のコンストラクタにてインスタンスを生成する。
- ドメインサービスが含まれる。(ステートレスに操作する。)
- イベント駆動の場合は、「ドメインイベント」を発行する。
アプリケーション層
ドメイン層の住人を取りまとめる層、アプリケーションサービスが挙げられます。
アプリケーションサービスクラスなどがここに該当します。
- プレゼンテーション層から使用される。
- 「アプリケーションサービス」を用意する。
プレゼンテーション層
ユーザーインターフェースとアプリケーションを結びつけます。そのインターフェースはWebであってもCLIであっても良い。
Webフレームワークで言えば、コントローラがこれにあたります。
- ドメイン層のモデルは極力つかなわないようする。
- ドメインがビューの影響を受けることがないように、プレゼンテーションモデル(ViewModel)を作ることが推奨される。
インフラストラクチャ層
他の層を支える技術基盤へのアクセスを提供する層、アプリへのメッセージ送信や、ドメインの永続化などを行うモジュールなど。
- 「リポジトリ」を利用して永続化する。
ヘキサゴナルアーキテクチャ
六角形をモチーフに代表とされるアーキテクチャ。「アプリケーション(ドメイン)層」を中心として考えて「ユーザー操作や自動テストなど」の入力側もデータベースなどの出力側も全て差し替え可能な外部インターフェースとして扱うといった考え方。UIやインフラストラクチャなども独立したアダプタで管理します。
コンセプト
アプリケーションとそれ以外のインターフェースが付けはずしができるというもの。
メリット
- ドメイン層以外もシンプルに維持することが可能です。
- 他のアダプタが決まってなくても暫定的にアダプタを用意して開発を進められる。
- REST APIと相性が良い。
ポート&アダプター
ポート
システムの目的に応じる。例えば、「データの永続化を行うためのポート」や「フロントエンド と接続するためのポート」など。
アダプター
技術的な差し替え可能な部分。例えば、「DBと接続するためのアダプタ」や「自動テスト用モックを使うためのアダプタ」など。
DIPに基づいたレイヤー化アーキテクチャ
メリット
DIP(依存関係逆転の原則)を導入したことによりドメイン層が他の層に依存しなくなった。ドメイン層のメンテナンスやテストがしやすくなる。
デメリット
インフラストラクチャが肥大化しやすくなる。
クリーンアーキテクチャ
4つの同心円が特徴的な図によって説明されるアーキテクチャ
思想
ビジネスルールをカプセル化したモジュールを中心に捉えるというのがコンセプト。ユーザーインターフェースやデータストアなどの詳細を端に追いやって依存の方向を内側に向けます。
円の外側に行くほど変化が大きく不安定になっていくという思想になっています。不安定な外側から安定した内側を守るという設計ですね。内側を守るために「DIP(依存関係逆転の原則)」を適用するというわけです。DIPが根幹となる考え方になっています。依存先が不安定なコードになっているとダメということですね。
外側→内側に依存しているのは良いですが、内側→外側に依存してはダメです。
エンティティ
企業のビジネスルール。複数のアプリケーションにまたがる処理を共通化したより抽象度の高いルール。
ドメイン駆動設計のエンティティとは一致しない。どちらかと言えば、ビジネスルールをカプセル化したオブジェクトないし、データ構造と関数のセットを刺すのでドメインオブジェクトに近い概。
ユースケース
アプリケーション固有のビジネスルール。エンティティを操作しながらアプリケーションが必要とする処理を行う。
注意点
高度に抽象化された手法であり、具体的な実装方法まで提示しているわけではないのでそのままソフトウェア開発に適用することはできない。
ヘキサゴナルアーキテクチャとの違い
実装の仕方が詳しく言及されているか。コンセプトを実現する具体的な実装方針が明示されている。
TypeScriptで言えば
importやrequireが依存しているコードになります。import先のコードが安定している(置き換え可能になっている)ことが望ましいです。
イベント駆動アーキテクチャとは?
イベントを待機して起こったイベントに応じて処理を行うプログラムスタイル
メリット
ユーザーに町が発生したりタイムアウトが発生したりするような長いタスクへの対策になる。
ヘキサゴナルアーキテクチャの場合
複数ドメイン間で連携を行う分散処理に適している。
パイプ&フィルター
イベント駆動のシンプルな形
メリット
コンポーネント単位で再利用したり、ボトルネック部分のリソースを増強したりできる。
デメリット
処理の再利用やチューニングが困難
長期プロセス(サーガ:並列パイプライン)
並列実行で処理速度を向上できる。
メリット
速度が速い。
デメリット
正常なユースケースだけでなく、失敗を想定したワークフローも組み込む必要があるので難易度が高い。
- 障害復旧
- 能動的/受動的タイムアウトの管理
- 重複イベントのメッセージ管理
イベントソーシング
履歴管理のために使うパターン(GitやSVNに似ている。)
三層アーキテクチャ
プレゼンテーション層、アプリケーション層、データ層の3層があります。
フロントとバックエンドでそれぞれ責務がごっちゃになってしまうことがあると思います。
解決案:アプリケーション層をフロントに寄せる
バックエンドはデータのみ持たせる構成にする案です。
これだと、プラットフォームごとにロジックを実装し直す必要が発生してしまいます。(React向け、iOS向け、Android向け)
解決方法
クロスプラットフォーム実装
iOSやAndroidをまとめて開発できるReact NativeやFlutterなどです。
CordovaやTitanium MobileなどはiOS、Android、Web全て対応できますが、WebViewベースなので重くなりがちで避けられます。
クロスコンパイル、トランスパイルによるライブラリ実装
「Kotlin/Native、Kotlin/JS」などが該当します。Kotlinでライブラリを実装してiOS、Androidに対応させる手法です。
ただ、これは認証ロジックやDBへのアクセスはバックエンドでしかできないので、セキュリティ面を考えると難しそうです。
この記事へのコメントはありません。