NHibernateとWCFが導入されて以来、.NET開発者は統一したエンティティモデルという概念へ近づいてきた。そして、ORMエンティティ、WCF DTO、MVC、MVP、MVVMフレームワークのモデルに同じクラスが使われるという点に議論が生まれている。Dependency Injection in .NETの著者であるMark Seemann氏はこの事態を必ずしも良いことではないと考えている。
氏の最も重要鵜な論点は“境界ではアプリケーションはオブジェクト指向ではない”という記事に書かれている。良く知られているように、ほとんどのシリアライゼーションにはパブリックなデフォルトコンストラクタと書き込み可能なプロパティが必要だ。したがって、カプセル化は破れ、DTO設計でのデータの隠蔽が壊れる。さらに、フィールドをnullや空の値を受け付けない値にできない。DTOは文字通りすべてを無視してしまうのだ。氏は次のふたつを認める。
- サービスはスキーマはクラスではなくスキーマと契約を共有する。
- DTOはカプセル化を壊さない。オブジェクトではないからだ。
そして、この条件下で、氏は3つの選択肢を提示する。
ひとつは既に実施している方法です。ギャップを埋めるためにはDTOをカプセル化されたドメインモデルのオブジェクトに転換するレイヤが必要です。これは私が自著で紹介した方法です。しかし、この方法は最善の方法ではないかもしれないという思いを強くしました。メンテナンス性に問題があるのです。 (ちなみに、これは本を書くときの問題とも似ています。書き終わったときには書き始める前より知識が多くなっているのです。本を非難するわけではないのですが、完璧な本が書けないということです。)
データをオブジェクトとして扱うのをやめて構造データとして扱うというのもひとつの手段です。構造データという独立した概念を持つプログラミング言語があるといいでしょう。興味深いことにC#にはこのような概念はないのですが、F#に振る舞いのないデータ構造を定義する方法があります。ひょっとしたらこれが最も素直な方法なのかもしれません。私もさらに調べてみたいと思っています。
第3の選択肢は動的型を使うことです。Cutting Edge: Expando Objects in C# 4.0という記事の中でDino Esposito氏は動的な手法でコードの自動生成をせずに構造データを使い、構造データ向けの軽量なAPIを提供する方法を書いています。これは有望な方法のように思えます…コンパイルによるフィードバックが生まれませんが、これはコードが大丈夫だという誤った感覚を生み出します。単体テストを利用して素早いフォードバックを得る必要があります。みんなTDDで開発しているのだから問題ないでしょう。
オブジェクト指向設計とカプセル化に興味があるのなら、ポカヨケ設計: においから香りまでという氏の記事が参考になる。