* 마틴 파울러님의 Refactoring, Chapter 별로 내용을 다룹니다. Chapter1 리팩터링: 첫 번째 예시 의 관한 글입니다.
* Refactoring (1)에서 다루지 못한 내용을 계속해서 다룹니다. Refactoring (1) 의 내용이 궁금하시다면 여기를 클릭해주세요.
* 관련 소스는github.com/SangchoKim/refactoring/tree/refactoringSecond에 있습니다.
다시 statement() 함수를 살펴봅시다. 앞서 말했던 것처럼 임시변수는 자신이 속한 루틴에서만 의미가 있어 루틴이 길어지면 코드의 명료함을 쉽게 잃을 수가 있습니다. 그렇기에 다음 리팩터링을 할 요소는 format 임시변수입니다. 이런 변수는 함수를 선언하여 사용하도록 바꾸는 것이 가장 깔끔합니다.
(1) format 변수 제거
1. format 변수 > use() 함수
2. statement() 함수 내 청구 내역 출력
usd() 함수에서는 달러로 변환을 하기 위해 나눗셈까지 처리하여 return을 합니다.
본래는 statement() 함수에서 format 변수를 이용하여 청구 내역을 만들었습니다. 하지만 format 기능을 use() 새로운 함수로 축출하였기 때문에 청구 내역을 출력하는 곳에서 호출을 해줍니다.
(2) volumCredits 변수 제거
두 번째 임시변수는 volumCredits입니다. 반목문을 한 바퀴 돌 때마다 값을 누적하는 하는 변수입니다. 그렇기에 리팩터링이 조금 까다롭습니다. 순서는 다음과 같습니다.
1. 반복문 쪼개기
2. 문장 슬라이드하기
3. 임시변수를 질의 함수로 바꾸기 (새로운 함수로 추출하기)
4. 변수 인라인하기
반복문 쪼개기에서는 말 그대로 반복문 안에 있던 값 누적 로직을 바깥으로 빼 또 다른 반복문으로 만들었습니다.
문장 슬라이드에서는 가장 위에 있던 임시변수를 새롭게 나눈 반복문 앞으로 이동시켰습니다.
그리고 난 뒤 임시변수를 질의함수로 바꿔 기능을 분리 시켰습니다.
마지막으로 임시변수로 있던 volumCredist 를 지우고 totalVoulumeCredist() 함수로 인라인하였습니다.
이렇게 총 4가지의 순서의 리팩터링을 거쳐 만들어진 코드는 전보다 깔끔한 구조를 지니게 되었습니다.
다시한번 정리해보면 4가지의 역할은 다음과 같습니다.
1. "반복문 쪼개기" 로 변수 값을 누적시키는 부분을 분리합니다.
2. "문장 슬라이드하기" 로 변수 초기화 문장을 변수 값 누적 코드 바로 앞으로 옮깁니다.
3. "함수 추출하기" 로 적립 포인트 계산 부분을 별도 함수로 추출합니다.
4. "변수 인라인하기" 로 volumCredits 변수를 제거합니다.
(3) totalAmount 변수 제거
totalAmount 변수도 volumCredist 변수와 마찬가지로 제거합니다. 반복문을 쪼개로, 변수 초기화 문장을 옮긴 다음, 함수를 추출하고, 변수 인라인을 합니다.
#5 중간 점검: 난무하는 중첩 함수
지금까지 리팩터링한 결과를 살펴보면 다음과 같습니다.
import playData from "./plays";
import invoiceData from "./invoices";
const statement = (invoice, plays) => {
let result = `청구 내역 (고객명: ${invoice.customer})\n`;
// format 함수
const usd = (aNumber) => {
return new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
minimumFractionDigits: 2,
}).format(aNumber / 100); // 단위 변환 로직 안으로 이동
};
// 연극 데이터 추출 함수
const playFor = (aPerformance) => {
return plays[aPerformance.playID];
};
// 각각의 연극 공연료 계산 함수
const amountFor = (aPerformance) => {
let result = 0;
switch (playFor(aPerformance).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);
}
break;
default:
throw new Error(`알 수 없는 장르: ${playFor(aPerformance).type}`);
}
return result;
};
// 포인트 적립 함수
const volumeCreditsFor = (aPerformance) => {
let result = 0;
// 포인트 적립
result += Math.max(aPerformance.audience - 30, 0);
// 희극 관객 5명마다 추가 포인트 제공
if ("comedy" === playFor(aPerformance).type) {
result += Math.floor(aPerformance.audience / 5);
}
return result;
};
// 값 계산 로직 함수
const totalVolumeCredist = () => {
let result = 0;
for (const perf of invoice.performances) {
result += volumeCreditsFor(perf);
}
return result;
};
// 토탈 값 계산 로직 함수
const totalAmount = () => {
let result = 0;
for (const perf of invoice.performances) {
result += amountFor(perf);
}
return result;
};
for (const perf of invoice.performances) {
// 청구 내역 출력
result += ` ${playFor(perf).name}: ${usd(amountFor(perf))} (${
perf.audience
}석)\n`;
}
result += `총액: ${usd(totalAmount())}\n`;
result += `적립 포인트: ${totalVolumeCredist()}점\n`; // 변수 인라인
return result;
};
console.log(statement(invoiceData, playData));
이번 글에서 진행한 리팩터링은 다음과 같습니다.
1. format 변수 제거하기
2. volumeCredits 변수 제거하기
3. 계산 단계와 포맷팅(html로 표현) 분리하기
4. 다형성을 활용해 계산 코드 재구성하기
다음 글에서는 3번째 계산 단계와 포맷팅 (html로 표현) 분리하기 부분을 진행해보겠습니다.
< 참고자료 >
[책] Refactoring - 마틴 파울러 지음
www.yes24.com/Product/Goods/89649360
<기타> Refactoring (2) end
'책' 카테고리의 다른 글
Refactoring (6) (0) | 2020.12.30 |
---|---|
Refactoring (5) (0) | 2020.12.19 |
Refactoring (4) (0) | 2020.12.15 |
Refactoring (3) (0) | 2020.12.12 |
Refactoring (1) (0) | 2020.12.08 |