どうも、いっとくです。
駆け出して少しだけ時が経った系のWebエンジニアです。
最近思うのですが、自販機って100円玉を認識失敗する確率高くないですか?
まぁそんなことは置いておいて、今回はリファクタリングの基礎であり比較的簡単な「メソッドの切り出し」についてのお話です!
小さなメソッドに切り出すメリット
処理を小さなメソッドに切り出すっていうのはすごく地味な作業ですが、めちゃくちゃ効果があるリファクタリング手法です。
そのメリットは2つ!
- 再利用可能になる!
- 処理の塊に命名できる!
それぞれ実例を交えて見ていきましょう!
コードはPHPです。
再利用可能になる
例えばこんな感じでフォームから送信されてきた値とクエリパラメータを受け取って、データベースに保存する処理があるとします。
public function storeData()
{
$input = $_POST;
$query = $_GET;
$merged = array_merge($input, $query);
unset($merged['token']);
unset($merged['page']);
saveToDataBase($merge);
}
saveToDataBaseというデータベースに保存するメソッドがどこか別のところに定義されていると仮定してください。
受け取った値をマージして保存しているのですが、いくつか保存する時に不要なデータがあるので、削除してからデータベースに保存しています。
また、別のメソッドでは以下のような更新処理が記述されています。
public function updateData()
{
$input = $_POST;
$query = $_GET;
$merged = array_merge($input, $query);
unset($merged['token']);
unset($merged['page']);
updateDataBase($merge);
}
処理の内容を見てみると、ほぼコピペですね。
コピペを感じたらリファクタの出番です!
このような共通処理があった時に、メソッドを切り出してみると再利用が可能になります。
public function storeData()
{
$sendData = $this->getSendData();
$removedData = $this->removeUnnecessaryValue($sendData);
saveToDataBase($removedData);
}
public function updateData()
{
$sendData = $this->getSendData();
$removedData = $this->removeUnnecessaryValue($sendData);
updateDataBase($removedData);
}
private function getSendData()
{
$input = $_POST;
$query = $_GET;
return array_merge($input, $query);
}
private function removeUnnecessaryValue($target)
{
unset($target['token']);
unset($target['page']);
return $target;
}
こんな感じで共通化が出来ました!
こうすると何が良いかと言うと、例えば不要なデータがtokenとpage以外に増えたときに変更する箇所が1箇所で良くなるわけです。
そうすると保守性が高くなりますね。
今回は切り出さなくても修正箇所の量は1箇所しか変わりませんが、例えば変更箇所がもっとたくさんあった時に探すのも時間がかかるし、仮に修正漏れがあったらそれはバグに繋がってしまいます。
そういったリスクを小さなメソッドで切り出すことで減らすことが出来ます。素晴らしぃ〜。
変更に対しての修正箇所は1箇所であるべきというのはプログラミングにおける美学でもあります。
一点気をつけたいのは、たまたま同じ処理になっているのか、必然的に同じ処理になっているのかを見極める必要があるということです。
たまたま処理が同じなだけだった場合、後々切り出した箇所に変更が必要になった際、片方の呼び出しでは変更が必要だけど、もう片方は必要ないという状況が生まれ、切り出したメソッドの中で条件分岐をしなくてはいけなくなります。
切り出したメソッドの中で条件分岐する必要性が出てきた場合は、分け方を変える合図であり、そこに無理やり条件分岐を追加するとスパゲッティコードに直滑降することになるので注意しましょう…!
ちなみに今回の場合、2つのメソッドに切り出しましたが、以下のような1つのメソッドにするという選択肢もあると思います。
private function getSendData()
{
$input = $_POST;
$query = $_GET;
$merged = array_merge($input, $query);
unset($merged['token']);
unset($merged['page']);
return $merged;
}
どれくらいの粒度で切り出すかについては、そのプロジェクトにもよりますが、今回のように取得と不要なデータの除去というそれぞれのメソッドに命名できるような目的がある場合は小さく分けたほうが良いような気はします。
処理の塊に命名できる!
これもソースコードの可読性を上げるにあたってめっちゃ大事です。
さっきのコードの新規作成のメソッドを切り分け前と切り分け後で比較してみましょう!
public function storeData()
{
$input = $_POST;
$query = $_GET;
$merged = array_merge($input, $query);
unset($merged['token']);
unset($merged['page']);
saveToDataBase($merge);
}
public function storeData()
{
$sendData = $this->getSendData();
$removedData = $this->removeUnnecessaryValue($sendData);
saveToDataBase($removedData);
}
まぁ、これくらい簡単なコードならそこまで読むのにかかる労力は変わらないのですが、切り分けていないコードだと、保存の処理を読むのにどこからどんなデータを取得していて、何の値がデータベースには不要なのかを読まないといけません。
一方細かく切り出して名前をつけた方は、送信したデータを受け取って、そこから不要なデータを削除してからDBに保存しているということがわかります。
その時に具体的にどんなデータを受け取って、何を削除しているかを知る必要がなくなるので、読む時にかかるコストがめちゃくちゃ減るんですね。
切り出したメソッドの行数が増えるほど、切り分けていないメソッドの読むコストが増えますが、切り出していれば全く増えません。知らなくて良いことをカプセル化出来ています。
以上、リファクタリングのテクニックの1つであるメソッドの切り出しについてでした!
もっとリファクタに興味がある人は、この本がすごく良いと思います!
内容は難しい部分も多いけど時間が立つほどに味が出てくる1冊だと思います。
コメント