プリンシプルオブプログラミング2回目

# 前振り
前回は書籍の第１章【前提】をやりました。
以下にその議事録を添付します。

https://qiita.com/Kudo_panda/items/0fa39bd387434818f20a

今回は２章の
・KISS
・DRY
・YAGNI
・PIE

の4項目になります。

本に書かれていないような自分なりの発見や
こんな時には、この原則には従わないよな～という思いなんかも記載します。

では、早速行きましょう。

# 2.1 KISS - Keep It Simple Stupid -
コードはシンプルにしておけ　という意味です。
当たり前なことを言っていますが、コード以前に複雑なワークフローはよく見かけます。
何をやってるのか？全然意図がつかめないというようなフローです。

## シンプルでないと何が起きる？
シンプルでないと、コードやワークフローは無秩序になり、
構造が崩れ去ったり、粒度感がそろわなくなり、それはコンテキスト境界の正しい位置を
不透明にしてしまいます。
結果的にそれは、変更容易性を低下させ、負債の解消がしづらくなってしまう。

## 何を心掛ければいいのか？
余計なことをしない！　本当に必要な物以外を継ぎ足さないってこと。

「何かを追加する処理があるから、何かを削除する処理も必要であろう」
みたいに、今必要ではないものを勝手に付け加えないこと。
これは後述のYAGNIとの関連性もあります。

:::note info
処理だけではありません、データに関しても一緒です！
:::

「こんな属性も必要なんじゃないか」みたいな余計なことは、メンテ性を低下させる行為です。
必要になってから反復的に要件の追加を行う方が安全です。


### 注意事項
一方で、何か要素を追加する処理があるのならば、
その要素を削除する処理も持つ　という、

:::note warn
【対象原理】には反する考えでもある
:::

と感じます。

そのため、あくまでも必要な物だけを追加しつつ、
頭の念頭に、「対象になるような処理は本当に不要なんだろうか？」と思い描きながら、
次の仕様変更時に不要なのかどうかの検証を行うというのは１つの手です。

## 戦術的フォークでKISSを満たしやすくする
コンポーネント内の不要なコードをボトムアップ式に削除していくパターンのことを
戦術的フォークという。詳細なその方法は下記の記事を参照ください。

https://qiita.com/Kudo_panda/items/4c2c7922c5a8079fe73d

この戦術的フォークによって、不要なコードを定期的に削除すること。
それによってシンプルさは保ちやすくなる。
それにメンテのコストなども削減できる。

それはプログラムのコードだけでなく、分析データなどに関してもそうである。
不要な価値を生んでいない分析データを大量に集めるだけ無駄なので、
不要なものはリスクを抑えるために、可逆性を担保しながら小さく消していく。


## 不用意にinterfaceを盛り込まない
コードは変更されるものであるものの、不必要に抽象概念を盛り込むことによって
複雑性が増してしまうリスクがあります。

不用意な抽象概念が大量にあることで、解析性が低下します。
解析性が高いことは、変更容易性を高めるうえで必須条件です。

その変更容易性を高めるためだからと言って、何も考えずにinterfaceを盛り込んだ結果、
解析性が低下してしまっては、逆に変更容易性が低下しかねません。

## コアドメインの複雑さはいかに？
シンプルにとはいっても、競争優位性を発揮し、かつ複雑さのあるコアドメイン部分などは
どうしてもシンプルではなくなってしまう。

だからこそ定期的に不要なものを戦術的フォークなどを用いて削り落とし、
適切にパッケージ協会などで境界を切り分けるなどして、シンプルさをキープしないと
その後更新されていく中で、正しい境界位置を見誤るリスクを高めてしまう。

## 要求そのものもシンプルに！！
これは議論の中で出てきた内容であるが、そもそもの前提になる

:::note warn
要求に無駄があるとコードも無駄なものが混在してしまう。
よって要求に無駄がないかのチェックをする。
:::

これは非常に大事と感じます。
あらゆる複数の要求を一度に実現しようとする案件を過去に見たことがありますが、
その後の結末は言うまでもないです。

