第11章 APIのリファクタリング
問い合わせと更新の分離
値を返す関数は、観察可能な副作用をもってはならない
→ コマンドとクエリの分離原則
必ずしもこの原則を取り入れる必要はないが、多くの場合従うようにするべき
手順
- 関数をコピーして、問い合わせ用の名前をつける
- 新しい問い合わせ関数から副作用を全て除去する
- 静的検査
- 元の関数の呼び出しを調べる
- 戻り値を使っている場合は、呼び出しを問い合わせ関数の呼び出しに書き換え、元の関数を呼び出しの後ろに挿入する
- 元の関数から戻り値を削除する
- テスト
パラメーターによる関数の統合
リテラル値が異なるだけの、非常に似たロジックを持つ二つの関数があるなら、異なる値を渡すためのパラメーターをもった一つの関数を用いることで重複を排除できる
手順
- 類似の関数のうち、一つ選ぶ
- 関数宣言の変更を適用して、リテラル値を全てパラメーターに変換する
- 関数を呼び出しているすべてのところで、対応するリテラル値を渡す
- テスト
- 新しいパラメーターを使用するように関数の本体を変更し、その度にテストする
- 類似の関数それぞれについて、元の関数呼び出しをパラメーター付き関数呼び出しに置き換える
フラグパラメーターの削除
引数にフラグを使うのではなく、別の関数を使うべき
手順
- パラメーターの値に対応して明示的な関数を作成する
- パラメーターにリテラル値を指定いる呼び出し元を、対応する明示的な関数呼び出しに置き換える
オブジェクトそのものの受け渡し
ひとつのレコードから、数個の値を取り出して、関数に渡している場合、レコード自体を渡して関数本体で取り出すように変更する
手順
- 望ましいパラメーターをもったからの関数を作る
- 新しく作った関数の本体を、新しいパラメーターーを古いパラメーターに変換して、古い関数の呼び出しで埋める
- 静的テスト
- 新しい関数を使うように呼び出し元を調整
- 古い呼び出し元がすべて変更されたら、古い関数に関数のインライン化を適用
- 新しい関数と呼び出し元の名前を全て変更する
問い合わせによるパラメーターの置き換え
パラメーターに渡すまでもなく容易に求められる値を渡している場合、それは重複になるのでこのリファクタリングを行う
手順
- 必要に応じて、パラメーターを算出している箇所に関数の抽出を行う
- 関数本体でのパラメーターへの参照を、その値を取得する式への参照に置き換える
- 関数宣言の変更を適用して、パラメーターを取り除く
パラメーターによる問い合わせの置き換え
関数のスコープ内で好ましくない参照をしている時に行う
関数をある要素から非依存にして、パラメーター化する
手順
- 問い合わせを行なっている箇所に、変数の抽出を適用して、関数本体の残り部分から分離する
- 問い合わせ以外の関数本体のコードに関数抽出を適用する
- 変数のインライン化を適用して、作成した変数を取り除く
- 元の関数に関数のインライン化を行う
- 新しい関数の名前を元の関数の名前に変える
setterの削除
オブジェクトを生成した後でフィールドを変更したくないなら、setterは不要
不要なsetterを用意してしまう典型的なケースは二つ
- フィールドを操作する時に、コンストラクタの内部も含めて常にアクセサを使用している
- この場合、setterは取り除く
- クライアントが生成スクリプトを使って、オブジェクトを生成している
- 初期の生成期間中に呼び出されるだけなので、setterは取り除く
手順
- 設定したい値がコンストラクタに渡されない場合は、関数宣言の変更を適用してパラメーターを追加する
- コンストラクタ内にsetter呼び出しを追加する
- コンストラクタ以外での、setterの呼び出しを一つ取り除いて、新しいコンストラクタを呼び出すようにする
- setterに対して、関数のインライン化をする
- 可能なら、フィールドを変更不可にする
- テスト
ファクトリ関数によるコンストラクタの置き換え
コンストラクタには通常の関数にない、制約がある
ファクトリ関数を使うことで、コンストラクトの制約から解放される
手順
- ファクトリ関数を作成する
- その関数の本体でコンストラクタを呼び出す
- 既存のコンストラクタの呼び出しを一つずつファクトリ関数の呼び出しに置き換える
- テスト
- コンストラクタの可視性をできるだけ制限する
コマンドによる関数の置き換え
関数自身をオブジェクトとして、カプセル化することが有用な場合がある
→ コマンドオブジェクト もしくは 単にコマンド
手順
- 関数のための空クラスを作り、関数に因んだ名前をつける
- 関数の移動を適用して、関数を空クラスに移動する
- 引数ごとに対応するフィールドを作って、パラメーターをコンストラクタに移動することを検討する
関数によるコマンドの置き換え
コマンドオブジェクトは複雑な計算を扱うための強力なメカニズムを提供してくれる
しかし、コマンドオブジェクトの関数がそれほど複雑でもないなら、コマンドオブジェクトにしてもあまり意味がない
手順
- コマンドの生成とその実行メソッドの呼び出しに対して、関数の抽出を適用する
- コマンドの実行メソッドから呼び出されるメソッドに対して、それぞれ関数のインライン化を行う
- 関数宣言の変更をして、コンストラクタの全てのパラメーターをコマンドの実行メソッドのパラメーターに加える
- フィールドごとに、コマンドの実行メソッド内での参照の代わりにパラメーターを使うように変更する
- コンストラクタの呼び出しとコマンドの実行メソッドの呼び出しを、呼び出し元にインライン化する
- テスト
- デッドコードの削除をコマンドクラスに適用する
## 感想
問い合わせと更新の分離は結構Rubyだとやらないことが多め?
言語仕様からして必ず戻り値があるから相性が悪いとか