はじめに

この記事の続きです.

設計とはデータ型を決めること

前回の記事を引用すると,

アプリケーションを設計するということは, まずそのアプリケーションで利用されるデータ型を定義するということ

その後, 自分が定義したデータ型を操作するインタプリタを設計する.

Java をつかっているものの, Java はそれらのデータ型のインタプリタでしかない

オブジェクト指向設計とはなんだろうか?

そんなことを考えていたとき, オブジェクト指向設計の本としてもっとも名高い本, エリック・エバンズのドメイン駆動設計が本屋にあった

思わず衝動買いした.

ドメイン駆動設計

ドメイン駆動設計とは, Eric Evans の提示した設計手法. DDD と略す.

本はこれ.

データ型の設計とは

抽象データ型については前回の記事でまとめた.

抽象データ型もオブジェクトも性質と操作の管理の仕方が異なるだけで, 性質や操作自体は同一だ.

抽象データ型を設計して, 型のインタプリタを作成すること.

DDD でいえば, エンティティと値オブジェクトを決めて, それを操作するサービスや集約, 生成方法を決定すること.

両者はおなじことを言っているように感じた. アプリケーションで扱う型を決めるということは, ドメイン層における, エンティティと値オブジェクトを決めるということ.

これが, とりありず前半部分を読んだ感想だ.

DDD 本の前半まとめ

以下 DDD 本の読書メモ.

とくに, リポジトリの章は, 明日まさに仕事で考えないといけないことなので, とても参考になった.

基本原則 (前書きより)

  • コアドメインに集中すること
  • ドメインの実践者とソフトウェアの実践者による創造的な共同作業を通 じてモデルを探求すること
  • 明示的に境界づけられたコンテキストの内部で, ユビキタス言語を語ること.

基本用語

巻末に用語集がある.

ドメイン

  • 知識, 影響, 活動の領域.
  • アプリケーションが対象とする業務領域.

ユビキタス言語 (p24)

ドメインエキスパートと開発者の間で使う共通言語.

  • モデルを言語の骨格として使用する.
  • チーム内のすべてのコミュニケーションとコードにおいて, 厳格にその言語を用いること.
  • 図, ドキュメント, コード, 会話において, 同一の言語を用いること.

UML

  • UML によって議論に確固とした基盤が与えられる.
  • クラス図と相互作用図がつかいやすい.
  • オブジェクトの名前や関係性を共有できる.
  • オブジェクトの概念, なにをおこなうかははっきり伝えることができない.
  • クラス図の操作名やコミュニケーションでそれとなくは伝えられる. はっきり伝えるためには, 補足的なテキストや会話が必要.
  • 説明のためのモデルはオブジェクトモデルである必要は全くなく, 通常はそうでないほうがよい.

ドキュメント

  • モデルは図ではない.図はコミュニケーションの手段に過ぎない.
  • 設計に関する本質的な詳細は, コードにおいてとらえられる.
  • すでにコードでうまくやっていることを, ドキュメントでもやろうとすべきでない.
  • ドキュメントは活動の役にたたなければならず, 最新の状態を保たなければならない.
  • ドキュメントを最小限にとどめ, その重点をコードと会話の補足に絞る ことで, ドキュメントを常にプロジェクトに結びつけた状態にたもつ.

モデル駆動設計 (P45)

  • 分析モデルと設計ととう二分法を捨て去り, 両方の目的に 使える単一のモデルを探し出す.
  • モデリングと設計のプロセスは, 反復されるただ 1 つのループ.
  • 設計で必要とする用語法と責務の基本的な割り当てをモデルから引き出すこと.
  • 開発は, モデルと設計, コードを単一の活動として改良しつづける, イテレーティブなプロセスとなる.

モデル駆動設計の構成要素 (p65)

レイア化アーキテクチャ (p66)

以下の 4 つに分解される.

  1. UI 層

    ユーザとの相互作用の境界となる層 (Web 層, プレゼンテーション層)

  2. アプリケーション層 (サービス層)

    ドメインオブジェクトを操作することで, ソフトウェアが果たすべき仕事を実現する層. 薄くシンプルにたもち, 仕事はドメイン層のオブジェクトにやらせる.

  3. ドメイン層

    ビジネス上の概念を表現する層.モデル層

  4. インフラストラクチャ層

    上の 3 層を支える技術的な基盤となる層. データベース, 通信など.

エンティティ (参照オブジェクト) (p87)

属性ではなく,連続性と識別性によって定義されるモノ

  • 連続性
    • 状態をもつ.
    • ライフサイクルをもつ.
  • 識別性
    • 一意であることが保証された記号をそえることによって実現できる.
    • ID, 座席番号, 出席番号… システムが生成する.

振る舞いと属性を, 他のオブジェクトに移動できないか検討する. (別のエンティティ, 値オブジェクト, サービス..)

値オブジェクト (p95)