要求が複雑ゆえに、機能的なフローも複雑になりやすく、
かつ　満たすべき品質要件なども複雑化してしまい、結局どんな意図があるから
そのアーキテクチャにしたいのか？などという繋がりを見失いやすくなります。

そのためにも、要望リストから蒸留作業を通して、要求に昇華させる段階で、
洗練しシンプルかつ最小限の要求に厳選する必要があります。

これに関しては、以前書いたこの記事が参考になります。
ボトルネック部分に対する施策だけに選択集中するということです。

https://qiita.com/Kudo_panda/items/b11e9b3ca267392aeeec

これは結果的に「Less is more(より少ないことはより豊か)」ということにもなります。

あまりにも大量の要件では、余計なコードも混在しやすく、
複雑に絡み合うリスクもあり、結果的にソフトウェア品質を低下させるリスクにも繋がるからです。

# 2.2 DRY - Don't Repeat Yourself -
概念の重複をなくしなさいということ。
この【概念の重複】という所がポイントで、偶然の重複による部分は１つにまとめてはいけない。

## DRYでないと何が起きる？
### 解読の時間が倍増する
似たようなコードが複数あることによって、その分だけ読む作業が増える傾向にある。
似ているだけなのか？　それとも完全に内容が一緒なのか？　
それを読み解く必要があるため、解読に時間がかかってしまうのだ。

### 修正コストが倍増する
それだけでなく、重複したコードがあることによって、下図のように直す作業が単純計算倍増する。


これが重複の数が2、3個とかならまだいいが、10個とか20個とかってなってくると、
修正コストも高くつくし、何より一部修正し忘れとかってリスクも出てきてしまう。

## 何を心掛ければいいのか？
:::note info
重複している部分を１つに共通化してまとめてしまう。
:::

これによって、もともと重複部分であったコードに変更が入った際にも、
その１か所を変更すればいいというように、修正コストを抑えられる。

さらに、まとめた部分はその単位で再利用しやすくもなる。
このあたりの考え方は、コンポーネントの凝集原則の再利用に関する以下の2つの原則を参考にするといい。

https://qiita.com/Kudo_panda/items/6cffc8b0ac246b988263

https://qiita.com/Kudo_panda/items/62012f0c10e04b968074

### データベースでのDRY
また、この重複部分を１つにまとめるというのは、
データベースでの「１つの事実は１か所のみに」という原則の考え方と似ている。
DBの方では、格納されるデータの重複を禁ずることによって、
データの不整合リスク(こっち更新されたのに、こっち古いままという状態)を防ぐ。

「１つの事実は１か所のみに」を実現するために、通常第三正規化までを行う。
ちなみにDBにおける「１つの事実は１か所のみに」を実現する手段は正規化しかない。

:::note warn
ちなみに筆者の経験則的に、もちろん丁寧に正規化を行うスキルも大事だが、
チームでデータモデリングを行いつつ、トランザクション境界の位置を探索し、
継続的に「このデータの集合で1つのテーブルだよね。」というデータモデリングを
行いながら、データのコンテキスト境界位置を探る活動をしていれば、
自ずと第三正規化は実現できている印象である。
:::


## 何を持って概念の重複なのか判別が難しい時
正直言って、早期に「こことここ似ているからDRYに従ってまとめちゃえ！」と判断するのはナンセンス。
まだ本当に概念の重複と確信できていない段階で共通化し、
その後やっぱり共通化してしまったけど、概念としては別物であった
なんてことが発覚した際、それを修正するのはなかなか体力を要する。

なので、

:::note info
コードの内容が一緒であり　かつ

変更される際に必ず下図のようにどこか１か所だけとかではなく、
すべての似ている箇所が常に同時に変更されるといったことが続く
:::
という場合に、１か所にまとめてしまうと決定する方が安全と言えば安全。

## ※重複による恩恵
様々な設計案では、DRYでは重複を許すなという思想が強いですが、
一方で重複察せることによる恩恵があるのもまた事実です。

