著者:MartinFowlerさんの本『リファクタリング 既存のコードを安全に改善する(第2版)』を読んだので、その感想エントリーを書いていきたいと思います。
- 作者:MartinFowler
- 発売日: 2019/12/06
- メディア: Kindle版
本書の第1版は「Java」で書かれていたのですが、第2版は「JavaScript」で書かれているので、フロントエンドの方でも読みやすくなっていると思います。
*とはいえ、「JavaScript」で説明できない部分(アクセス修飾子の表現等)は、「Java」で書かれているので注意してください。
本書のChapterと感想
本書のChapter
は以下の通り、Chapter
ごとに感想を書いていきます。
- Chap.1 リファクタリング-最初の例
- Chap.2 リファクタリングの原則
- Chap.3 コードの不吉な臭い
- Chap.4 テストの構築
- Chap.5 カタログの紹介
- Chap.6 リファクタリングはじめの一歩
- Chap.7 カプセル化
- Chap.8 特性の移動
- Chap.9 データの再編成
- Chap.10 条件記述の単純化
- Chap.11 APIのリファクタリング
- Chap.12 継承の取り扱い
Chap.1 リファクタリング-最初の例
サンプルコード(劇団員を派遣して演劇のパフォーマンスを行う会社を想定して、演じた劇に対する請求書を作成するコード)を例に、リファクタリングしていく一連の流れが書かれています。
このChapter
を読むだけで、コードをリファクタリングしていく流れを体験できると思います。
私も本書を読むまで知らなかったのですが「いきなり目的に向かってリファクタリングをしても良いコード」と「いきなり目的に向かってリファクタリングをしてはいけないコード」があります。
たとえば、以下のようなサンプルコードがあり、関数名をinOldEngland(c)
をinNewEngland(c)
に変更したいとします。
const newEnglanders = someCustomer.filter(c => inOldEngland(c)); function inOldEngland(aCustomer) { return ["MA", "CA", "ME", "VT", "NH", "RI"].includes(aCustomer.address.state); }
関数名をただ変更するだけなので、直接関数名を変更したくなりますが・・・
ちょっと立ち止まって考えてみましょう!
関数名を変更すると、呼び出し側の関数名も変更する必要があります。
呼び出し側が1つしかないのであれば問題ありませんが、呼び出し側が複数ある場合、いきなり関数名を変更すると変更漏れが発生するかもしれません。
また、関数名が変わることで「引数の見直し」もしたくなるかもしれません。
このような場合、関数名変更後の関数を仮実装(inNewEngland(c)
を仮実装)して移行することを考えます。
// Step.1 // 関数名を`inNewEngland(c)`に変更 const newEnglanders = someCustomer.filter(c => inNewEngland(c)); // 関数`inNewEngland`を仮実装する function inNewEngland(aCustomer) { return inOldEngland(aCustomer); } function inOldEngland(aCustomer) { return ["MA", "CA", "ME", "VT", "NH", "RI"].includes(aCustomer.address.state); }
引数も見直します。
こちらも段階的に変更します。
// Step.2 const newEnglanders = someCustomer.filter(c => inNewEngland(c)); function inNewEngland(aCustomer) { return inOldEngland(aCustomer.address.state); } // 引数を`stateCode`に変更。呼び出し側(仮実装側)の引数を変更します。 function inOldEngland(stateCode) { return ["MA", "CA", "ME", "VT", "NH", "RI"].includes(stateCode); }
// Step.3 const newEnglanders = someCustomer.filter(c => inNewEngland(c.address.state)); // 引数を`stateCode`に変更。呼び出し側(実装側)の引数を変更します。 function inNewEngland(stateCode) { return inOldEngland(stateCode); } function inOldEngland(stateCode) { return ["MA", "CA", "ME", "VT", "NH", "RI"].includes(stateCode); }
上記コードで、ちゃんとテストをして問題ないことを確認してから、仮実装した関数は削除して、以下コードに変更します。
// Step.4 const newEnglanders = someCustomer.filter(c => inNewEngland(c.address.state)); function inNewEngland(stateCode) { return ["MA", "CA", "ME", "VT", "NH", "RI"].includes(stateCode); }
上記は遠回りなリファクタリングの方法です。
「テストをしていれば大丈夫!」と考える人もいると思いますが、「テストに責務を持たせすぎないこと!」というのも、本書では書かれています。
「リファクタリングは小さな変更の積み重ねであること!」これが本書でMartinFowlerさんの言いたかった事の1つです。
Chap.2 リファクタリングの原則
リファクタリングの定義、リファクタリングを行う理由、リファクタリングはいつすべき?、問題点など・・・
リファクタリングの原則について書かれています。
やっぱり「IDEを使うのがいいよね」的な話も書かれていました。
Chap.3 コードの不吉な臭い
いわゆるリファクタリングすべき場所を解説している。
このあたりは「不吉な臭い」等でググると書いている記事が多くでてくる。
とはいえ、第1版と第2版ではいくつか追加・削除されたものもあるので注意。
Chap.4 テストの構築
リファクタリングにはテストが欠かせない・・・というお話。
最近は、開発者にとってテストは関心事の1つになってきているとも書いてありましたね。テストやりましょう・・・・m( )m
Chap.5 カタログの紹介
ここから以下のChapter
すべてリファクタリングテクニックのお話。
「うーん、書いてみないとわからんなぁ・・・」という箇所は、雑に写経しながら理解しました。
Chap.6 リファクタリングはじめの一歩
関数と変数に着目したリファクタリングのテクニック集。
- 関数は一画面に収まらなければ、ロジックを詰め込みすぎだと考える
- 2回以上使われるコードはそれ自体を関数にすべき!
- パラメーターが多すぎるならオブジェクトごと渡す!
などなど、いわゆるリファクタリングの王道パターンに対するテクニック集が記載されていました。
Chap.7 カプセル化
クラスに着目したリファクタリングのテクニック集。
私はあまり意識していなかったのですが、関数からコレクションを返す時は、コピーか読み取り専用にするのが良いとされていますね。
昨今では、このあたりもパフォーマンス的に問題になることは少ないとも書かれていました。
前のChapter
でも書かれていましたが「変数・関数に名前を付ける -> 名前以上のことをする処理の場合はクラス化する」これを守っていればよさそうです。
委譲の隠蔽
と仲介人の除去
は使い方が難しいテクニック(= o = ;;)
Chap.8 特性の移動
クラスや関数のロジックの移動に着目したテクニック集。
オブジェクト指向の大原則「データ構造
と処理
を分離しよう」にしたがってリファクタリング(移動)しましょう!という感じですね。
ループの分離
なんかで書かれている「1回のループで処理したいという理由だけで、2つの異なる処理を同時に行っているループをよくみる。」というコメントは、イタタタ・・・・
Chap.9 データの再編成
変数、フィールド名やそれ自体の置き換えや変更に着目したテクニック集。
フレッド・ブルックスの名言「フローチャートを見せてくれても、テーブルを隠されたら煙に巻かれたままだろう。テーブルを見せてくれれば通常フローチャートは要らない。それだけですぐわかる」
それだけ、名前って大切なんですね。ところで、フレッド・ブルックスって誰?(= = ;;)注)すごい人です
「変更可能なデータは、ソフトウェアにおける問題の発生源となる。」とのことですね。
話は変わりますが、TypeScript
でreadonly修飾子
がありますが、これが使えるだけで結構変わりそうです。
Chap.10 条件記述の単純化
条件分岐に着目したテクニック集。
ポリモーフィズムによる条件記述の置き換え
は何を言っているのかさっぱりだったので、写経多め・・・
条件分岐にアサーションを入れてコメント代わりに使う方法があった。
Fowlerさんはセルフテスト
と呼んでいるそうですが、こんな使い方をするのもおもしろいですよね。
Chap.11 APIのリファクタリング
関数、関数の引数などの呼び出し側に着目したテクニック集。
個人的にでるかな〜?と思っていた、setterの削除
はここで登場。
「関数に渡す引数が、その関数に相応しいかを考えよう」をFowlerさんは責務という言葉を使って「債務が関数側に相応しいかを考えよう」と言っていました。
ファクトリ関数によるコンストラクターの置き換え
で、コンストラクター
の制限について書いていましたが、正直そんな事まで考えたこともありませんでした。m( )m
Chap.12 継承の取り扱い
最後は継承に着目したテクニック集。
委譲
と継承
を同列で考えたことなんてありませんでした。m( )m
委譲によるサブクラスの置き換え
と委譲によるスーパークラスの置き換え
はぜったい難しい。。。
さいごに
というわけで、雑な写経をしつつ、本を読み進めてみました。
大切なのはChap.3 コードの不吉な臭い
を覚えること。そして、それに着目して怪しいコードはリファクタリングしていくこと。
「リファクタリングはいつすべきなのか?」という問に対しても、Fowlerさんは「常に」と回答しています。
テクニックだけではなく、リファクタリングは身近なものでなくてはならないことを、この本で教わりました。
最初にも書きましたが、第2版は「JavaScript」で書かれているのですごく読みやすかったです。興味のある方は是非読んでみることをオススメします!!