« Apache Incubator Q2レポート | メイン | マウス買い替え »

賢いデータは必要なのか

きっかけは、「オブジェクトからサービスへ」というエントリに対して、通りがかりさんからコメントいただいたことだった。これまで、長い間、もやもやしたものを感じていたのだ。

オブジェクト指向の本を紐解くと、データと振る舞いをクラスにカプセル化すると書かれている。僕も疑問は、そもそも、それが正しいのか、つまり、データに振る舞いを持たせる必要性があるのだろうか?賢いデータは必要なのか?ということだ。


Javaでは、データと振る舞いの分離が進んでいる
まず、現状として、Javaの世界では、データと振る舞いの分離が大きくすすんでいる。EJBにしても、EntityBeanとSessionBeanというのは、データと振る舞いの関係にあり、分割がよいこととされている。さらに、O/Rマッピングツールが流行するにつれ、データの保持クラスはPOJOとなった。一方、ビジネスロジックは、FacadeやServiceと呼ばれ、外部への見せ方(インターフェース)が重視され、そこにデータを与えることで、結果のデータが返ってくるという形になっている。

今、僕がアプリケーションを組むなら、間違いなくデータと振る舞いを分離してしまう。まず、ビジネスロジックと言われる部分で、データをどう扱うのかという振る舞いを記述する。一方、データを保持するクラスは、Getter/SetterだけのJavaBeansにしてしまい、なるべくそれ以外のメソッドは実装しない(データ構造だけに関係あるメソッドならOK)。そして、ビジネスロジックは、自身にInjectされたDAO(DataAccessObject)を通じてデータを取得する。

オブジェクト指向によって手続きを組む
誤解を恐れずに言えば、それは手続き型に近い。データに対する処理制御に注目しているからだ。ただし、昔ながらの手続き型とはまったく異なる。オブジェクト指向の様々なテクニックを使って、手続きを柔軟に組み立てている。たとえば、DIやAOPは、手続きのカプセル化(=オブジェクト化)に大いに役立つ。
ついでに言えば、ESB(SOA)やワークフロー制御というのが流行しているが、それらは振る舞いを設定として外部化し、データは構造だけを保持するようにしている。

つまり、現状は、データと振る舞いの分離という方向性に向かっているわけだ。

ビジネスに、振る舞いをもつデータが存在するのか
では、なぜ、オブジェクト指向の原点が、「データと振る舞いを同じクラスに持つ」ことなのか?たしかに、世の中の多くの「モノ」は振る舞いを持っている。車や人は自分で動く。

が、しかし、ことビジネスや業務については、賢いデータが存在しているとは思えない。結局、ビジネスや業務というものは、所詮、紙を基本としており、それを動かすことによってなりたっている。紙に必要事項を記入し、窓口にもっていく。窓口の人は、手続きに従って、その紙を処理する。であれば、システムも、そう作ったほうが、あきらかにわかりやすいのではないだろうか?
そもそも、ビジネスや業務は、複数のデータをまたがっているような処理がよく発生する。では、データに振る舞いを持たせた場合に、データをまたがる振る舞いは、誰が責任を持つべきなのか?

データに振る舞いを持たせることの反論は、「それはビジネスの現実ではない」ということにつきる。

たぶん、ファウラー氏が主張するようなドメインモデリングは、データに振る舞いを持たせることを基本にしている。ユースケースから抽出されたものを、ドメインモデリングして、整合性を確認している。しかし、そんな顧客が理解できないようなモデリングに意味があるとはどうしても思えないのだ。

トラックバック

このエントリーのトラックバックURL:
http://www.arclamp.jp/mt33/mt-tracback.cgi/1432

コメント (23)

先日の通りすがりの者:

yusukeさんのエントリからは、オブジェクト指向のもととなっている抽象データ型に対する視点が抜けているように感じられます。

以下を一度ご覧いただきたく思います。
なぜ「データと振る舞いを同じクラスに持たせるのか」の答えへの一助となるかと。

http://www.atmarkit.co.jp/fdotnet/bookpreview/codecomp2nd_06/codecomp2nd_06_01.html