:::note warn
すべての設計案は、必ず長所と短所があります。
DRYに従った設計が常に正しいということはなく、それによるデメリットも当然あります。
:::

その代表的な例を2つほど見ていきましょう。

### 継承
デザインパターンのTemplateパターンなどがそれだ。
もともと具象なクラス群にあった、共通の属性や処理をまとめて抽象クラスに定義する。

これはその共通化した部分に変更が入る可能性が低いのであれば、
再利用することができ、その分開発速度を速めてくれるので嬉しい。

その代わりにもしも共通化した部分に変更が入ってしまった場合には、
サブクラス側の方全体に変更の影響が波紋してしまい、
開閉原則を満たしているとは言えない状況を作り出してしまう。

つまり、コンテキスト境界の維持ができているとは言えない状況。

### 再利用パターン
継承の時の構造と何となく少し似ているケースを紹介しましょう。
詳細は以下のページに載っています。

https://qiita.com/Kudo_panda/items/e8bad3a20b9e9c2c350b

複数のサービスに対して重複してコードを持たせる【コードレプリケーションパターン】

これは、

:::note info
・コードを共有しないから独立性を担保できる
・サービスコンテキスト境界の維持ができる
:::

という長所があるのに対して、

:::note alert
・重複部分のコードを変更するのが困難
・サービス間で重複部分の整合取るのが難しい
:::

などの問題がありました。

DRYに則った再利用パターンが、上記の再利用パターンの記事にある
共有ライブラリパターンと　共有サービスパターンになります。


## まとめ
たしかにDRY原則には多くのケースでしたがった方がいいものの、
上記のようにコンテキスト境界の維持をどうしてもしたいとか、
まだ本当に共通化したらいいのかわからない　といった
特別な理由がある時にはやむをえずにあえてDRYを破ることもある。

いずれにしてもそれらのWHYになる前提の想いとして「こんな脅威は避けたい」という脅威分析を脅威モデリングなどを通して丁寧に行うことで、DRYをあえて破るのかどうなのか？が見えてくる。


# 2.3 YAGNI
「こんなもの必要かもしれない」と思って付け足したものは必要にならないということ。
アジャイル開発でも、今本当に必要な物だけを徐々にイテレーティブに作っていこうというマインドがある。

これはコードに限った話ではなく、さらにその前提の要求開発や要件定義でも
「こんなものも必要ですよね」的なものは大体使われず、でも構造を複雑にしてしまい、
無駄にメンテコストはかかる。
さらにはモノリスで蜜結合な時には、その不要な部分と結合してることで、
無駄にテストコストなどもかかるといった負債が増大する要因にもなる。

## KISSとの関係性
この原則を破ると、自ずと前述のKISS原則も守りにくくなってくる。
それはプロセス面だけではなく、データに関しても言えること。
「こんなデータもあった方がよさそうかも」みたいに、
業務データにせよ、分析データにせよ、不要なデータがあることによって、
データのコンテキスト境界の位置を見誤ったり、そのデータの意図が不明確になる。
さらには、分析データに関しても、不要なデータが混在していることによって、
意思決定時に判断をミスる可能性も高まる。

## 早期からの拡張性の考慮
コードには確かに変更や拡張入るのが当たり前ではあるものの、
売れるプロダクトなのかも定かではない段階で、早期に「ここには拡張性が求められるだろう」みたいに考えて、interfaceを盛り込むなどというのは、かえって複雑化させてしまう。
だから大事なのは

:::note info
そこに本当にinterfaceを盛り込む必要はあるのか？
本当に必要になってから定義する！
:::

というマインドである。

せっかく定義した抽象概念も、使われるプロダクトであり、
その抽象概念を実装するコードに本当に変更が入るのであれば、interfaceを定義した意味があるが、そんな未来のことは予測できない。

まとめると

:::note warn
拡張性は必要になってから考慮する。
:::

## 何を心掛ければいいのか？
今本当に必要な物だけにすること！　これに尽きる。

