【社内勉強会報告】酔ってもわかる！現場で役立つシステム設計の原則 Part.1

# はじめに
### お前、誰よ
こんにちは。[AXLBIT株式会社](https://axlbit.com/)の[@ax-tabu](https://qiita.com/ax-tabu)です。
事業戦略室で新規サービスの企画・開発をしています。

### この記事について
新規サービスは素早いサイクルでユーザーのフィードバックを得て機能の追加・改修をする必要があります。
素早くサイクルを回したいのに、機能追加に時間がかかっていては、他のサービスに追い越されてしまいます。

どうすれば変更が楽で、素早く改修できるソフトウェア開発ができるか、自分の中で明確な判断軸が無かったので、様々な本を読み漁りました。
その中で『現場で役立つシステム設計の原則』の内容が自分の中でしっくり来たので、本の内容を自分なりに咀嚼したうえで他の社員にも共有したく、社内勉強会に登壇しました。

本稿では社内勉強会で話した内容を一部割愛しています。内容が気になった方は『現場で役立つシステム設計の原則』を買って実際に読んでみてください。

#### 酔ってもわかる！シリーズとは...
AXLBITでは隔週金曜日の業務終了後に社内勉強会を開催しています。軽食を食べながら、お酒を嗜みながら、わいわい楽しくやっています。
お酒が入るとどうしても思考力が低下したり、判断力が鈍ったりしてしまうこともあります。
このシリーズは酔っていてもわかるくらいに、簡単に説明することを目標としています。


* * *

# ソフトウェアの最大の敵は変更である
### こんな経験ありませんか
* １か所しか触っていないはずなのに、想定外のところでバグが発生する
* 仕様変更の内容は軽微なのに変更箇所が広範にわたる
* 変更しようにも、どこに何が書いてあるのかわからない
* コピペコードが多すぎてどこをどう直していいのかわからない

これが変更しにくいソフトウェアの典型です。
最初はきれいなソースコードだったものが、 **ちょっとした条件分岐の追加** や **ちょっとした関数への引数追加** で、じわじわとクラスやメソッドが大きくなり、変更しにくいソフトウェアが出来上がります。

### プログラムは生き物
プログラムは一度書いておわりではありません。提供しているサービスが終了するまで動き続けます。
書いた本人が退職した後にも動いている可能性もあります。
そして、そこには常に修正や拡張が伴い、まるで生き物のように動き続けます。
変更容易なプログラムを書けば、修正や拡張がスムーズに行えます。

### 変更容易なプログラムとは
* わかりやすい命名がされている
* 読みやすいように意味のまとまりで段落分けされている
* 変数を目的ごとに割り当て使いまわしていない
* オブジェクト指向設計

これらを意識してソースコードを書くと、今後のメンテナンス性が高まります。

# オブジェクト指向設計とは
オブジェクト指向設計とは、変更しやすいプログラムを書くためのノウハウです。
**現実世界に存在するコト・モノをそのままプログラムに落とし込む** ことで、プログラムで現実世界を表現することができます。
こうすることで、プログラムをそのまま仕様書っぽくなるので、別でドキュメントを用意しなくても開発者間で共有できます。
オブジェクト指向設計では、再利用可能な部品を作り、それを組み合わせて全体のシステムを構成します。


### 値オブジェクト・エンティティを使う
例えば、プログラムで「金額」を表現するとき、何も指定がなければ、int型やfloat型で書くかもしれません。
同じプログラムの中で、商品の「個数」を表現するには金額と同じようにint型で定義することもできるでしょう。
しかし、これらは変数名以外で見分けることができません。
さらに、int型はマイナスの値も許容するので、個数としてマイナス値も受け付けることになり、実態に即していません。

int型やfloat型、str型などプログラミング言語が提供する型を **プリミティブ型** と呼びます。
オブジェクト指向設計では、できるだけプリミティブ型を使わず、**実態に即したクラス** を用意します。
例えば、お金はMoney型、個数はUnit型のように定義します。

この実態に即したクラスのこと **値オブジェクト** や **エンティティ** と呼びます。

これらを使うと以下のようなメリットがあります。
* インスタンス化時にその値オブジェクトとして生成してよいかの検証もできる
  * 商品単価がマイナスの場合、不正な値としてインスタンス化させない
  * 値の範囲を制限して、プログラムをわかりやすくできる
* データと業務ロジックをまとめることで、より変更容易に
  * 業務ロジックがクラスにまとまっていると、どこを見ればいいかすぐにわかる
* 「型」が示せるので意味が分かりやすい

#### 値オブジェクトとエンティティの違い
値オブジェクトはお金や期日のように、個々を識別できないものを表現するときに使います。
エンティティはユーザーA、ユーザーBのように個々を識別するときに使います。

### 業務ロジックを集約する
変更困難なプログラムにはたくさんの条件分岐が含まれます。
この条件分岐こそがプログラムで解決したい業務上の課題であることが多いです。
しかし、条件分岐が増えるとどうしてもプログラムの見通しが悪くなります。
条件分岐を集約することで、どこでどんな判断が行われているかがすぐにわかります。

* 条件分岐が業務の関心事となる場合が多い
* 使う側に条件分岐が増えることは、あちこちに業務ロジックが散在すること
* 使われる側に条件分岐を移すことで業務ロジックがより集約されていく

# ドメインモデルの考え方で設計する

### ドメインモデルとは
業務で使用するデータと業務ロジックを集約したオブジェクトを **ドメインオブジェクト**  と呼びます。
さらに、ドメインオブジェクトを整理してまとめたものを **ドメインモデル** と呼びます。
**ドメイン** とはソフトウェアを使用して解決したい業務の **領域** 、 **関心事** のことを指します。
整理されていないソフトウェアでは、汎用関数や汎用クラスに業務ロジックが散在していることがよくあります。
業務データと業務データの判断ロジックをひとつのクラスに集約することで、見通しがよくなり、変更の影響範囲を狭めることができます。

###  ドメインモデルをどう作るか
オブジェクト指向設計では、部品を作り、それを組み合わせて全体を構成する、ボトムアップのアプローチをとります。
パッケージ図を活用しながら全体を俯瞰し、その中で業務において重要な部分や間違いなく必要になる部分を探し、そこから優先的に作ります。
開発当初はどこが重要な部分か判断できないことが往々にしてありますが、開発を進めるにつれ、理解できるようになります。
オブジェクト指向での開発は、修正や拡張を楽に早くできるようにするための手法です。開発を進める中で徐々にドメインモデルを洗練させることが、オブジェクト指向らしい開発といえます。

###  ドメインモデルをどう見つけるか
ドメインモデルとは、ソフトウェアを使用して解決したい業務上の関心事です。
業務上の重要な関心事や関係性に着目するとドメインモデルが見つかります。

業務上の関心事は主に、 **ヒト** 、 **モノ** 、 **コト** に分類できます。
* ヒト　＝　個人、企業、担当者など
* モノ　＝　商品、サービス、店舗など
* コト　＝　予約、注文、支払など

#### 先ずコトより始めよ

**コト** は業務活動そのものを表す、業務ルールの宝庫です。業務の専門家( **ドメインエキスパート** )は業務の流れを把握しているので、自分で全体を俯瞰して設計を始めるより専門家から情報を引き出すことで設計が進められます。
さらに、コトはヒトとモノの関係を表すので、コトから整理を進めると登場人物の整理がしやすくなります。コトに着目して全体の流れや関係者、前後関係を整理することから始めましょう。

### ドメインオブジェクトの関心事の基本パターン
ドメインオブジェクトにはいくつか決まりきったパターンがあります。自分で一から考えて設計を進めるより、よく使われるパターンに当てはめる方がスムーズに設計が進められます。

* 値オブジェクト
* コレクションオブジェクト
* 区分オブジェクト
* 列挙型の集合操作

### 業務の関心事の基本パターン
業務の関心事にも同じようにパターンがいくつかあります。

* 口座(Account)パターン
* 期日(DueDate)パターン
* 方針(Policy)パターン
* 状態(State)パターン

# おわりに
ソフトウェアの最大の敵は **変更** です。
一度作ったソフトウェアはサービスが終了するまで動き続け、その間に常に変更が伴います。
変更を楽にするやり方のオブジェクト指向設計で開発を進めると、スムーズに機能拡張や改善ができます。
改善しやすいプログラムを書き、開発者体験を向上させましょう！

# 参考文献
[現場で役立つシステム設計の原則](https://gihyo.jp/book/2017/978-4-7741-9087-7)