yusukeです。コメントありがとうございます。
抽象データ型が重要だということには大賛成です。教えていただいたリンク先にあるフォントのような例であれば、僕も同じように実装します。
なので、僕の疑問は「なぜデータと振る舞いを同じクラスに持たせるのか」というよりも「この手法がビジネスのシステム化にも使えるのか?」ということですね。
ビジネスでは複数のオブジェクトが関わることが多くなります。その場合に、この手法は有効でしょうか?むしろ、開発者にとっても顧客にとっても、理解が難しいものとなりデメリットのほうが大きくなるのではないでしょうか?

sato:

satoと申します。たまたまこの記事を拝見し、興味深いテーマだったのでコメント差し上げます。
yusukeさんのおっしゃるデータと振舞の分離は、マーチン・ファウラーの言うところの「Transaction Script」パターン(あるいはドメインモデル貧血症)に相当するかと思います。ファウラーがなぜこれを良くないと言っているかというと、結局これはスクリプト的なプログラミングでしかないので、いずれドメインロジックがある程度の規模になると、コードの重複がどうしても排除しきれなくなる、ということだったかと思います(この辺の議論は、彼の新著PoEAAに詳しいはずです)。
ファウラーがより優れたパターンとして提案しているのが「Domain Model」です。これは正にデータと振舞を合わせたオブジェクトによって、ドメインを構築する手法です。データと振舞が一緒になるので、ドメイン分析によりしかるべき場所に振舞が置かれるようになり、コードの重複が無くなると言っています。
また、私の考えでは、yusukeさんの言うようにデータと振舞を分けてしまうと、このような 分析 -> 設計 -> 実装 のシームレスな流れが阻害されてしまうと思うのです。
この点についてはいかがお考えでしょうか?

先日の通りすがりの者:

>ビジネスに、振る舞いをもつデータが存在するのか
>では、なぜ、オブジェクト指向の原点が、「データと振る舞いを同じクラスに持つ」
>ことなのか?たしかに、世の中の多くの「モノ」は振る舞いを持っている。
>車や人は自分で動く。
>
>が、しかし、ことビジネスや業務については、賢いデータが存在しているとは思えない。
>結局、ビジネスや業務というものは、所詮、紙を基本としており、
>それを動かすことによってなりたっている。紙に必要事項を記入し、窓口にもっていく。
>窓口の人は、手続きに従って、その紙を処理する。であれば、システムも、
>そう作ったほうが、あきらかにわかりやすいのではないだろうか?

紙なんてものは、ある事象のビューに過ぎないと考えます。
ドメインモデルを使うことで事象そのものを表現することができるのですから、
わざわざ紙(ビュー)を持ち出さずとも事象(ドメインモデル)だけで表現すればいいではないか、
私はそう考えています。

また、仮に「ドメインモデル」が「紙モデル」と比べて不自然なモデルだったとします。
その上で以下のどちらかを選べと言われたならば、私は後者(ドメインモデル)を選びます。

-紙をベースにした、自然だが抽象データ型のメリットを得られないモデル
-ドメインモデルをベースとした、不自然だが抽象データ型のメリットを得られるモデル

多少不自然であろうが、ビジネスの現実でなかろうが

http://www.atmarkit.co.jp/fdotnet/bookpreview/codecomp2nd_06/codecomp2nd_06_07.html

で上げられているメリットを享受できるのであれば、それはそれでハッピーです。

先日の通りすがりの者:

>EJBにしても、EntityBeanとSessionBeanというのは、データと振る舞いの関係にあり、
>分割がよいこととされている。

以下を見るに、データと振る舞いの分割は決して良いこととされているようには
思えないのですが?

http://sdc.sun.co.jp/java/technicalArticles/spguide/chap2.html
# セッション Bean は、エンティティ Bean や他のセッション Bean で、
# クライアントがまとめて簡単にビジネスロジックにアクセスする際の
# Facade(ファサード―“皮”)として使用してください。
## Facadeには通常ビジネスロジックは持たせません。
## ですから「データと振る舞いの分割を推奨している」に反していると考えます。

http://sdc.sun.co.jp/java/technicalArticles/spguide/chap3.html
# モデル: EntityBean, JavaBean
# ビュー: Servlet, JSP
# コントローラ: Servlet, SessionBean
## とされている。MVCでいうコントローラには、通常ビジネスロジックは持たせませんから
## 「データと振る舞いの分割を推奨している」に反していると考えます。

先日の通りすがりの者:

>一方、ビジネスロジックは、FacadeやServiceと呼ばれ、
>外部への見せ方(インターフェース)が重視され、
>そこにデータを与えることで、結果のデータが返ってくる
>という形になっている。

