最近、書評をあまり書いていなかったので久しぶりに書いてみようと思います。
というのも LLM が発達した今日、個人が書評を書くことにあまり提供できる価値を感じていなかったのですが、将来の自分のために知識をまとめておきたいと思います。

書籍の概要
レガシーコードの正体
本書のタイトルにも記載されている「レガシーコード」は「誰かから引き継いだテストがないコード」と定義されています。かなりニュアンスが省略されており、保守などで辛い思いをしていないと意味を読み取れないと感じました。
少し捕捉すると、テストがないために期待する振る舞いが分からない。結果的に手がつけられず、長い時間放置されしまいレガシーとなってしまったコードというニュアンスが含まれているのかなと考えます。
一貫したテーマ
400P ほどある分厚い書籍ではありますが、コアにあるのは「どのようにして安全にコードを変更するか」というテーマです。そのために、問題を特定可能な十分に小さく繰り返し実行できるコストの低いテスト(単体テスト)が必要不可欠であり、テストができるように依存を排除する・構造を意識した設計・変更を行うためのプラクティス集です。
拙作のサンプル
以下の税込み価格を算出するサービスクラスはDatabaseConnectionに依存しており、このクラスの単体テストを書くには実際のデータベースとテーブル、適当なデータを用意する必要があります。
class DatabaseConnection { fun init(hostname: String, port: Int): DatabaseConnection.Ready { // 接続をトライして実際にDBにアクセスできることを確認する // このコードは適当に書いています。実際のライブラリを使用するものではありません return DBM.initFromResult( postgresql.manager.init(hostname, port) ) } } class ProductCalculator( private val db: DatabaseConnection.Ready ) { fun calculate(products: List<Product>): UInt { // 商品価格を取得する val today = LocalDateTime.now() val productPrices = db .exec("SELECT * FROM product_prices WHERE $today >= create_time AND ...") .map(::buildProducts) .associate { it.id to it } val 税抜の合計金額 = products.fold(0: UInt) { acc, product -> val price = productPrices.get(product.id) ?: error("該当する商品が見つかりませんでした。") acc + price } val taxRate = db .exec("SELECT * FROM tax_rates WHERE ...")?.let { buildTaxRate(it) } ?: error("税額が設定されていません。") val 税込の合計金額 = 税抜の合計金額 * (taxRate + 1.00) return 税込の合計金額 } }
このクラスのテスタ容易性を向上させるにはDatabaseConnectionの依存を排除して、内部で実際に SQL を実行する処理を取り除くのが良いでしょう。interfaceや Repository パターンを活用すれば簡単に完了することが想像できます。
銀の弾丸はない
Claude に本書を推薦され、レガシーコードを改善するための超絶☆最強テクニックがあるのではないかなと期待して読みましたが、そんなものは当然ありませんでした。銀の弾丸はないとは散々、言われ尽くしたことですが、レガシーコード改善についても同様です。
改善のヒントとなるプラクティスはあれど、システムの状況やアーキテクチャはどれも異なり、何がどう使えるかはコンテキスト次第です。実際のプラクティスについては数が多いので省略しますが、多くはコードから依存を排除するためのものでした。
感想
出版されたのは 2009 年なので、もう数十年前ということになります。
interfaceを使って依存を排除したり、スーパークラスを活用する方法などが、数十年前には提案されていたと考えると驚嘆させられます...。しかし、現代ではすでに基本的なテクニックとして昇華されていると感じるものが多く、あえて今、この書籍を読む強い理由はないかなと私は感じました。
なぜ「SOLIDの原則」や GoF(デザインパターン)で「継承より委譲」などが推奨されるのかの答え合わせができたのは良かったです。