リファクタリングについて学ぶ
PyLadies Tokyo Advent Calendarの5日目です。
先日のPyLadies Tokyo 秋合宿で取り組んだMartin Fowler著の"Refactoring"の第1章は良かったよ、というゆるい投稿です。
なお、秋合宿の模様はsugitaさんのこちらの記事をどうぞ。
第1章では、ツッコミどころ満載のサンプルコードを少しずつ書き換えていくことを通じて、Refactoringのノウハウを体験する構成になっています。
export {statement};
function statement(invoice, plays) {
let totalAmount = 0;
let volumeCredits = 0;
let result = `Statement for ${invoice.customer}\n`
const format = new Intl.NumberFormat("en-US",{
style: "currency",
currency: "USD",
minimumFractionDigits: 2
}).format;
for (let pref of invoice.performances) {
const play = plays[pref.playID];
let thisAmount = 0;
switch (play.type) {
case "tragedy":
thisAmount = 40000;
if (pref.audience > 30) {
thisAmount += 1000 * (pref.audience - 30);
}
break;
case "comedy":
thisAmount = 30000;
if (pref.audience > 20) {
thisAmount += 10000 + 500 * (pref.audience - 20);
}
thisAmount += 300 * pref.audience;
break;
default:
throw new Error(`unknown type: ${play.type}`);
}
// add volume credits
volumeCredits += Math.max(pref.audience - 30, 0);
console.log(thisAmount);
// add extra credit for every ten comedy attendees
if ("comedy" === play.type) {
volumeCredits += Math.floor(pref.audience / 5);
}
// print line for this order
result += ` ${play.name}: ${format(thisAmount/100)} (${pref.audience} seats)\n`;
totalAmount += thisAmount;
}
result += `Amount owed is ${format(totalAmount/100)}\n`;
result += `You earned ${volumeCredits} credits\n`;
return result;
}
このコードを下記のステップを踏んで段階的に書き換えていくアプローチを取っています。最初から大幅に書き換えないという方向のようですね。
0. テストを実行できるようにする
1. 大きすぎる処理を意味がある単位で分割する
2. 名前をわかりやすくする
3. 一時的な変数を定義するのではなく、都度計算で求めるようにする
4. 計算と表示に関する処理を分ける
5. classを利用する
なお、3は計算コストより可読性を優先するならという前提での書き換えになっています。一時的な変数は名前が微妙になりがちで、それを回避することが目的のようです。
書き換え後は大幅にコード量が増えますが、コードの可読性と拡張性、テスタビリティが改善することを感じられます。
---
リファクタリングの対象次第で取るべきアプローチが異なるのは確かですが、この本を読むことで引き出しを増やすことができそうです。第2章以降も読みたいです。
この記事が気に入ったらサポートをしてみませんか?