『リファクタリング(第2版)』を読んだ

かの古典的名著『リファクタリング』が全面改訂された第2版の翻訳書が発売されたので、読んだ。ちなみに第1版は読んでいない。

www.ohmsha.co.jp

初版との違いとして「サンプルコードがJavaからJavaScriptに変更になった」ということが目立つが、根本的には、クラスを中心とした設計を減らしていくという大方針に従って技術選定した結果と思われる。時代ですね。

The reorientation towards a less class-centered view is a large part of this.
The Second Edition of "Refactoring"

説明の分解能

各リファクタリングの手法について、動機・手順・例を詳細を、他にないほど丁寧に説明している。例えば、「変数名の変更」をする際の手順が以下のように紹介されている。

  • 変数が広く使われている場合、カプセル化を検討する
  • 変数への参照を探し、それらすべてを変更する
    • 変数が別のコードベースから参照されている場合 ...(略)
    • 変数が変更されない場合 ... (略)
  • テストする

プログラミングを仕事でやっている人で、「変数名の変更のやり方がわからない」という人はほぼいないと思う。そのため、ここに書かれていることはかなり冗長に感じる。一方で、変数名の変更を「常に最適な方法でやっている」と自信を持って言える人は少ない気がする。本書の価値はそこにありそう。例えば、新規サービスを開発するプロジェクトにおいて、どうやって作るか、なぜその方法を選択するのかについて、説明を求められることは普通にある。ただそこからどんどん粒度を細かくしていったとき、どこまでその合理性を説明できるか。

本書はなにげなくやっているリファクタリングについて「自分がいま何をやっているのか、なぜそうするべきなのか」を言語化し、説明可能な状態にしている。これはまた、熟練者の「感覚でやっている、慣れろ」という謎の説明放棄に苦しむ初学者にとっても、助けになるかもしれない。同時に、初学者の側も、「なにがわからないのか」を分解して言語化する努力をすべき。というかそれができたら実は問題が解けている、ということが往々にしてある。説明の分解能は理解度に直結している。その意味で、著者はリファクタリングをめっちゃ理解している。

タスクの細分化

人間の脳はシングルコアであり、マルチタスクには向かない。例えば、リファクタリングと、他の目的(機能追加やチューニング)を混同して同時にやろうとしてはいけない。前述と同じで、「いまなにをやっているのか?」と聞かれてシャープに答えられる状態が理想。リファクタリングをするためには、計画が必要。既存のコードに手を入れる場合に「まずリファクタリングし、そのあとの機能追加する」というように計画に組み込まないと、片手間にやろうとしてもだいたい失敗する。あるいは、片手間にすらやろうとせず既存のコードに手を入れてしまうと、レガシーコードに工数が飲み込まれる。

そもそもタスクを細分化することが必須の場面もある。なぜなら、だいたいのレガシーシステムは肥大化し、「つくりなおす」みたいな非現実的な夢を語ることしかできなくなる。これは明確な思考停止状態。段階を踏めないか、と考え、まずプロジェクトを割れるだけ割ってみる。細かなところでいうと、上述の変数名の変更の例では、手順の1つ目に「変数が広く使われている場合、カプセル化を検討する」とある。変数がいろんなところから参照されているなら、それらを一気に変更する必要がある。副作用や漏れがあるかもしれない。カプセル化すれば、参照もとの変更は、一気にやらずひとつずつ段階的に移行できる。コストとリスクのトレードオフでもあるが、選択肢があると戦略を練る余地がある。

また、計画段階でリリースを細分化できることが多い。そうするとバグなどのリスクを低減できるし、featureブランチが不必要に育っていくという状態を防げる。自分がこれまでにやったプロジェクトを振り返っても、うまくいかない部分はだいたいこの計画段階に集約される。プロジェクトの要件と仕様がある程度わかった段階で、どうやってリリースするかを具体的に想像すると幸せになれそう。

設計と計画だいじ

「デザインスタミナ仮説」ははじめてきく言葉だった。内部の設計を入念にやれば、ソフトウェア開発をより長い期間、より速い速度でできる、という仮説。仮説なので、もちろん実証はなく、著者のこれまでの経験に即しているらしい。

martinfowler.com

会計的なメタファを使うと、設計償却線が存在する。そして、この設計償却線が、一般に想像するよりもはるかに下にあるのでは、ということをいっている。つまり、一般に設計が足りていないという主張をしている。前述のスコープを刻むというところにも即するが、設計のための調査と、それに基づいた実装は、意識して区別したほうがいい。ついコードを書き始めたくなる気持ちはすごくあるけど、情報が不足している状態で実装を始めると、だいたいろくなことにならない。

また、本書では自動テストについても触れている。テストコードを書く段階をいつ設けるかはそれぞれの事情があるけど、すくなくとも新たなインターフェイスを定義し、それに期待する振る舞いがある場合は、テストを書く前提で設計したほうがいい。

手動テストははらわたがちぎれるほど退屈 (p.91)

まったくもって同意。テストを書くことは、品質を担保するだけでなく、これから何を作るかを明確にできる。どんなテストを書いていいのかわからなければ、それは何を作っていいのかわかっていないという状態なので、作り始めてはいけない。既存のコードでテストが書きづらいものもあるが、だからこそリファクタリングが必要とされる。計画し、必要ならしっかり議論しましょう。