Facadeには通常ビジネスロジックは持たせませんし、Serviceも、PoEAAによれば
-ドメインオブジェクトへ処理を委譲
-ApplicationLogicを実装して、DomainLogicはドメインオブジェクトへ委譲
とあり、データと振る舞いの分割を推奨しているようには思えません。

# 重箱のスミをつつくようでスミマセン。

先日の通りすがりの者:

>ビジネスでは複数のオブジェクトが関わることが多くなります。その場合に、
>この手法は有効でしょうか?むしろ、開発者にとっても顧客にとっても、
>理解が難しいものとなりデメリットのほうが大きくなるのではないでしょうか?

ひとつの振る舞いに複数のオブジェクトが関わることは、ビジネスアプリケーションに
限らず良くある話なのではないでしょうか?

また、私自身ひとつの振る舞いに複数のオブジェクトが関わるような状況を幾度となく
扱ってきましたが、有効性には疑問を抱くことはありませんでした。

先日の通りすがりの者:

>そもそも、ビジネスや業務は、複数のデータをまたがっているような処理がよく発生する。
>では、データに振る舞いを持たせた場合に、データをまたがる振る舞いは、誰が責任を持つべきなのか?

基本は、いちばん座りがいいクラスへ割り当てる、だと思いますが、中にはどのクラスへも割り当てがたい振る舞いというのもありますね。そのような振る舞いはコントローラクラスへ割り当てれば良い、と古のOOSEに記されていますし、私も(だめだなーと思いながらも)よくやります。

yusukeです。お返事遅くなりました。
satoさん、コメントありがとうございます。

>データと振舞の分離は、マーチン・ファウラーの言うところの「Transaction Script」パターン(あるいはドメインモデル貧血症)に相当するかと思います。

確かにそうです。ですが、振る舞いをユースケース内でちゃんと管理すれば、ファウラー氏が指摘するようなデメリットは発生しないと思っています。
僕が思うに、振る舞いのくくりというのは、データではなくて、ビジネス上のユースケースであるべきで、そうすれば、重複も発生しないはずです。

> また、私の考えでは、yusukeさんの言うようにデータと振舞を分けてしまうと、このような 分析 -> 設計 -> 実装 のシームレスな流れが阻害されてしまうと思うのです。

「紙と手続き」からなるビジネスにおいて、分析から実装の距離を縮めるのであれば、TransactionScriptの方が、ドメインモデルへの変換がないだけ、シームレスだと感じています。いかがでしょ?

通りすがりさん、コメントありがとうございます。

> # 重箱のスミをつつくようでスミマセン。

いえいえ。僕の用語使いが適当なだけで、ご指摘感謝します。

> -紙をベースにした、自然だが抽象データ型のメリットを得られないモデル
> -ドメインモデルをベースとした、不自然だが抽象データ型のメリットを得られるモデル

ということですが「データと振る舞いの分離」をおこなっても、抽象データ型の大半のメリットは享受できると思います(そもそも、享受できないのはまずいですよね)。
ビジネスドメインで考えて、ユースケースに対応したクラスで振る舞いを管理していれば、

http://www.atmarkit.co.jp/fdotnet/bookpreview/codecomp2nd_06/codecomp2nd_06_01.html

で、メリットとされているもののうち、

# ■ 実装の詳細を隠ぺいできる
# ■ 変更がプログラム全体に影響しない
# ■ インターフェイスが提供する情報をより明確にできる
# ■ パフォーマンスを改善しやすくなる
# ■ プログラムの正しさがより際立つ
# ■ プログラムがひとめでわかるようになる

は、満たせるのではないでしょうか。くくりが、データかユースケースかというだけで目的は同じです。かつ、ユースケースであれば、振る舞いのほうが、データよりも、範囲内に収まる確立が高いでしょう。

そもそも、ドメインモデルが、実装手法として良いものだとしても、多くの人にとって敷居が高いのであれば推奨できないです。であれば、わかりやすい「データと振る舞いの分離」を前提にしたうえで、抽象データ型のメリットを得る方法を考えたほうがいいかなと。
現在であれば、O/Rマッピング、DI、AOPなどによって、かなり楽にできるようになってきています。

itak:

いつも拝見させて頂いております。

フォントなど、多くのプログラマにとっては余りなじみがなく、直接の関心事でない対象は、データと手続きが一体化されている方が扱いやすいですよね。

