勉強日記

チラ裏

PoEAA ch15 Data Transfer Object

martinfowler.com


Data Transfer Object

An object that carries data between processes in order to reduce the number of method calls.

  • Remote Facade(未習)等のリモートインタフェース利用時はコール回数を少なくしたい
    • レイテンシ大きいため
    • 過不足ないデータを取得するために何回もコールしてしまうより、1回のコールでデータを取りすぎるほうがマシ
  • コール回数を減らすためには、1コールあたりのデータ転送量を増やす必要がある
  • 戻り値が1つしかない言語では複数のオブジェクトを返せない
  • Data Transfer Objectにシリアライズして返す
  • Java界隈ではこのオブジェクトのことを「Value Object」と呼ぶ
    • PoEAA的にはValue Objectは全く別のパターン

How It Works

  • Data Transfer Objectは、普段は忌み嫌われるたぐいのオブジェクト
    • フィールドとgetter/setterが生えてるだけ
    • 振る舞いなし
  • N/W越しに1コールで複数の情報を転送できることに価値がある
    • 分散システムで必要
  • Domain Modelは複雑に絡み合ったグラフ構造になっており、そのままではシリアライズできない
    • 循環参照があったりする
  • 比較的単純なData Transfer Objectに詰めなおしてシリアライズする
    • 階層構造
    • プリミティブ型、または別のDTOのみ集約する
  • クライアントごとに別のDTOを作ることはままある
    • Webページ用
    • GUI
  • 何種類作るの
    • one size fits allな答えはない
    • データに共通点が多ければ1つ
    • 一部のrequest/responseだけデータの共通点が無かったりしたら分ける
  • request/responseで分ける?共通?
    • one size fits allな答えはない
    • 全然違えば分ける
  • immutableにする?mutableにする?
    • 派閥
      • requestで渡されたオブジェクトと全く同じものを返却する場合でも、新しいものを生成して返す派
      • requestで渡されたオブジェクトをmodifyして返す派
    • 著者は「どちらがよい」という意見はない
    • が、便利のためにmutableを好む
      • 「新しいものを生成して返す」場合でも、少しずつ構築できる
    • (PoEAAの)Value Objectパターンとの混同も関連する話題
      • Value Objectはimmutable
  • Record SetはまさにDTO
    • RDBというリモートインタフェース用のDTOだといえる
  • 汎用コレクションにする?専用クラスにする?
    • 汎用コレクション
      • 配列はよくない
        • コードが不明瞭になる
      • 辞書がよい
        • 意味のあるキーを指定できる
    • コード生成が利用できない場合は汎用コレクションの利用価値あり
    • コード生成が利用できるなら専用のクラスを作るべき

Serializing the Data Transfer Object

  • DTOは、getter/setterに加えて、自身のシリアライジングの責務ももつ
  • ビルトインのシリアライズがあればそれを使うと良い(json,xml等)
  • レコード定義からコード自動生成できると良い
  • シリアライズ形式をどうする?(テキスト/バイナリ)
テキスト バイナリ
可読性 o x
帯域幅節約 x o
DTO定義の変化への耐性 o x
  • 理論的には、送信側と受信側でDTOのクラス定義が同期しているべき
  • 実際には同期しなくなることがある
  • 専用のクラスを作る場合で、バイナリにシリアライズする場合は、送信側/受信側でクラス定義が同期していないと、デシリアライズ時にエラーが発生する
  • 汎用の辞書を使うことでエラー耐性を持たせることができる
    • 【補】キーが増えても辞書は辞書

Assembling a Data Transfer Object from Domain Objects

  • Domain ModelとDTOとの相互変換
  • Domain ModelとDTOとは依存させなくない
    • Domain Model <-- DTO
      • Domain Objectの定義はN/Wの両サイド、システムごとにで異なるため、依存するわけにはいかない
    • Domain Model --> DTO
      • Domain Modelは外部インタフェースからの影響をうけたくない
  • Assemblerクラスを導入して依存を切り離す
    • 要するにMapperパターン

When to Use It

  • 2つのプロセス間で、1回のメソッドコールで複数のデータアイテムを転送する必要がある時に
    • 代替案
      • 戻り値が1つしかない問題への対処 -- 戻り値を使わない
        • 引数をたくさん取るsetterを生やす
        • 引数で複数のオブジェクトを返却するgetterを生やす
          • 【補】.NETのout引数
      • DTOではなく、文字列表現をそのまま転送する
        • 文字列表現にすべてが依存するのでよくない
        • explicitなインタフェース = クラスを使用する利点は、実装を隠蔽できること
          • 文字列
          • バイナリ
  • XMLDTOにパースするのがよい
    • DOM操作は痛みを伴う
    • DTOカプセル化することで生成を簡単にする
      • 【補】XMLをそのまま使おうとすると、パーサやらなんやら構築しないといけない
  • レイヤー間の疎通の抽象化
    • UI側は、Record Set (DTOの一種)の扱い方だけを知っている
      • DBから得られたRecord Setなのか、他のレイヤーで加工されたRecord Setなのか意識しない

Further Reading

  • Assembler
    • 名前の出処: Alur et al.
    • Mapperの一種なので独立したパターンとしては掲載していない
  • DTOという命名Value Objectとの名前衝突の解決
    • 多数決に従った
      • 「PoEAAのDTO」のことを指して「Value Object」と呼ぶのはJ2EEコミュニティのみ
      • 多くの人々にとって「Value Object」は別のパターンだった
        • 「PoEAAのValue Object」はこちらを指すことに

Example: Transferring Information About Albums (Java)

Example: Serializing Using XML (Java)

英語

  • blanket rule
    • どんなときにも適用できるルール