事物の特性を記述するオブジェクト. 概念的な同一性はない.

  • 識別子を持たない (与えてはいけない) 属性にのみ興味がある.
  • オブジェクトは不変でなければならない (fatal)
  • 通例読み出し専用のオブジェクト.
  • Flyweight パターンを用いて共有できる.
  • しばしば, オブジェクト間のメッセージでパラメータとして渡される.

サービス (p103)

  • 操作をおこなう責務をもつ.
  • ソフトウェアが実行すべきことに対応し, 状態には対応しない.
  • オブジェクト自身に操作をさせずに, それぞれごとにオブジェクトの操 作をするものは, しばしばマネージャーと呼ばれる.それは手続的だ.
  • 状態をもたせないこと.
  • 要求に応じてクライアントのために行われるなにか. なので, 名詞よりも動詞として定義される.
  • 操作名がユビキタス言語の一部になること.

モジュール / パッケージ (p108)

  • モデルの意味ある一部.
  • モジュール内は高凝縮, モジュール間は低結合.
  • モジュールは本で言えば章.
  • モジュール名は, ユビキタス言語をつけること. ドメインに関する深い洞察を反映していなければならない.

ドメインオブジェクトのライフサイクル (p122)

集約 (Aggregates) (p123)

  • 関連を最小限にして設計する.
  • モデル内にある参照をカプセル化するための抽象化が集約.
  • 関連するオブジェクトの集まりであり, データを変更するための単位. -> 集約のときに宣言する型は抽象クラスかインタフェースになるのかな?
  • 集約にはルートと境界がある.
    • ルート
  • 集約に含まれている特定の 1 エンティティ.
  • 外部オブジェクトへの参照をもつ.(車がルート, タイヤは違う)
  • グローバルな一貫性をもち, 不定条件をチェックする最終責務をも つ.(リソースの開放処理とか?)
    • 境界 * エンティティと値オブジェクトを集約のなかにまとめ, 各集約の周囲に境界を定義すること.
  • 境界の内部に存在するオブジェクトへのアクセスは, ルートオブジェクトを経由して制御すること.

ファクトリー (p134)

  • オブジェクトや集約全体を生成するのが複雑だったり, 内部構造をさらけ出し過ぎている場合は, 別のオブジェクトに移譲すること.
  • ファクトリーでカプセル化する.
  • 実装を簡単に切り替えられるようにできる.
  • 要求される型によって抽象化する.
  • デザインパターンでいくつかまとまっている
    • ファクトリーメソッド
    • ビルダー
    • アブストラクト・ファクトリー
  • ファクトリの置き場所は,
    • 集約のルートオブジェクトにメソッドを用意する.
    • 他のオブジェクトの生成に密接に関わるオブジェクト.

リポジトリ (p146)

  • オブジェクトを使用するための方法は

    1. 生成する
    2. 関連を巡る
    3. クエリを実行して,
      • 属性に基づいてデータベース内でオブジェクトを見つける
    • オブジェクトの構成要素を見つけて, それを再構築する
  • この第 3 の方法こそがリポジトリ.

  • データベース検索は, グローバルにアクセスすることができて, どんなオブジェクトにも直接到達できる. オブジェクトのネットワークは管理しやすくなる.

  • 開発者は通常, そういう設計の機微についてあまり考えない.

  • 格納されたデータからインスタンスを生成することは, エンティティのライフサイクルの一部. なのでこれを再構築と呼んで, 生成と区別する.

  1. 関連でほとんどの場合は十分!

    • 一時的なオブジェクト (値オブジェクト) は必要ない. ライフサイクルが短く, それを利用するクライアントで生成と破棄がされる.
    • 永続化されりオブジェクトのうちで, 関連を巡ってみつけるほうが便利 なものに対しても, クリエによるアクセスは必要ない. なによりも, 集約内部にあるどのオブジェクトも, ルートから辿る以外の方法でアクセスすることは禁止だ.
    • 永続化された値オブジェクトを見つけるには, それをカプセル化する集約のルートとして機能するエンティティから関 連を巡るのが普通のアプローチ.
  2. どのようなときに検索が必要?

    • オブジェクトの属性に基づいた検索を通じて, グローバルにアクセスできなければならないものもある. そういうアクセスを必要とするのは, 集約のルートのうち 関連を巡って到達しようとする都合の悪いもの.
    • データベースへのアクセス方法はいくつかある
  3. リポジトリの作り方

    • リポジトリは, 特定の型のオブジェクトをすべて概念上の集合として表現する. この定義の集合を通じて, 集約のルートに対するアクセスが提供される.
    • クラアイントがリポジトリに対してオブジェクトを要求する際は, クリエメソッドを使用する.
    • グローバルアクセスを必要とするオブジェクトの各型に対して, あるオブジェクトを生成し, その型のすべてのオブジェクトで構成され るコレクションが, メモリ上にあると錯覚させるようにできるようにすること.
    • 実際に直接的なアクセスを必要とする集約ルートに対してのみ, リポジトリを提供すること.