ビジネスのデータに関して言えば、対象業務を熟知している人にとってはデータと手続きが分離していても十分簡単に理解できるでしょうし、従来の手続き型プログラミングに慣れているとOOが逆に不自然に感じられるのかもしれません。
対象業務を知らない人にとっては、フォントと同様、データと手続きが一体化していた方が理解しやすいと考えます。(少なくともデータと手続きの組み合わせを考えなくてよいため。)ある程度の複雑さがないと、恩恵を感じられないと思いますが。

何が関心事なのか、どの程度複雑と感じるかは人によって異なってくると思いますので、結局誰のために作るか?で決まる気がします。

先日の通りすがりの者:

>ということですが「データと振る舞いの分離」をおこなっても、抽象データ型の大半のメリットは
>享受できると思います(そもそも、享受できないのはまずいですよね)。
>ビジネスドメインで考えて、ユースケースに対応したクラスで振る舞いを管理していれば、

上記が具体的に何を行うのかはわからないのですが、

># ■ 実装の詳細を隠ぺいできる
># ■ 変更がプログラム全体に影響しない
># ■ インターフェイスが提供する情報をより明確にできる
># ■ パフォーマンスを改善しやすくなる
># ■ プログラムの正しさがより際立つ
># ■ プログラムがひとめでわかるようになる
>
>は、満たせるのではないでしょうか。くくりが、データかユースケースかというだけで目的は同じです。
>かつ、ユースケースであれば、振る舞いのほうが、データよりも、範囲内に収まる確立が高いでしょう。

上記は抽象データ型によるメリットの一部でしかありません。上記を実現したところで抽象データ型はいらないと考えるのは早計に過ぎるのではないでしょうか?

また、上記を「データと振る舞いの分離」を行っても実現できるとのお考えのようですが、私には大半が実現できないように思えます。

># ■ 実装の詳細を隠ぺいできる
→できないと考えます。
例えば、FontDataクラス内のフォントが太字であることを表す変数 boldの型が intから boolへ変更された場合、FontDataを使用する全てのクラスに変更が入ります。また、メモリに格納していたデータを外部記憶装置に格納することにした場合にもFontDataを使用する全てのクラスに変更が入ります。つまりFontDataは実装の詳細を隠蔽できていません。

># ■ 変更がプログラム全体に影響しない
→上記と同じ理由で変更がプログラム全体に影響していると考えます。

># ■ パフォーマンスを改善しやすくなる
→どちらとも言えない
できる場合あるとは思いますが、例えば「遅延ロード」や「オブジェクトのキャッシング」等のように、データと振る舞いがカプセル化されてなければ実現が困難なものが多くあるものと考えます。

># ■ プログラムの正しさがより際立つ
>「currentFont.attribute = currentFont.attribute or 0x02」
>といったステートメントが正しいかどうかを確認する面倒な作業が、
>「currentFont.SetBoldOn()」の呼び出しが正しいかどうかを確認する
>といった簡単な作業で済むようになる。
→できないと考えます。
これをどうやって抽象データ型を用いずに実現させるのでしょうか?

># ■ プログラムがひとめでわかるようになる
>「currentFont.attribute or 0x02」というステートメントは、
> 0x02をBOLDなど0x02が表すものに置き換えれば改善できるものの、
>「currentFont.SetBoldOn()」といったルーチンの呼び出しの
>読みやすさとは比べものにならない。
→できないと考えます。
これをどうやって抽象データ型を用いずに実現させるのでしょうか?

先日の通りすがりの者:

>そもそも、ドメインモデルが、実装手法として良いものだとしても、
>多くの人にとって敷居が高いのであれば推奨できないです。
>であれば、わかりやすい「データと振る舞いの分離」を前提にしたうえで、
>抽象データ型のメリットを得る方法を考えたほうがいいかなと。

パラダイムシフトを要求する手法は推奨できないということでしょうか?

また、前提として

抽象データ型=データと振る舞いのカプセル化≒オブジェクト指向

となります(少々乱暴ですが)。
「データと振る舞いの分離」を前提とするということはオブジェクト指向を捨てて新たなパラダイムを生み出すということでしょうか?


> 現在であれば、O/Rマッピング、DI、AOPなどによって、かなり楽にできるようになってきています。

