<< Value Object : シンプルで小型のオブジェクトに目覚めた経緯 | main | 関連もオブジェクトも、小さくする。少なくする。 >>

Value Object は不変にする

ドメイン駆動設計(DDD)の Value Objects パターンでは、オブジェクトを不変(immutable)にすることを強く推奨している。

なんとなく、そんなもんか、と思っていたけど、ある日、なるほど、というケースに出くわした話し。

変数名にこだわる


前提として、変数名にこだわるようになったことがある。
DDD のユビキタス言語パターンの実践として、
・パッケージ名
・クラス名
・メソッド名
・変数名
は、業務上の意味のある名前にこだわることを、徹底しはじめた。

Java Calendar クラスの日付計算


当日から、2週間後に、期限切れになる、というビジネスルルールを実装していた。

Calendar getExpireDate()
{
 Calendar now = Calendar.getInstance();
 now.add( Calendar.DATE, 7*2 );
 return now ;
}

ほんとうは、2週間後の日付を戻すのに、 return now はおかしいでしょ?

めちゃくちゃ単純化すると、 expireDate = now になっちゃう。(ほんとうは2週間後)

now.add() によって、now の内容は、2週間後に変わっているのに、変数名は "now(今)"のまま。

これは不自然。
こういう記述は、意味が読み取りにくい。バグがまぎれこむのは、こういう場所。
将来、コードを変更する時に、怪しいことが起きそう。

可変から不変に変えると


これは、Calendar のインスタンス now が、可変であることによって起きる。

now を不変にして、

Calendar expireDateTime = now.add( Calendar.DATE, 7 * 2 )

というように、 add() メソッドは、自分を書き換えるのではなく、別のオブジェクトを作って戻すようにする。
String オブジェクトはこうなっていますよね。

可変(mutable) オブジェクトは、ソフトウェアを分かりにくし、変更についても危険な臭い。

不変(immutable) オブジェクトにすれば、分かりやすく、安全になる。

ちょっとした発見だったけど、なるほど 不変(immutable)かあ、ということを実感した瞬間。

Value Object 第一号 :BusinessDate の誕生


Java の Calendar は、これ以外にも、業務的な日付を扱うのには向かない。
例えば、時刻のない「日付」だけを扱うようにできていない。日付演算もわかりにくい。

この return now 事件(?)を経て、DDD の Value Object パターンを実践した BusinessDate クラスを作った。

BusinessDate today = new BusinessDate();
BusinessDate exireDate = today.addWeek(2) ;

こんな感じで使う。

あと、parse() とか、format() も、用途を限定したメソッドをいくつか用意した。(メソッド名もそれなりに)

シンプルで、小型のオブジェクト。そして不変(immutable)。
Value Object パターンをはじめて意識的に実装したのが、この BusinessDate クラス。

読みやく、安全になった


BusinessDate クラスは、Calendar や SimpleDateFormat の面倒くささをなくしたので、みんなが喜んで使うようになった。
コードから、低レベルな日付操作が消えたので、格段に読みやすくなった。

そもそも、Calendar という名前自体がわかりにくかったし。

そして不変(immutable)にしたことによって、別の日付は、別の変数名で参照するしかなくなった。
これも、読みやすさを格段に向上した。

かつては、 date 変数をいろいろ上書きしながら使いまわしていたようなコードが、

today
expireDate
registeredDate
...

とか、意味のある日付名がたくさん登場するようになった。

コードを読むだけで、どういう日付を、どう扱っているか、格段に読みやすくなった。
変更があった時も、簡単に安全に変更しやすくなった。

つまんないバグが明らかに減った。

変数はソフトウェアを脆弱にする


BusinessDate を Value Object として実装してから、変数(mutable)は、ソフトウェアを脆弱にする、と考えるようになった。

例えば、グローバル変数は良くないとされている。
あちこちから、参照され、かつ変更可能だと、ソフトウェアがわけがわからなくなる。

これは「グローバル」というより「変数」自体の問題なんだと思うようになった。

可変(mutable)の変数(variable)を使うことを、プログラミングの世界では、当たり前のこととしてきた。
でも、分かりやすく、安全なコードを書くには、できるだけ、変数(variable)を避けるべきなんだ。

同じメソッド内のローカル変数といえども、書き換えることは、ソフトウェアを脆弱にする。

Value Objects パターンで、不変(immutable)が強く推奨されるのは、こういう問題意識からなんだと思う。

不変オブジェクトの実装


実装方法としては、

・コンストラクトで、値をすべてセット。
・setter など、内容を書き換えるメソッドを書かない。
・値を変えたいときは、同じクラスの別のインスタンスを作成して戻す

もちろん、クラス内部の private なメソッドでも、値を変えない。

これが、Value Object の実装の基本。
そして、多くのドメインオブジェクトは、 Value Objectとして、こういう不変(immutable)の実装にすべき。

言語仕様:Java だと、final、Scala だと val


Java だと、変数に、final修飾子を使えば、変数を不変に宣言できる。
Scala だと、var(iable) と val(ue) ということで、「変数」と「値」の違いを明示的に宣言できる。

プログラム言語としては、final や val は分かる。
でも、DDD のユビキタス言語として見れば、よい表現方法ではない。(業務の専門家には意味不明の議論)

Scala は、面白い言語だと思うけど、def,var, val とかの短縮形や、記号を多用するの発想が、DDD の実装言語向きではない、と思っている。ユビキタス言語としてどうか、ということ。

コメント
コメントする









この記事のトラックバックURL
トラックバック
calendar
   1234
567891011
12131415161718
19202122232425
262728293031 
<< March 2017 >>
システム設計日記を検索
プロフィール
リンク
システム開発日記(実装編)
有限会社 システム設計
twitter @masuda220
selected entries
recent comment
recent trackback
categories
archives
others
mobile
qrcode
powered
無料ブログ作成サービス JUGEM