易しい言葉でめった刺しされる一冊に出会った

# はじめに
[良いコード／悪いコードで学ぶ設計入門 ―保守しやすい 成長し続けるコードの書き方](https://www.amazon.co.jp/dp/4297127830)、いわゆる`ミノ駆動本`を読んだので読書感想文です。


# どんなことが書かれているか
**悪いコードがどんなものか、それを良いコードに変えるにはどうしたらいいか**について、さまざまなテクニックが、平易な文章とわかりやすいサンプルコードとともに書かれています。それに尽きます。


# 感想
## とにかく読みやすい、そして刺さる
ページ数が多く一瞬尻込みしましたが、ぺらぺらっと立ち読みしてみると、易しい文章でサンプルコードも多く、さくさく読み進められそうでした。続きがもっと読みたくなって購入。

読み進めてみると、すごく読みやすいのに、内容はとってもとっても鋭利でした。めった刺し。
ただし、めった刺しされるかは個々の状況によるとは思います。
すなわち、いかに「悪いコード」と相対していて、そして自分自身も「悪いコード」を生み出しているのかによります・・・

少なくとも私は、「悪いコード」の例、実コードでよく見かけるものや思い当たる節が多々あります。
この本を読んだ後に製品コードを見て、「あ、これ進研〇ミでやったやつだ！」現象が何度起こったかわかりません。

刺されて苦しいけれど、刺されるからこそ、「もっと読みたい」。
そう思わせられる技術書ってシンプルにすごいと思います。


## コードレビュー時の共通認識として頭に入れておきたい1冊
感覚的にだめだと感じていることを論理的に解説してくれているため、曖昧だった設計への考え方に後ろ盾ができる感覚です。
レビュワーとしてもレビュイーとしても、指標の1冊にしたい。


## 今すぐにでも実践できる要素が盛りだくさん

- 変数は使いまわさない
- ネストは浅く
- 早期return
- 最初にガード節
- 基本は不変

このあたりは即実行案件です。


## 「ちゃんと」教えてくれる
これってありそうでないです。カッコよく、洗練された要約じゃなく、「ちゃんと」書いてくれている本。

筆者が「悪いコード」と対峙した時、まずどこを見るか、どう感じるか。そして退治のために何から始めるか、それをやったら次はどこを直すのか、そうしたらここも気になるよね、などなど。
考えていること、やるべきことを1つ1つ丁寧に書いてくれています。
さながら頭の中で勝手に動画が構築されていく感覚。


## 少しでも製品コードに触れてから読むと見え方が違うはず
学習はしているけれど実務でコードに触れたことがない、という方は、刺さり方が浅いかもしれません。実感が伴いづらいからです。

少しでもいいから製品コードを読む。欲を言えば軽微な不具合修正1つでいいから自分自身でも製品コードを書いてみる。
これらを経験してからこの本を読んだ方が、よく腑に落ちると思います。


## その他、とりわけ刺さったポイントを章ごとに

### 【第8章】継承による悪しき共通化
このセクションで書かれているロジック、散見されるし自分自身もやってしまっている。心が苦しいセクションでした・・・


#### 8.1.6 DRY 原則の誤用
DRY(Don’t Repeat Your Self：繰り返しを避けること)原則については、私自身誤った解釈が頭にありました。重複コードすなわち悪、という部分が強く刷り込まれていて、もはや重複ロジック恐怖症に近いというか。
DRY原則とOAOO(Once and Only Once:1度、ただ1度)原則を混同している結果なんだなと認識しました。

DRY原則の誤解釈については下記がわかりやすかったです。

https://qiita.com/yatmsu/items/b4a84c4ae78fd67a364c

https://qiita.com/morerowsea/items/91a2f8e51cdf212f6abd

安易なコピぺは悪だという考えは変わらずですが、ミノ駆動本の下記の言葉を自戒のための一節として引用しておきます。

> 知識とはいったい何でしょうか。粒度、技術レイヤー、さまざまな観点で考えることができますが、その内のひとつに、ソフトウェアが対象とするビジネス知識があります。ビジネス知識とは、ソフトウェアで扱うビジネス概念です。

> DRYにすべきは、それぞれの概念単位なのです。同じようなロジック、似ているロジックであっても、概念が違えばDRYにすべきではないのです。

そしてこちらも。

> 異なる概念であることがわかった段階で共通化を解くなど、すぐに構造を見直しましょう。


#### 8.2.3 なんでも public で密結合

> 　デフォルトのものは表記を省略する仕様が、さまざまなプログラム言語やフレームワークに備わっています。デフォルトと異なっている場合のみ、違いを明記するという考え方です。なぜアクセス修飾子を省略したデフォルトの状態だと package private なのでしょうか。
　それは、パッケージどうしの不要な依存を避けるにはpackage privateが適切だからです。パッケージは、強く関連付くクラスどうしを凝集するよう設計します。

デフォルトは同じpackage内での参照に留めるべきというのが言語の設計の根幹にあるからだというところ、あーなるほどなと思いました。
私も基本publicで書き始めてしまっていました。反省。
少なくともこれから書くコードについては、基本はpackage private、本当に外部公開すべきもののみpublicにできるよう設計時点で気を付けていこうと思います。


### 【第9章】設計の健全性をそこなうさまざまな悪魔たち
#### 9.9 技術駆動パッケージング
パッケージの切り方、意外と指針にできるものが見つけられず、いつもものすごく悩んだ末にいまいち腑に落ちない切り方をしていました。そんなこれまでの私に対する1つの大きな解を与えてもらった気持ちです。

**パッケージは、設計パターンではなく、ビジネス概念で切るべきである。**

第8章は、めった刺しされて割と瀕死状態でした。でもどこかで「いやでもパッケージ外を見に行かないとか限界があるよな・・・」と思っていました。技術駆動パッケージングされた製品コードにどっぷり浸かっていたからです。

そんな甘えた言い訳も、完膚なきまでに打ち崩されました。

service, controller, entityなどの設計パターンごとのパッケージの中に、ビジネス概念ごとのパッケージがいる、という状態はよく見かけますし、自分もやっていました。
思えば上位パッケージは割とビジネス概念で切られているけれど、末端になればなるほど技術駆動のパッケージングになりがちだな、などとも。

ビジネス概念ベース！を念頭に置こうと再度決意しました。

すでに技術駆動でパッケージングされた製品コードの中でビジネス概念ベースでのパッケージの切り方をするのは骨が折れるかもしれないですが、挫けずコツコツと進めていこうと思います。


### 【第14章】リファクタリング ー既存コードを成長に導く技ー
第13章までは、「どう書くべきか」に焦点を置かれています。ただ正直、年季の入ったシステムと対峙する場合は「それができたら苦労しないんだよな…」と思うところもありました。
そう思っていたらこの章で、すでに存在して動いているソースコードをどうリファクタリングしていくかについて、結構なページ数を割いて書かれていました。

特に**14.2.2 テストコードを用いたリファクタリングの流れ**は、筆者がテストコードを利用してリファクタリングをする際、どういう思考でソースコードを改良していくか、その一挙手一投足が書かれていて、最近[ユニットテストデビュー](https://qiita.com/moromi25/items/9358c716cb7d70fde31a)をした身としてはとても参考になりました。
そして筆者が常日頃「悪いコード」と戦い続けている猛者であるのだな、と改めて感じました。


# レガシーコードはすべて「悪いコード」か？
ところで、あくまでも弊社のソースコードを読んでいての所感ですが、「レガシーコード」と一緒くたにされる割と昔のソースでも、たとえば私が先に挙げたようなDRY原則やpackage privateをデフォルトとした設計、ビジネス概念ベースでのパッケージングなど、しっかり守られているコードは当然あるんですよね。

すべての「悪いコード」が、昔の人が作りあげた負の遺産なのではない。

昔とか今とか関係なく、半端に学んだだけで、なぜそれぞれの概念が存在しているかを考え切れていなかったり、すでに存在する「悪いコード」に安易に右に倣えしてしまったりしていた（残念ながら私も含む）開発者が、さらに「悪いコード」を量産してしまっているのだろうなと感じます。
それを阻止するべく開発者1人1人が学んでいかなければいけないし、コードレビューが機能しなければいけないな、とも。


# おわりに：【第17章】設計技術の理解の深め方 より
本を読めば知識はつきますが、当然ですが本を読んでいるだけで実践的なスキルがつくわけではありませんし、ソースコードの状況は千差万別。この本に書かれている例示だけでは当然足りません。
筆者も第17章の中で、下記のように書かれていました。

> リファクタリングの練習題材にするのは普段仕事で使っているプロダクションコードです。プロダクションコードは泥臭い複雑さを抱えています。だからこそ、実践レベルで使える設計力を養えます。

> サービス開発可能な実践的なプログラミングスキルを身につけるには、プログラミング言語の入門書を読んだだけでは困難です。実際に機能要件を自分で噛み砕き、要件を満たすロジックを考えて組んでいく経験が必要です。

よし、あとはとにかく実践あるのみ！

迷ったときには再度この本に刺してもらおうと思います。