O/Rマッピング: Javaオブジェクト RDBレコードの自動マッピング
Dependency Injection: オブジェクト依存関係をパラメタ化させたファクトリ
AOP: 横断的関心事の分離

それぞれが解決する問題は上記のものでして、抽象データ型の代わりとなるものではないように思います。

yusukeです。
itakさん、コメントありがとうございます。

> 何が関心事なのか、どの程度複雑と感じるかは人によって異なってくると思いますので、結局誰のために作るか?で決まる気がします。

そうですね。システムの価値基準と置き換えてもいいのかもしれません。僕は理解がしやすいことが大事と考えています。ドメインモデルの場合は、システム自身の美しさというか、完成度が重要ということだと思います。

通りすがりさん、引き続きコメントありがとうございます。

> また、上記を「データと振る舞いの分離」を行っても実現できるとのお考えのようですが、私には大半が実現できないように思えます。

うーん、達成すべきは目的です。抽象データ型という手法は重要ではありません。たとえば、「 ■ 実装の詳細を隠ぺいできる」は、いわゆる「カプセル化」でしょうから、データや振る舞いという問題に関係なく実現可能です。他も同じことです。

> パラダイムシフトを要求する手法は推奨できないということでしょうか?

クリステンセン氏の「イノベーションのジレンマ」に従うなら、パラダイムシフトとは、簡単すぎて適用範囲が少ないと思われていたことが、時間がたつにつれ適用範囲を広げることです。ドメインモデルには当てはまらない気がします。
ドメインモデルは、むしろオブジェクト指向の原点に対して厳格であるように感じます。新しいというよりも、純粋に正しい方法というか。ある意味で古典的というか。

> 「データと振る舞いの分離」を前提とするということはオブジェクト指向を捨てて新たなパラダイムを生み出すということでしょうか?

そんな大げさなことは考えていません。「データと振る舞いの分離」とJava言語的なオブジェクト指向は相反することではないのですよね。Javaには、それを許容する柔軟性があります。現に、データと振る舞いを分離しても実装可能ですし。
そして、オブジェクト指向のテクニックは有効に使うべきです。O/Rマッピング、DI、AOPによって責務をコンポーネント化(オブジェクト化)し、それぞれの依存関係をコントロールするのです。

実装テクニックとして、ドメインモデルが非常に有効な場合もあります。例えばフォントの実装。あるいは、データと振る舞いがわかりやすいようなドメインの場合。
ただ、業務システムであれば、オブジェクト指向のテクニックを利用し、流れに沿って手続き的に実装することを前提にしたほうが、メリットが大きいと感じます。ちゃんと実装すれば、ドメインモデルというテクニックを使わなくても、十分に良いシステムになるのではないでしょうか。

sato:

satoです。
yusukeさん、お返事ありがとうございます。

大変興味深い議論が展開されていますね。

> 振る舞いをユースケース内でちゃんと管理すれば、ファウラー氏が指摘するようなデメリットは発生しないと思っています。
>「紙と手続き」からなるビジネスにおいて、分析から実装の距離を縮めるのであれば、TransactionScriptの方が、ドメインモデルへの変換がないだけ、シームレスだと感じています。

確かに、「紙と手続き」からなるビジネスのシステム構築には、ドメインモデルよりも「データと振舞の分離」の方が簡単かもしれませんね。一つの方法論を万能と思わず、マルチパラダイムで行くというスタンスには大変共感いたします。

その後の通りすがりさんとの議論の中で、気になったことがあったのでコメントします。yusukeさんの、

> 抽象データ型という手法は重要ではありません。たとえば、「 ■ 実装の詳細を隠ぺいできる」は、いわゆる「カプセル化」でしょうから、データや振る舞いという問題に関係なく実現可能です。

とのコメントですが、Parnasなどの正統なアカデミックな議論を踏まえるならば、「抽象データ型」と「カプセル化」は対概念だったかと思います。抽象データ型の強力なメリットの一つを示す言葉が、カプセル化、または情報隠蔽という言葉なはずです。この辺は@ITなどよりは大学教材などのもう少しアカデミックな資料を参考にされた方が、誤解が無いと思います。

お言葉から察するに、通りすがりさんはかなりのOOエキスパートの方のようですが、逆にOOでも明確に「構造」と「振る舞い」の分離を勧めているVisitorパターンなどのパターンについては、どうお考えなのでしょうか? 私は、yusukeさんの仰る「データと振る舞いの分離」はVisitorパターンのかなり特殊なケースなのでは、と解釈しています。エンタープライズなシステムの本でVisitorパターンについて深く言及した本は、ほとんど見た事がありませんが(コンパイラの本ではよく見かけますが)。

