乱暴な基本データ型:なんだろう、ソフトウェアを複雑にするのやめてもらっていいですか?2/10

まえがき

商品個数がint型?マイナス21億からプラス21億まで許容するのはおかしい。大体個数にマイナスなんてあるの?ただであげるの? そんなふうに思ったことないですか?そう思ったなら専用の型を作ればいいんです。

記事のレベル感

  • 「初級+」くらい。
  • 言語: Java

基本データ型から値オブジェクトへ

伝えたいことは簡単。 IntegerとかBigDecimalとかStringとかではなくて、現実に即した型にしようということ。 商品の個数なら「0〜99」とか、値段なら「1〜9999999」とかビジネスにもよるけれど現実的な範囲というものが必ずある。

これらを専用の型として定義して使用する。そうすることでありあえない値が入ってしまうバグも防げるし、修正や拡張するときも対象箇所を特定しやすい。さらに、影響範囲を限定的なものにできる、封じ込められる。

こういった専用の方を「値オブジェクト:Value Object」という。

Javaの基本データ型の値の範囲

初めに基本データがどれくらいの範囲になるのかを確認してみる。

商品金額型を作る

適当に、ケーキ屋さんだと思って設計。ツッコミどころはあるよね。

  • 商品は0円から99,999円の範囲
  • 範囲を超えると例外を発生、不正な値は入れない。
  • 計算結果も不正な値は返ってこない。
/**
 * 商品単価クラス
 */
class Price {
    /**
     * 商品単価最大値
     */
    static final int MAX_LIMIT = 99_999;
    /**
     * 商品単価最小値
     */
    static final int MIN_LIMIT = 0;

    int value;

    /**
     * コンストラクタ
     */
    Price(int value){
	if(value < MIN_LIMIT)
	    throw new IlligalArgumentException("過少な金額値: " + MIN_LIMIT + "未満" );
	if(value > MAX_LIMIT)
	    throw new IlligalArgumentException("過多な金額値: " + MAX_LIMIT + "超え");

	this.value = value;
    }

    /**
     * 値引き可能判定
     * @param downPrice 値引金額
     * @return boolean 判定値
     */
    boolean canPriceDown(Price downPrice){
	return downPrice > MIN_LIMIT;
    }

    /**
     * 値上げ可能判定
     * @param upPrice
     * @return boolean 判定値
     */
    boolean canPriceUp(Price upPrice){
	return upPrice < MAX_LIMIT;
    }

    /**
     * 値下げ
	 * @param downPrice 値下げ額
	 * @return PriceObject 値下げ後の金額
     */
    Price doPriceDown(Price downPrice){
	if(!canPriceDown(price - downPrice))
	    throw new IlligalArgumentException("値下げ額が" + MIN_LIMIT + "円を下回る。");
	return new Price(subValue(downPrice));
    }

    /**
     * 値上げ
	 * @param upPrice
	 * @return PriceObject 値上げ後の金額
     */
    Price doPriceUp(Price upPricce){
	if(!canpriceUp(price + upPrice))
	    throw new IlligalArgumentException("値上げ額が" + MAX_LIMIT + "円を上回る");
	return new Price(addValue(upPrice));
    }
    
    /**
     * 加算
     */
    private int addValue(Price addPrice){
	return this.value + addPrice.value;
    }
    
    /**
     * 減算
     */
    private int subValue(Price subPrice){
	return this.value + subPrice.value;
    }
    
}

ケーキ屋さん(業務アプリケーション)で考えられるデータ型

商品金型を元に以下のオブジェクトが考えてみよう。それぞれのオブジェクトでの値の範囲や振る舞いがどうなるだろうか。重要なのは専用型にすることで、変更を特定しやすく影響を限定的にできる点にある。

以下のオブジェクトで値オブジェクトにして一番恩恵があるのは文字列のタイプではないだろうか?ただのString型では:

  • 長さはほぼ無限。
  • 形式もない。
  • 1バイト文字、2バイト文字、3バイト文字でも良い。
  • 絵文字でも良い。(多分。。。笑)

何度も使うようなものをまとめておいて再利用できる点でも値オブジェクトは優れている。実装するたびに電話番号などをフォーマットや形式をその場で定義していてはどこかで形式の違う電話番号ができありかねない。

型には制約が必要である。

業務アプリケーションに限った話でないが、型には制約が必要だと思う。業務のルールに合わせたデータ型を使うのがより良いソフトウェア、システムだ。

業務のルールに合わせて設計して行けばソースコードは自ずと業務の説明書になっていく。業務通りのオブジェクト型とで書かれた説明書とJavaのデータ型だけで書かれた説明書では前者の方が文章としてわかりやすいのは明白だ。

わかりやすければ変更箇所やその方法、さらにはバグにも気がつきやすい。String型が何を意味しているのがをどこまでソースの世界の果てまで探しにいく必要がないからである。

筆者などは、プログラミングという設計行為にこそ時間を使うべきであって、何かを探す時間にはもう1秒も使いたくないのである。

参考書籍

現場で役立つシステム設計の原則

  • 第1章 小さくまとめてわかりやすくする
  • 第2章 場合分けのロジックを整理する
  • 第3章 業務ロジックをわかりやすく整理する
  • 第4章 ドメインモデルの考え方で設計する
  • 第5章 アプリケーション機能を組み立てる
  • 第6章 データベースの設計とドメインオブジェクト
  • 第7章 画面とドメインオブジェクトの設計を連動させる
  • 第8章 アプリケーション間の連携
  • 第9章 オブジェクト指向の開発プロセス
  • 第10章 オブジェクト指向設計の学び方と教え方

コメントする