おすすめされていた本の、「リファクタリング - 既存のコードを安全に改善する」を読んでみました!
本の内容
前半はJavaScriptで書かれたコードを題材に、この本で紹介されている原則に則ってリファクタリングをしていきます。
後半では前半のリファクタリングの際に用いた、様々な原則を丁寧なリファクタリング手法と共に説明されています。
より良いコードを書くためのテクニックをまとめた本といえば、「リーダブルコード」は名著として有名ですよね。
私は「リーダブルコード」も何度か読んでいますが、この本と比較すると「リファクタリング」はより具体例が豊富で、辞書的にも使いやすそうな書籍だなあという印象を持ちました。
参考になった具体例
確かに読みやすさが変わるなと思った項目を適当に2つ紹介していきます。
ファクトリ関数によるコンストラクタの置き換え
コンストラクタだけで初期化すると少し戸惑ってしまいそうな処理を、ファクトリ関数として置き換えることでよりわかりやすくできる原則のこと。 私自身はわりとシンプルにコンストラクタを使いがちだったので、これだけで扱いやすさがだいぶ変わるなという印象。
リファクタリング適用前
// sample.js leadEngineer = new Employee(document.leadEngineer, 'E');
リファクタリング適用後
// sample.js leadEngineer = createEngineer(document.leadEngineer); func createEngineer(name) { return new Employee(name, 'E'); }
委譲によるスーパークラスの置き換え
継承は既存の機能を再利用するのに強力な手法ですが、 何でもかんでも継承をしてサブクラス化してしまうと、ただ処理が複雑になってしまったり、使われない操作までもが継承されてしまう場合がありますよね。
古典的な継承の失敗例として、StackをListのサブクラスにしていることが挙げられていました。(Javaを例にすると、実際に継承されているのはVectorで、VectorがListのinterfaceを実装しているもよう。) Stackを実装するために、Listのデータ構造や処理を再利用するために継承する設計になっていたようですが、Listの操作はStackにあまり適合していないイメージ。 docs.oracle.com
//sample.java Stack<Integer> stack = new Stack<Integer>(); stack.push(2); stack.add(1);
たしかにJavaだとStackにVectorクラスのaddが実装されているのは気持ち悪い…。
C#のStackのドキュメント見てみたら、こっちのStackは割とシンプルで良さそうだった。 docs.microsoft.com
話は逸れたが、スーパークラスの関数をサブクラスで活用出来ないような場合は継承するのではなく、Listをフィールドに保持しておき、必要な操作はStackに任せたほうがスッキリする。
リファクタリング適用前
// sample.js class List { // 具体的な処理 } class Stack Extends List { // 具体的な処理 }
リファクタリング適用後
// sample.js class Stack { constructor() { this._storage = new List(); } } class List { // 具体的な処理 }
まとめ
具体的な改善例が丁寧に書かれていて、納得感が多い事例ばかりでした!
長いけど、読む価値はあると思います!!!