yusukeです。satoさん、コメントありがとうございます。

> Parnasなどの正統なアカデミックな議論を踏まえるならば、「抽象データ型」と「カプセル化」は対概念だったかと思います。

なるほど。僕の言い方は誤解を招きますね(毎度ながら、適当な用語使いで申し訳ないです)。

http://e-words.jp/w/E382ABE38397E382BBE383ABE58C96.html

によると、カプセル化とは、

#外部からは公開された手続きを利用することでしかデータを操作できないようにすることで、個々のオブジェクトの独立性が高まる。 #中略# オブジェクト内部の仕様変更が外部に影響しなくなり、ソフトウェアの保守性や開発効率が高まり、プログラムの部分的な再利用が容易になる。

ということですね。僕が言いたかったのは、カプセル化のメリットである「再利用性」は重要。ただ、それを得るためには、データに振る舞いがなくても可能だということです。DIは強力な武器になります。

通りすがりさんの主張は、多少、理解しにくくても、データに振る舞いを持たせるメリットが大きいということだと思います。言い換えれば、
- ビジネス分析から見た理解しやすさ
- 実装上のできの良さ
を比べて、実装メリットが重要だということかと思います。確かに、いかに理解しやすくても、出来上がるモノがダメダメでは意味がないという主張はとっても正しいです。

ただ、DIやAOPがある現状では、データと振る舞いを分離しても、十分に実用的な実装メリットが得られるようになったと僕は感じています。

というわけで、「データに振る舞い」がだめだというつもりはまったくないですが、選択肢が広がりつつあるという事実は認めてほしいなぁとは思います。

通りすがり:

> 逆にOOでも明確に「構造」と「振る舞い」の分離を勧めている Visitorパターンなどのパターンについては、どうお考えなのでしょうか? 私は、yusukeさんの仰る「データと振る舞いの分離」は Visitorパターンのかなり特殊なケースなのでは、と解釈しています。エンタープライズなシステムの本でVisitorパターンについて深く言及した本は、ほとんど見た事がありませんが(コンパイラの本ではよく見かけますが)。


まず、Visitorパターンについて。
実は Visitorパターンの使用経験が皆無なため私には何かを意見を言う資格など無いのですが、
Refactoring to Patternsの Move Accumulation to Visitorパターンの
説明の中で(P321)以下のような記述がありました。

Ralph Johnson, ... ,once observed,
"Most of the time you don't need Visitor,
but when you do need Visitor, you really need Visitor!"

なので、本当に必要な状況が来るまでは使うべきでないパターンと認識しています。
まあ、木構造のトラバースでもやるのでなければ使うことも無いのかなと。

* Move Accumulation to Visitor
http://www.industriallogic.com/xp/refactoring/accumulationToVisitor.html


次に。yusukeさんの仰る「データと振る舞いの分離」の考え方の元となっているのは、ひがやすをさんが提唱する「くーす」と呼ばれる開発手法だと思われます(そうですよね?)。ですので、このことに関しては「くーす」を調べてみるのも参考になるかと思います。

