読書メモ:ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本 1

DDD自体が複雑な概念なので、その用語とパターンに集中して解説する入門書。

長くなりそうなので、メモは何回かに分割予定。

この本で慣れた後に本格的な教科書へ進もう、という本の意図通りの目的で購入。

知りたかったことは、

  • 本来の(オブジェクト指向をルートとする)DDDにおける用語やパターンの定義
  • オブジェクト指向でないOutSystemsにDDDを適用するにあたって、そのパターンはそのまま/手を入れれば使えるのか、代替策を考えるべきなのか、それともOutSystemsでは利用を諦めるべきか、という点についてのヒント

Introductionの

オブジェクト指向以外のパラダイムをもつ言語であっても、本書のエッセンスをソフトウェア開発に役立てることは可能です。

という言葉どおり、OutSystemsに、そのエッセンスを適用する方法を見出したい。

以下、章ごとのメモ。

Chapter2 ドメイン固有の値を表現する「値オブジェクト」

最初に解説されるこのパターンがすでに、OutSystemsに適用するにあたって困難がある。

この「値オブジェクト」は、ドメインの知識を表現するパターンの1つで、開発するシステムで固有の値を表すオブジェクト(実際はOOPL前提なのでクラス定義)。

値オブジェクトは決してただのデータ構造体のことを指しているわけではありません。オブジェクトに対する操作をふるまいとして一処にまとめることで、値オブジェクトは自身に関するルールを語るドメインオブジェクトらしさを帯びるのです。(PAGE 74)

ということなので、

  • データ構造を持ち
  • そのデータに対する振る舞い(メソッド)

をまとめたもの。

その目的として

値オブジェクトを使うモチベーションとして紹介するのは次の4つです。

・表現力を増す

・不正な値を存在させない

・誤った代入を防ぐ

・ロジックの散在を防ぐ(PAGE 76)

が挙げられている。

というわけで、これをOutSystemsにマッピングするなら、

値オブジェクトにされた概念ごとに

  1. Structure(Public=Yes)
  2. Entityを操作するためのPublic Action

を定義する。OutSystemsにはクラスは無く、これら要素の入れ物としてモジュールがあるため、1モジュールにこのセットを複数含めることになるはず(複数のStructureとその処理を1モジュール内に含める)。

ただ、OutSystems内だと「データと対応する操作」を小さな単位に封じ込めるクラスのような仕組みがなく、モジュール内では自由に他のデータにアクセスできてしまう。

Chapter3 ライフサイクルのあるオブジェクト「エンティティ」

値オブジェクトと似ているが、こちらは、各オブジェクトを一意に識別する識別子を持つのが違い。

ライフサイクルが存在し、そこに連続性が存在するかというのは大きな判断基準になります。(PAGE 106)

というのも併せて考えると、OutSystemsで表すならEntity。ただし、Structureと同じく、Entity自体に振る舞いをラッピングすることはできず、同じモジュールであれば、自由にアクセスできる。

実装に際しては、Core Entity Patternを使う[1]詳細はEntityの更新を1箇所に限定するパターン

  1. EntityをPublic=Yes かつ Expose Read Only=Yesで定義
  2. Entityを操作するActionをPublic=Yesで作成

これらの要素をCore Business Layerの特定のモジュールにまとめるというやり方。

Chapter4 不自然さを解決する「ドメインサービス」

値オブジェクトやエンティティのクラスに実装すると不自然になる振る舞い(メソッド)を独立した別のクラスに実装するものがドメインサービス。

不自然になる振る舞いの例としては、「データストアに同じユーザーが既存でないか確認する処理を、Userクラスに持たせる」「その物流拠点から別の物流拠点まで物品を移動する処理を、物流拠点クラスに持たせる」など複数のオブジェクトにまたがるものが挙げられている。

注意すべきアンチパターンとして「ドメインモデル貧血症」というのがあるそうで、

ドメインオブジェクトに本来記述されるべき知識やふるまいが、ドメインサービスやアプリケーションサービスに記述され、語るべきことを何も語っていないドメインオブジェクトの状態をドメインモデル貧血症といいます。(PAGE 126)

というもの。ちなみにドメインオブジェクトはドメインモデルを実装したもの。

以上を踏まえてOutSystemsへのマッピングを考えると

  1. 値オブジェクト(Structure+Action)やエンティティ(Entity+Action)を閉じ込めたモジュールには、そのデータと共に記述されるべき処理はモジュール内に作成されるように注意する
  2. 値オブジェクトやエンティティに収まらない、複数オブジェクトに跨がる処理などは独立したCore BusinessレイヤーのモジュールにActionとして実装する

という感じか。1と2は別モジュールにしておかないと、処理がこんがらがって、結果的に上にあった「ドメインモデル貧血症」になるかもしれない。