리팩토링 1장을 시작해본다.
function statement(invoice, plays) {
let totalAmount = 0;
let volumeCredits = 0;
let result = '청구 내역 (고객명: sfinvoice.customers) \n';
const format = new Intl.NumberFormat("en-Us", {
style: "currency",
currency: "USD",
minimumFractionDigits: 2
}).format;
for (let perf of invoice.performances) {
const play = plays[perf.playID];
let thisAmount = 0;
switch (play.type) {
case "tragedy": // 비극
thisAmount = 40000;
if (perf.audience > 30) {
thisAmount += 1000 * (perf.audience - 30);
}
break;
case "comedy": // 희극
thisAmount = 30000;
if (perf.audience > 20) {
thisAmount += 10000 + 500 * (perf.audience - 20);
}
thisAmount += 300 * perf.audience;
break;
default:
throw new Error('알 수 없는 장르: sfplay.typer');
}
//포인트를 적립한다.
volumeCredits += Math.max(perf audience - 30, 0);
//희극 관객 5명마다 추가 포인트를 제공한다.
if ("comedy" === play.type) volumeCredits += Math.floor(perf.audience / 5);
//청구 내역을 출력한다.
result += '${play.name}: ${format(thisAmount / 100)} (${perf.audience}석)\n';
totalAmount += thisAmount;
}
result += '총액: ${format (totalAmount/100)}\n';
result += '적립 포인트: ${volumeCredits)점 \n';
";
return result;
}
프로그램이 새로운 기능을 추가하기에 편한 구조가 아니라면, 먼저 기능을 추가하기 쉬운 상태로 리팩터링하고 나서 원하는 기능을 추가한다.
statement
함수를 보면, 결국 공연로 청구서를 만드는 작업이다.리팩터링하기 전에, 제대로 된 테스트부터 마련한다. 테스트는 반드시 자가진단하도록 만든다.
statement
함수를 리팩터링 해보자.switch
문을 보자.switch (play.type) {
case "tragedy": // 비극
thisAmount = 40000;
if (perf.audience > 30) {
thisAmount += 1000 * (perf.audience - 30);
}
break;
case "comedy": // 희극
thisAmount = 30000;
if (perf.audience > 20) {
thisAmount += 10000 + 500 * (perf.audience - 20);
}
thisAmount += 300 * perf.audience;
break;
default:
throw new Error('알 수 없는 장르: sfplay.typer');
}
function statement(invoice, plays) {
let totalAmount = 0;
let volumeCredits = 0;
let result = '청구 내역 (고객명: sfinvoice.customers) \n';
const format = new Intl.NumberFormat("en-Us", {
style: "currency",
currency: "USD",
minimumFractionDigits: 2
}).format;
for (let perf of invoice.performances) {
const play = plays[perf.playID];
let thisAmount = 0;
thisAmount = amountFor(perf, play);
//포인트를 적립한다.
volumeCredits += Math.max(perf audience - 30, 0);
//희극 관객 5명마다 추가 포인트를 제공한다.
if ("comedy" === play.type) volumeCredits += Math.floor(perf.audience / 5);
//청구 내역을 출력한다.
result += '${play.name}: ${format(thisAmount / 100)} (${perf.audience}석)\n';
totalAmount += thisAmount;
}
result += '총액: ${format (totalAmount/100)}\n';
result += '적립 포인트: ${volumeCredits)점 \n';
";
return result;
func amountFor(pert, play) {
let thisAmount = 0;
switch (play.type) {
case "tragedy": // 비극
thisAmount = 40000;
if (perf.audience > 30) {
thisAmount += 1000 * (perf.audience - 30);
}
break;
case "comedy": // 희극
thisAmount = 30000;
if (perf.audience > 20) {
thisAmount += 10000 + 500 * (perf.audience - 20);
}
thisAmount += 300 * perf.audience;
break;
default:
throw new Error('알 수 없는 장르: sfplay.typer');
}
return thisAmount;
}
}
리팩토링은 프로그램 수정을 작은 단계로 나눠 진행한다.
thisAmount
-> result
func amountFor(pert, play) {
let result = 0;
switch (play.type) {
case "tragedy": // 비극
result = 40000;
if (perf.audience > 30) {
result += 1000 * (perf.audience - 30);
}
break;
case "comedy": // 희극
result = 30000;
if (perf.audience > 20) {
result += 10000 + 500 * (perf.audience - 20);
}
result += 300 * perf.audience;
break;
default:
throw new Error('알 수 없는 장르: sfplay.typer');
}
return result;
}
aPerf
가 애매하니 이걸 aPerformance
로 바꾸자.func amountFor(aPerformance, play) {
let result = 0;
switch (play.type) {
case "tragedy": // 비극
result = 40000;
if (aPerformance.audience > 30) {
result += 1000 * (aPerformance.audience - 30);
}
break;
case "comedy": // 희극
result = 30000;
if (aPerformance.audience > 20) {
result += 10000 + 500 * (aPerformance.audience - 20);
}
result += 300 * aPerformance.audience;
break;
default:
throw new Error('알 수 없는 장르: sfplay.typer');
}
return result;
}
사람이 이해하도록 작성하는 프로그래머가 진정한 실력자다.