[現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法](https://gihyo.jp/book/2017/978-4-7741-9087-7) のメモ 本のサンプルソースはJavaで書かれているが、勉強も兼ねてGo言語にアレンジしている。 # Chapter3 業務ロジックをわかりやすく整理する ## データとロジックを別のクラスに分けることがわかりにくさを生む 編集予定 ## データとロジックを一体にして業務ロジックを整理する 編集予定 ### クラスが肥大化したら小さく分ける >[name=Yusaku Matsuki] > クラスが大きくなるとは具体的にはどれくらいなのか? >> ...良いコードのお手本としてApache Commonsのコードを参照してみよう。すると、1クラス中の平均メソッド数は6.5くらい、全体の8割にあたるクラスのメソッド数が10以下であった。... >> - https://anopara.net/2014/04/11/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E4%B8%AD%E7%B4%9A%E8%80%85%E3%81%AB%E8%AA%AD%E3%82%93%E3%81%A7%E3%81%BB%E3%81%97%E3%81%84%E8%89%AF%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89/ ## 三層の関心事を業務ロジックの分離を徹底する ### 業務ロジックを小さなオブジェクトに分けて記述する 業務データと業務ロジックを一つにまとめたオブジェクトを***ドメインオブジェクト***と呼ぶ。 ドメインとは、対象領域や問題領域という意味。 データとロジックは小さい単位に分けて整理する。 次のようなものが業務ロジック。 - 受注日と今日の日付から受注日の妥当性を判断する - 単価と数量から合計金額をけいさんする - 数値データの価格を千円単位の文字列表記に加工する クラスを設計するときには、地位異彩単位の業務データと業務ロジックの関係に注目する。 受注日に関連するデータとロジックは、OrderAcceptDateクラス。 単価に関する計算や判断処理のロジックはUnitPricdクラス。 価格を千円単位に丸め、「千円」という単位表示付きの文字列表記に加工するロジックはAmountクラス。 >[name=Yusaku Matsuki] > 例 > ```go > type OrderAcceptDate struct { > date time.Time > } > > func (o OrderAcceptDate) verify{ > ... > } > > type UnitPrice struct { > price uint64 > number uint64 > } > > func (u UnitPrice) TotalPrice{ > ... > } > > type Amount struct{ > > } > > func (a amount) display{ > ... > } > ``` 業務データと業務ロジックを小さい単位で整理したドメインオブジェクトを設計する。 小さなドメインオブジェクトを組み合わせて「顧客」「商品」「注文」など、より大きな業務の関心事を表現するクラスを設計する。 「注文」は業務の重要な関心事なので、早い段階でクラス候補として発見できる。 しかし、「注文」クラスは、ロジックの整理の単位としては大きすぎる。 「商品」「数量」「金額」「納期」「届け先」「請求先」という単位に分けてドメインオブジェクトを作る。 小さなドメインオブジェクトを組み合わせて「注文」オブジェクト組み立てる。 ### 業務ロジックの全体を俯瞰して整理する 業務データと業務ロジックをクラス単位で整理すれば、重複がなくなる。 しかし、ドメインオブジェクトを小さな単位に分けて整理すると、クラスの数が膨大になり、見通しが悪くなる。 クラスが多くなった場合の整理の手段が「パッケージ」。 ```graphviz digraph G { label = "ドメインオブジェクトを整理するパッケージの例" node [fontsize = 8, shape = "tab"] order [label = "注文"] shipping [label = "出荷"] billing [label = "請求"] deposit [label = "入金"] customer [label = "顧客"] item [label = "商品"] order -> customer [style = dashed] order -> item [style = dashed] shipping -> order [style = dashed] billing -> shipping [style = dashed] deposit -> billing [style = dashed] } ``` 矢印はパッケージの参照関係。 パッケージ参照関係は基本的に時間軸に沿った関係になる。 >[name=Yusaku Matsuki] > 参照関係は時間軸とは逆に表されてる。 > 顧客と商品が存在。顧客から商品への注文が発生する。注文をもとに出荷。出荷後に対価を請求。顧客から入金を確認。 顧客パッケージのオブジェクトは注文パッケージに含まれるオブジェクトを参照してはいけない。 注文パッケージの注文オブジェクトが顧客パッケージに顧客オブジェクトと、商品パッケージの商品オブジェクトを知っている必要がある。 最初からこのような関係をすべて厳密にできるわけではない。 整理し、改善を続けることで、業務ロジックの全体的な関係が明確になる。 業務アプリケーションの対象領域(ドメイン)をオブジェクトのモデルとして整理したものをドメインモデルと呼ぶ。 ### 三層+ドメインモデルで関心事をわかりやすく分離する ドメインモデル方式では、アプリケーション全体の構造はドメインモデルに集めた業務ロジックを三層が利用する形になる。 三層+ドメインモデルの構造では業務ロジックを記述するのはドメインモデルだけ。 | 名前 | 役割| | --- | --- | |プレゼンテーション層|UIなど外部との入出力を受け持つ| |アプリケーション層|業務機能のマクロな手順の記述| |データソース層|データベースとの入出力を受け持つ| |ドメインモデル|業務データと関連する業務ロジックを表現したドメインオブジェクトの集合| ## 第3章のまとめ ###### tags: `ISBN-978-4-7741-9087-7`