Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

実践DDD本 第10章「集約」~トランザクション整合性を保つ境界~

IDDD本から理解するドメイン駆動設計 第10回

  • LINEで送る
  • このエントリーをはてなブックマークに追加

 ドメイン駆動設計(DDD)は、顧客と開発者が業務を戦略的に理解し、共通の言葉を用いてシステムを発展させていく設計手法です。前回は「モジュール」について紹介しました。10回目となる今回は「集約」について解説します。

目次

DDDにおける集約

 DDDにおける集約(Aggregates)とは、オブジェクトのまとまりを表し、整合性を保ちながらデータを更新する単位となります。通常はオブジェクトの集まりの「境界線」の意味で使われ、オブジェクト群の生成/読み込み/変更/保存といったライフサイクル管理が行われます。

外部から集約を操作できる「集約ルート」

 外部から集約を操作する場合、代表オブジェクトである「集約ルート(≒ルートエンティティ)」のみ参照することができます。集約ルートを操作することで集約全体の整合性を保ちながらデータを変更できます。

DDDの「集約」のイメージ
DDDの「集約」のイメージ

 上図の例では、注文に関わるオブジェクト群が集約の「境界線」となっています。操作をしたい場合「注文」という「集約ルート」に変更依頼をすることができます。集約内部にある「注文明細」や「配送先住所」といった集約ルート以外のオブジェクトに直接指示を出すことはありません。

集約が担う境界内の「整合性」

 集約はオブジェクト群の整合性の境界を保ちながらデータを更新します。整合性には以下の2つが存在しています。

 DDDの集約は、即時的な整合性である「トランザクション整合性」と同義です。このことから、トランザクションの分析をした後でなければ、集約の設計が適切かを判断できません。なお、トランザクションという言葉は使っていますが、特定のDBのトランザクション命令そのものではありません。あくまで(結果整合性とは対照的に)同期的に整合性を保つ必要性を表しています。

 上の注文例の場合、注文明細として100円の追加をした場合には、注文合計額にも100円が同時に加算された上で確定される必要があります。

IDDDのサンプルプロジェクトで考える集約

 それでは、SaaSOvationを例に集約について見ていきましょう。前回まで紹介してきた通り、アジャイルプロジェクトのサービスに関するモデリングを見ていきます。ここでは、各プロダクトは複数のバックログアイテム(課題)を持ちます。そしてスプリント(2週間などのタイムボックス期間)やリリース(デプロイ日)を持ちます。これらを集約の観点からモデリングしてみます。

巨大な集約の問題点

 まず、何も考慮せずにモデリングした場合、大きな集約ができ上がります。こうした大きい集約「プロダクト」を作成した場合、数千のバックログアイテム、スプリント、リリースオブジェクトを毎回メモリに読み込み、更新する必要があり、性能面で期待することはできません。

大きな集約の問題点
大きな集約の問題点

 モデリングは簡単ですが、この場合、実用に耐えません。複数のユーザーが同時に操作した場合に、トランザクションが衝突する可能性が非常に高いためです。通常、エンティティの実装を行う場合、楽観的並行性制御と呼ばれる手法がよく用いられます。この手法では、エンティティがバージョン番号を保持しており、なんらかの変更を行う度にバージョン番号を加算していきます。もし別のユーザーが集約を更新済みの場合、想定しているバージョン番号と異なるため、後から更新しようとしたユーザーがエラーとなります。そのため別のユーザーに更新された後の最新値を取得して、更新処理をやり直す必要があります。

小さな集約の特徴

 そこで、大きな集約の問題を回避するために、小さい集約を複数作成することにします。これまでひとつだった集約を複数に分解します。各集約それぞれに集約ルートが存在することになります。

小さな集約(4つの集約に分割し識別子を参照)
小さな集約(4つの集約に分割し識別子を参照)

 この例では、大きな集約を分割し、バックログアイテムの集約にフォーカスしています。プロダクト/リリース/スプリントといったエンティティは、別の集約のルートエンティティとしてモデリングしています。そして、他の集約ルートを直接参照するのではなく、識別子(ID)のみを参照しています。トランザクションは、集約を取り扱うアプリケーションサービス(11章)側で制御することになります。大きな集約と小さな集約の違いについて簡単に見てみましょう。

大きい集約と小さい集約の違い
項目 大きい集約 小さい集約
トランザクションの衝突 多い 少ない
設計難易度
スケーラビリティ・性能
エンティティ間の依存 直接参照 ID参照

 このように、集約を小さくすることでトランザクションが衝突しなくなります。なお、要件を満たすだけの性能が出せるかは、実際のシナリオに基づいた検証を行う必要があります。参考までに、IDDD本の中では、ひとつの集約が144個のオブジェクトを保持することを試算し、ここでは問題ないと判断しています。

[コラム]DDD本における集約の解説

 DDD本でEvans氏は

ほとんどのビジネスドメインは非常に強く相互に結びついているので、結局はオブジェクトの参照を通じて、長くて深い経路を辿ることになる。ある意味で、こうしたもつれはこの世界の現実を反映している。現実には、はっきりした境界が引いてもらえることはめったにないのだ。

と述べ、ドメインが大きくなることは自然な傾向だと述べています。それをふまえた上で、トランザクションや性能面の問題に対応する現実的な手法として集約を以下の通り定義しています。

エンティティと値オブジェクトを集約の中にまとめ、各集約の周囲に境界を定義すること。各集約に対してルートとなるエンティティを1つ選び、境界の内部に存在するオブジェクトへのアクセスは、そのルートを経由して制御すること。外部のオブジェクトが参照を保持できるのは、ルートのみとすること。内部のメンバに対する一時的な参照を渡してよいのは、単一の操作で使用する時だけだ。ルートがアクセスを制御するので、内部が知らないうちに変更されることはなくなる。この取り決めにより、どんな状態変化においても、集約内にあるオブジェクトと集約全体に対して、不変条件をすべて強制することが現実的になる。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • WINGSプロジェクト 青木 淳夫 (株式会社ネクストスケープ)(アオキ アツオ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XMLD...

バックナンバー

連載:IDDD本から理解するドメイン駆動設計

もっと読む

All contents copyright © 2005-2018 Shoeisha Co., Ltd. All rights reserved. ver.1.5