くーすに関してのまとまった情報は特に無いので、ひがさんの日記(http://d.hatena.ne.jp/higayasuo/)を「くーす」で検索するのが手っ取り早いかと思われます。簡単に言うと「メソッドオブジェクトを使った構造化設計」といった感じのものです。

去年末に2chやblog上でくーすに関しての議論にお付き合いいただいたのですが(その時の44は私です)、お互いの立ち位置が違いすぎるため、有効な議論にはなりませんでした。

通りすがり:

>ただ、DIやAOPがある現状では、データと振る舞いを分離しても、十分に実用的な実装メリットが得られるようになったと僕は感じています。

DomainModelやTransactionScriptは、DIやAOPとは直行した概念です。ですから、DomainObjectかTransactionScriptかの判断基準にはなにひとつ影響しないように思うのですが。


>というわけで、「データに振る舞い」がだめだというつもりはまったくないですが、選択肢が広がりつつあるという事実は認めてほしいなぁとは思います。

はい。私もTransactionScriptがだめだというつもりはありません。ドメインモデル云々は手段であって目的ではありません。自分が使いやすいと思う手段を使って目的を実現すべし、というのが私の考えですし、yusukeさんの考えでもあると思っています。

私が唯一訴えたいこと。それは

>オブジェクト指向の基本といわれる「データと振る舞いの一体化」。でも、それは間違っているのではないだろうか?

は間違ってないですよ。この一点のみです。

確かに敷居が高く感じる人が多いかもしれませんし、既存の伝票を基に考えると不自然に感じるかもしれません。が、それは決してデータと振る舞いのカプセル化が間違っている!の理由になるものではありません。

yusukeです。

> 「データと振る舞いの分離」の考え方の元となっているのは、ひがやすをさんが提唱する「くーす」と呼ばれる開発手法だと思われます

明確に意識したことはないのですが、確かにそうですね(ちなみに、Seasarを使ったことはないです)。

> お互いの立ち位置が違いすぎるため、有効な議論にはなりませんでした。

このエントリ&コメント達が、有効な議論になっていることを望みます(笑)。もしくは、有効な議論になる方法を教えてくださいませ。

> 確かに敷居が高く感じる人が多いかもしれませんし、既存の伝票を基に考えると不自然に感じるかもしれません。が、それは決してデータと振る舞いのカプセル化が間違っている!の理由になるものではありません。

確かに。僕も使うことありますから。
では「オブジェクト指向では、データに振る舞いを持たせることだけが良い実装方法」というのは間違っているでいいですかね?
状況に応じて実装テクニックを選択すればよいということですよね。どこまで応用が利くかについては細かい議論がたくさんあるとは思いますが。なんにせよ選択肢が多いというのは良いことです。

ハマ:

こんにちは。
いつも楽しく記事のほう読ませていただいています。

さて、
> では「オブジェクト指向では、データに振る舞いを持たせることだけが良い実装方法」というのは間違っているでいいですかね?

で、「データに振る舞いを持たせる」事をしないとオブジェクトと言えないのではないでしょうか。僕はオブジェクト指向の本質って「メッセージパッシング」だと思っています。

オブジェクトにメッセージを発信したけど処理がされない(もしくは発信できない)のならば、それはただの構造体な気がします。

通りすがりさんがおっしゃるように、データと振る舞いを分けるのはマーチンファウラー曰く Transaction Script と言われます(ちょっと違うニュアンスですが)。

Transaction Script だと、似たような処理が重複して出現することが多々あります。処理が重複するのは、オブジェクト指向プログラミングでわないと考えます。


特別、何が言いたいと言うことではないのですが、「データと振る舞いを分ける」と言うのを、オブジェクト指向といわれると、なんとなく違うかなと思いました。

ただ、「データと振る舞いを分ける」事がいいことなのか悪いことなのかは、別の話ですけど

yusukeです。ハマさん、コメントありがとうございます。

> で、「データに振る舞いを持たせる」事をしないとオブジェクトと言えないのではないでしょうか。僕はオブジェクト指向の本質って「メッセージパッシング」だと思っています。

うーん。であればオブジェクト指向という単語にこだわるつもりもありません(笑)。良いシステムがつくれるならなんでもいいです。

> Transaction Script だと、似たような処理が重複して出現することが多々あります。

そんなことはないと思います。重複するならリファクタリングしてライブラリとして切り出せばよいだけです。なぜ複雑になると重複が発生すると言われているのか、どうしても理解できません。

> ただ、「データと振る舞いを分ける」事がいいことなのか悪いことなのかは、別の話ですけど

一概に良い悪いはいえないですね。ビジネス分析と実装のメリット・デメリットを一緒に語ることはできないでしょう。

通りすがり:

とりあえず、一点だけ。

>> Transaction Script だと、似たような処理が重複して出現することが多々あります。

>そんなことはないと思います。重複するならリファクタリングしてライブラリとして切り出せばよいだけです。なぜ複雑になると重複が発生すると言われているのか、どうしても理解できません。

そうでしょうか? いくつか思いつくものとしては

1) 違う型に対して同じ処理を行うような場合などは、リファクタリングが難しい。(通常は多態を用いて重複を取り除くが、データと振る舞いが分かれている場合はこれができない)

2) 以下のようなコードの重複に対してのリファクタリングが難しい(通常はExtractClassしてからTemplateMethodで対応かな?)。

class TransactionScirptA
 void doSomething() {
  doA();
  doB();
  doD();
 }
}

