31-状態だけでなく「ふるまい」もカプセル化する

プログラマが知るべき97のこと」の31個目のエピソードは、カプセル化ドメインモデルに関する話です。オブジェクト指向プログラミングの特徴といえば、継承・ポリモーフィズムカプセル化の3点です。何れも効率良くプログラムを構成するための考え方であり、Javaを初めとしたオブジェクト指向言語では言語機能として提供されています。カプセル化を一言で言えば、情報を隠蔽することで外部に公開する範囲を限定し、内部的には修正の影響範囲を限定する効果を、外部的には内部仕様を意識する必要のないシンプルなAPIになる効果をもたらします*1。これはオブジェクト間の境界を定義する手法とも言えます。
このエピソードの初めの方では「クラス」に関するカプセル化について記述されています。クラスとは、状態と振る舞いを細かい単位でカプセル化したものです。そして、陥りがちな問題として「状態のみがカプセル化された」データクラス(レコード型クラス)を作ってしまう事をあげています。解りやすく言えば、Getter/Setterのみをメソッドとして持つクラスです。そのようなクラスはデータをまとめて格納するコンテナの価値しかなく、オブジェクト指向であるべき姿ではないという主張です。これは「ドメインモデル貧血症」*2と呼ばれる症状で知られています。クラスには適切に振る舞いも持たせる事が望ましいという考え方です。
オブジェクト指向言語を扱うプログラマであれば、ドメインモデルの考え方について学ぶ必要があります。自分もドメインモデルをどんな状況でも意識していた時期があります。それまで酷い手続き型のコードや設計書に苦労していた事もあり、ドメインモデルという考え方は理想の設計方法に映ったのです。しかし、どんな時でもドメインモデルとして設計する事は誤りだという結論に至りました。
特にウェブアプリケーションでは、リクエストに対して対応する一連の処理が行われます。また、表示するデータはView層によりレンダリングされて、次のリクエストの時に必要に応じて再構成される事がほとんどです。すると、アクション(ユースケース)毎にサービスクラスを作成し、処理をシーケンシャルに行う方法(トランザクションスクリプト)の方が適しているとも言えるのです。
ドメインモデルとトランザクションスクリプトがどちらが正しいといことはありません。何か特定のドメインに限定すれば、どちらかが向いているという事はあるでしょう。しかし、重要なのはバランス良く使うことではないでしょうか?ウェブアプリケーションであれば、トランザクションスクリプトをベースに必要に応じて振る舞いをカプセル化するのが良いでしょう。
オブジェクト指向についても同様です。オブジェクト指向を強く意識しすぎると、何でもかんでもポリモフィズムを適用しようとしたり、フィールドはprivateでなければいけないという強迫観念にかられたりします。単純なif-elseで記述した方が遙かに解りやすいロジックは幾らでもあるのです。
このエピソードでは、ドメインモデルを推奨してドメインモデル欠乏症にならないようにするべきという主張であり、その点は共感します。しかし、ドメインモデル信仰をこじらせ、ドメインモデル絶対症(仮)にならないようには注意しましょう。

プログラマが知るべき97のこと

プログラマが知るべき97のこと

*1:一例を挙げればpublicなメソッドが20あるクラスより2つしかないクラスの方がシンプルです。

*2:ドメインモデル欠乏症の方が耳にするかも?