それは目に見えやすい機能的なコードだけではない。
こんな脅威にも対応したい、こんな脅威にも対応したいと
保証すべき品質の項目を最初から増やし過ぎて、それをアーキテクチャに反映させてしまう
こういった行動もYAGNIには反するといえる。
せっかく時間かけて考えたアーキテクチャも要求を満たさずに、使われないシステムになってしまうことになる。

:::note info
本当に今必要とされる品質項目を満たすアーキテクチャを考える。
:::

早期からの非機能項目の決めつけではなく、継続的に考えること。
そしてそれをアーキテクチャに反映させ続ける活動が大事。

### テスト観点でもYAGNI
脅威モデリングなどでリスクをチームで評価したら、それをもとにテスト計画を継続的に考える。
もしもそれをせずに、今本当に必要なテストだけを考えるのではなく、
よくある後工程でテストを第三者検証会社に丸投げ状態では、不要なテストまで【やりすぎ】なことに繋がってしまう。

:::note info
不要なテストはやらずに、今本当に必要なものだけをテストする！
:::

これは【選択と集中】の考えに近いものすら感じます。

# 2.4 PIE
意図が明確になるようにプログラミングせよということ。
つまり名前などを見て読み手が意図がわかるとか。
そうすることで、読む時間を削減することにも繋がる。

## PIEによる恩恵

### コンテキスト境界位置の精度がUPする
コードの意図が伝わりやすいと、開発者がコードを書きながら、
ボトムアップ式に今のコンテキスト境界の位置が変わってきた際に気づきやすいという利点がある。

例でいうと、仕様変更に伴い、今修正しているクラスが
【本当に現在配置されているパッケージ下でいいのか？】と
クリティカルシンキング的に問うてみて検証する。
これによって、モデリングというトップダウンアプローチとの組み合わせで、
コンテキスト境界の位置の精度はぐっと跳ね上がりやすい。

### 仕様変更の際の変更箇所の特定がしやすい
意図がわかりやすいと、何か今あるコードに修正が入るようなケースでも、
どこが変更されるのか？といった特定の時間の削減にもつながる。


## KISSとの関係性
前述のKISSと関係している。
シンプルにしているがゆえに、意図がわかりやすい。
意図が不透明ということは、それはたとえば処理が複雑怪奇になっている。
または、複数の目的を担ってしまっていて、単一責務に反しているかもしれない
ということにも繋がる。

## 何を心掛ければいいのか？
極力コメントでの説明なくして、メソッド名や変数名、モジュール名で意図が具体的に
共通認識持てるような名前やコードを心掛けることが重要。
その際に思うことは、やはり良い名前の設計のために、
チーム全体や時に越境してみなでドメインモデリングしながら、よい名前を探索すること。

そしてコードで表現しきれない、Whyにあたるものに関しては、
コメントとして書かないと、Whyの情報がわからないという場合に限って、
１つ上の上位目的の内容を残すというようにすれば、トレーサビリティがはかれる。

この

:::note warn
1つ上の上位目的の内容
:::

というのがポイント。
クラスだったら、そのクラスの配置されているパッケージ全体がどんな目的を果たしたいのか？ということをコメントとして残すということ。

## チームトポロジー的な話
チームトポロジーでも、確か３章とかでチームの名称や配置構造を名称からわかりやすく
することによって、どのチームがどんな責務を担い、どんなデータを所有しているのか？
類推しやすくせよ的なことが記載されていた記憶がある。

これは組織のアーキテクチャなどを考えている人などなら、
必ず意識していることだが、大規模になればなるほど、チーム名などがコンテキストのわかりやすい名称になっていて、かつAチームのサブチームのaとかっていう場合なら、
「A.a」みたいに構造というか粒度感がわかるような名称になっていることが重要。

それによって、サブチームaの行動方針は、親のAの方針にのっとっていないとダメだな
というリスコフの置換原則を使った検証などを行いやすくなる。

:::note warn
ちなみに上記でも記載したように、そのチームがどんな要求を満たし、
どんなリスクを防ぎたいのか？　といった意図に関しては、
チーム名だけで表現できない場合には、文章化するなどして対応する。
:::