class TransactionScirptB
 void doSomething() {
  doA();
  doC();
  doD();
 }
}

3) Transaction Scriptで実装した場合、1メソッドに着眼して処理が実装されますので、必然的に他のトランザクションのことは考えなくなる(考えないことがメリットでもあるのですが)と思います。つまり、ドメインロジックが多くなればなるほど、各トランザクションでの共通したロジックであるサブルーチンが切り出しにくくなり、重複したロジックが増え、結果的に保守しにくいものになる可能があるかと思われます。
(http://otndnld.oracle.co.jp/columns/arai-semi/data_access/1/ より引用)

4) 再利用したいコードがどこにあるか分からない。(ドメインモデルの場合は見当がつきやすい)

5) 再利用のため、顧客に関するロジックを EmployeeLogicへ集めてゆく。が。それってドメインモデルに近づいてるだけじゃない?

などがあります。
# 思いつきで書いてるので、へんなところがあったらご指摘ください。

また、私がよく使う重複除去のテクニックとして「Template Method」と「ExtractClass or ExtractInterfaceを適用して多態」などがあるのですが、TransactionScriptではこれらが使えないのがつらいなーと感じています。

あと。TransactionScript(≒機能的トップダウンアプローチ)の再利用性の低さ(≒コードの重複)については、オブジェクト指向入門の4章に若干の記述があるようです。

通りすがり:

今回も立ち位置の違いを感じてはおりますが(w、少しずつ近づいてゆきましょう。
# 立ち位置が違うのは悪いことではありませんしね。

>確かに。僕も使うことありますから。
では「オブジェクト指向では、データに振る舞いを持たせることだけが良い実装方法」というのは間違っているでいいですかね?
状況に応じて実装テクニックを選択すればよいということですよね。どこまで応用が利くかについては細かい議論がたくさんあるとは思いますが。なんにせよ選択肢が多いというのは良いことです。

はい。状況に応じてはトランザクションスクリプトの方が有効な場合もあると考えます。

yusukeです。違う点が明確になればよいと思いますw。お互い良いシステムを作りたいという点では同じですし。

1)、2)、3)は、その通りです。
まず、ビジネスから考えると、まったく違う型に同じような処理が発生する可能性が低い気がしています。もし発生なら技術的には以下の3種類で処理します。

- データクラスに共通Interfaceを実装し、手続きはInterfeceに対して行う
- データクラスに親クラスを作成(Extends)し、手続きは親クラスに対して行う
- 手続きはReferection APIを使いメソッド名で処理する(Validatorのやり方)

> また、私がよく使う重複除去のテクニックとして「Template Method」と「ExtractClass or ExtractInterfaceを適用して多態」などがあるのですが、TransactionScriptではこれらが使えないのがつらいなーと感じています。

上記の方法ではだめですかね?(なんか、僕は変なこといっているのかな?)

そもそも「データと振る舞いの分離」によるメリットを優先させているので重複に対する優先度低いです。ただ実用に耐えうるレベルというのは存在するはずのですが、明確ではありません(笑)。

> 5) 再利用のため、顧客に関するロジックを EmployeeLogicへ集めてゆく。が。それってドメインモデルに近づいてるだけじゃない?

これはその通りです。「ドメイン」に注目して処理を寄せるという点ではまったく同じです。そうしないと再利用したいものが見つからなくなりますから。ただ、それを手続きだけについて行います。当然、データが同じドメインに含まれる可能性は高いですが、またがってよしって感じですかね。

> はい。状況に応じてはトランザクションスクリプトの方が有効な場合もあると考えます。

ですね。なので、このエントリの概要の書き出しの表現をやわらかくしましたw


さて、コメントも長くなってきたので、別エントリにしようと思います。続きは、そちらでお願いします。(このエントリのコメントに対するものなら、ここに入れていただいたも良いですが)

コメントを投稿

(いままで、ここでコメントしたことがないときは、コメントを表示する前にこのブログのオーナーの承認が必要になることがあります。承認されるまではコメントは表示されません。そのときはしばらく待ってください。)

About

2005年05月02日 23:00に投稿されたエントリーのページです。

ひとつ前の投稿は「Apache Incubator Q2レポート」です。

次の投稿は「マウス買い替え」です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。

Creative Commons License
このブログは、次のライセンスで保護されています。 クリエイティブ・コモンズ・ライセンス.
Powered by
Movable Type