「レガシーコード改善ガイド」を読んだので、その要点

[レガシーコード改善ガイド（マイケル・C・フェザーズ ウルシステムズ株式会社 平澤 章 越智 典子 稲葉 信之 田村 友彦 小堀 真義 ウルシステムズ株式会社）｜翔泳社の本](https://www.shoeisha.co.jp/book/detail/9784798116839)

![image](https://www.seshop.com/static/images/product/10900/L.png)

からなるほどと思ったところのピックアップ、読書感想文です。以下目次は[紹介ページ](https://www.shoeisha.co.jp/book/detail/9784798116839) からの引用です。感想のハイライトを書くと、**第24章　もうウンザリです。何も改善できません** が読めただけでも良かったです。レガシーコードで「もうウンザリです。何も改善できません」と思っている人はこの章だけでもどうにかして読むと良い... 。



## 第1部 変更のメカニズム
> 第1章　ソフトウェアの変更
> 1.1　ソフトウェア変更の4つの理由
1.2　危険な変更

- **レガシーコードとは、単にテストのないコードである。**
- テストのないコードは悪いコードである。どれだけうまく書かれているかは関係ない。どれだけ美しいか、オブジェクト指向か、きちんとカプセル化されているかは関係ない。
- 依存関係は、ソフトウェア開発における最も重大な問題の1つである。レガシーコードを扱う時にはたいてい、変更を容易にするために依存関係を排除する必要がある。
- システム変更の方法は、大きく2つに分けることができる。以下2つ。
   - 編集して祈る（Edit and Pray）
   - 保護して変更する（Cover and Modify）
       - 残念なことに、編集して祈るがほとんど業界標準になっている。



> 第2章　フィードバックを得ながらの作業
2.1　単体テストとは
2.2　上位レベルのテスト
2.3　テストによる保護
2.4　レガシーコードの変更手順

> 第3章　検出と分離
3.1　協調クラスの擬装

> 第4章　接合モデル
4.1　巨大な用紙の文字の羅列
4.2　接合部
4.3　接合部の種類

> 第5章　ツール
5.1　自動リファクタリングツール
5.2　モックオブジェクト
5.3　単体テストハーネス
5.4　一般的なテストハーネス

## 第2部 ソフトウェアの変更
> 第6章　時間がないのに変更しなければなりません
6.1　スプラウトメソッド
6.2　スプラウトクラス
6.3　ラップメソッド
6.4　ラップクラス
6.5　まとめ


- スプラウトメソッド については以下がわかりやすい。

https://ryo511.info/archives/3744


> 第7章　いつまで経っても変更作業が終わりません
7.1　理解すること
7.2　遅延時間
7.3　依存関係の排除
7.4　まとめ

> 第8章　どうやって機能を追加すればよいのでしょうか？
8.1　テスト駆動開発（TDD）
8.2　差分プログラミング
8.3　まとめ

> 第9章　このクラスをテストハーネスに入れることができません
9.1　いらだたしいパラメータ
9.2　隠れた依存関係
9.3　複雑な生成
9.4　いらだたしグローバルな依存関係
9.5　恐るべきインクルードの依存関係
9.6　玉ねぎパラメータ
6.7　別名のパラメータ

> 第10章　このメソッドをテストハーネスで動かすことができません
10.1　隠れたメソッド
10.2　言語の「便利な」機能
10.3　検出できない副作用

> 第11章　変更する必要がありますが、どのメソッドをテストすればよいのでしょうか？
11.1　影響の調査
11.2　前方向の調査
11.3　影響の伝播
11.4　影響調査のためのツール
11.5　影響スケッチの単純化

> 第12章　1ヶ所にたくさんの変更が必要ですが、関係するすべてのクラスの依存関係を排除すべきでしょうか？
12.1　割り込み点
12.2　絞り込み点で設計を判断する
12.3　絞り込み点の落とし穴

> 第13章　変更する必要がありますが、どんなテストを書けばよいのかわかりません
13.1　仕様化テスト
13.2　クラスの仕様を明らかにする
13.3　狙いを定めたテスト
13.4　仕様化テストを書くための経験則

- レガシーコードに対する変更は、次のような手順で行うことができる。

1. 変更点を洗い出す
2. テストを書く場所を見つける
3. 依存関係を排除する
4. テストを書く

- テスト駆動開発は、次に示す手順で行う。

1. 失敗するテストケースを記述する
2. コンパイルする
3. テストを通過させる
4. 重複を取り除く
5. 繰り返す

- 仕様化テストを書くための簡単な手順は次のようになる。

1. テストハーネスの中で対象のコードを呼び出す
2. 失敗するとわかっている表明を書く
3. 失敗した結果から実際の振る舞いを確認する
4. コードが実現する振る舞いを期待するように、テストを変更する
5. 以上の手順を繰り返す


- 上記で仕様化テストは成功する。成功するだけでなく、クラスについて最も基本的な事実の1つを文書化したことになる。それは例えば `PageGeneratorを生成してすぐにgenerateメソッドを呼び出すと空の文字列が返る`、などという事実である。
- 仕様化テストは、一部のコードの実際の振る舞いを記録する。仕様化テストを書き、予期しないことを発見したのであれば、**発見した内容を明確にすることに価値がある。** それはバグかもしれない。疑わしいものとして印を付け、その部分を修正するとどんな影響があるかを調査すべきである。
- レガシーシステムでメソッドを使う前には、テストがあるかどうかを調べ、なければ、テストを書く。**作業を行っているとテストをコミュニケーション手段として使える。** 
- 開発者はそのメソッドに何を期待でき、できないかを感じ取れる。クラスをテスト可能な状態にするだけで、コードの品質が向上する。

> 第14章　ライブラリへの依存で身動きが取れません
> 第15章　私のアプリケーションはAPI呼び出しだらけです
> 第16章　**変更できるほど十分に私はコードを理解していません**
> 16.1　メモを取る／スケッチを描く
16.2　印を付ける
16.3　試行リファクタリング
16.4　使用していないコードを削除する

- 巨大なレガシーコードに対峙すると、**変更できるほど十分に私はコードを理解していません** というケースによく当たるが、以下は特に試みやすそう。
    - メモ
    - スケッチ
    - 印をつける
    - 試行リファクタリングする
    - 使用していないコードを削除する


> 第17章　私のアプリケーションには構造がありません
17.1　システムのストーリーを話す
17.2　白紙のCRC
17.3　会話の吟味



> 第18章　自分のテストコードが邪魔になっています
18.1　クラスの命名規約
18.2　テストコードの配置

> 第19章　私のプロジェクトはオブジェクト指向ではありませんが、どうすれば安全に変更できるでしょうか？
19.1　簡単なケース
19.2　困難なケース
19.3　新しい振る舞いの追加
19.4　オブジェクト指向の長所の活用
19.5　すべてはオブジェクト指向

> 第20章　このクラスは大きすぎて、もうこれ以上大きくしたくありません
20.1　責務の把握
20.2　その他の技法
20.3　先へ進む
20.4　クラスの抽出後

> 第21章　同じコードをいたるところで変更しています
21.1　最初のステップ

> 第22章　モンスターメソッドを変更する必要がありますが、テストを書くことができません
22.1　モンスターの変種
22.2　自動リファクタリング機能でモンスターに立ち向かう
22.3　手作業によるリファクタリングに挑戦
22.4　戦略

> 第23章　どうすれば何も壊していないことを確認できるでしょうか？
23.1　超集中編集
23.2　単一目的の編集
23.3　シグネチャの維持
23.4　コンパイラまかせ
23.5　ペアプログラミング

> 第24章　もうウンザリです。何も改善できません

- レガシーシステムを担当する人たちは、しばしば新規開発に携わることを望む。
- システムをゼロから構築するのは楽しい。しかし既存システムは時がたつにつれて不明瞭なものとなり、変更が困難になる。
- 何ヶ月かが経つと、既存システム、つまり現在保守しているシステムを置き換えるのはほとんど不可能なことが明らかになってくる。
- 人々は、保守チームが重要な仕事を担っており、将来誰もが頼らなければならないシステムの面倒を見ていることに気が付く。
- **つまり「新規開発は次のレガシーシステムになる。新規開発の芝は青くない」のである。**
- こんな書評もあります。[【感想】レガシーコード改善ガイド　【後編】 - Rのつく財団入り口](https://iwasiman.hatenablog.com/entry/2018/02/26/200000#%E7%AC%AC24%E7%AB%A0%E3%82%82%E3%81%86%E3%82%A6%E3%83%B3%E3%82%B6%E3%83%AA%E3%81%A7%E3%81%99%E4%BD%95%E3%82%82%E6%94%B9%E5%96%84%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%9B%E3%82%93)

>　これまた正直なタイトルですが、2部の最後はこんな時どうするかの話。
　プログラミングに楽しさを知った最初の頃の気持ちを振り返ってみよう。向こうで新しい開発をやってるチームが楽しそうに見えても、「隣の新規開発の芝はそれほど青くない」。成功する鍵はやりがいを見い出すことだ。コミュニティと交流を持ってみよう。物事をより良くする機会だと捉えよう。これを機会にテスト駆動開発をやってみよう。気晴らしに仕事と関係無ないコードを書いてみよう。
　不毛なレガシーコードの砂漠もリファクタが徐々に進んでコードを制御でき始めると、「優れたコードのオアシス」が現れてくる。そして楽しくなってくるよ…と締めくくっています。うーん、エモいです。


## 第3部 依存関係を排除する手法

- 依存関係を排除する具体的な手法について紹介している。
- テストがないコードにテストを整備することが目的。

> 第25章　依存関係を排除する手法
25.1　パラメータの適合
25.2　メソッドオブジェクトの取り出し
25.3　定義の補完
25.4　グローバル参照のカプセル化
25.5　静的メソッドの公開
25.6　呼び出しの抽出とオーバーライド
25.7　Factory Methodの抽出とオーバーライド
25.8　getメソッドの抽出とオーバーライド
25.9　実装の抽出
25.10　インタフェースの抽出
25.11　インスタンス委譲の導入
25.12　静的setメソッドの導入
25.13　リンクによる置き換え
25.14　コンストラクタのパラメータ化
25.15　メソッドのパラメータ化
25.16　パラメータのプリミティブ化
25.17　メソッドと変数の引き上げ
25.18　依存関係の押し出し
25.19　関数ポインタによる関数の置き換え
25.20　getメソッドによるグローバル参照の置き換え
25.21　サブクラス化とメソッドのオーバーライド
25.22　インスタンス変数の入れ替え
25.23　テンプレートによる再定義
25.24　テキストによる再定義

## 参考記事

[「レガシーコード改善ガイド」のススメ　第1回：レガシーコードの定義、テストの重要性とは (1/2)：CodeZine（コードジン）](https://codezine.jp/article/detail/4103)
[『レガシーコード改善ガイド』再入門〜 技術的負債とダンスを(5). 前回までは、『レガシーソフトウェア改善ガイド』を参考に、改善のゴールのすり合わせ… | by Eiji Ienaga | 時を超えたプログラミングの道](https://twop.agile.esm.co.jp/working-effectively-with-legacy-code-ebeaefafb900)


## まとめ

各書評で評判の

> 第24章　もうウンザリです。何も改善できません

は、自分でも思っていたこと ([「エンジニアはテクニカルサポートを絶対にやったほうがいい」 - カスタマーサクセスエンジニア論 - Qiita](https://qiita.com/e99h2121/items/b5c2497000c32d6fd3c3)) の後ろ盾になるくらい共感できる内容だった。

テストがないコードがレガシーコードであり、テストを書くことでレガシーコードに立ち向かえる。テストはつまり仕様書なのだなと理解できました。

[文法を学んだ次に知りたいのは、ゼロから巨大なコードを書き上げる方法ではなく、"既存のコードの改修を適切にやれる方法"なんじゃないか - Magnolia Tech](https://blog.magnolia.tech/entry/2022/03/20/092936)

以上参考になればさいわいです。