함수 추출하기
- 프로그램이 새로운 기능을 추가하기에 편한 구조가 아니라면, 먼저 기능을 추가하기 쉬운 형태로 리팩터링하고 나서 원하는 기능을 추가하자.
- 한번에 너무 많이 수정하려다 실수를 저지르면 디버깅하기 어려워 결과적으로 작업 시간이 늘어난다.
- 따라서 리팩터링은 프로그램 수정을 작은 단게로 나눠 진행해야 한다.
- 코드 조각을 함수로 추출할 때 스코프를 벗어나는 변수가 있는지 확인해야 한다.
- 저자는 함수의 반환 값에는 항상
result
라는 이름을 쓴다고 한다.
임시 변수를 질의 함수로 바꾸기, 변수 인라인하기
function playFor(aPerformance) {
return plays[aPerformance.playID];
}
function statement(invoice, plays) {
...
for(let perf of invoice.performance) {
// AS-IS: const play = playFor(perf);
// TO-DO: 불필요한 변수를 제거하고 아래처럼 사용
if ('comedy' === playFor(perf).type) {...}
}
}
- 지역 변수를 제거해서 얻는 가장 큰 장점은 추출 작업이 훨씬 쉬워진다는 것이다.
- 스코프를 신경 써야 할 대상이 줄어들기 때문이다.
반복문 쪼개기
function statement(invoice, plays) {
let totalAmount = 0;
let volumeCredits = 0;
let result = `청구 내역 (고객명: ${invoice.customer}`;
for (let perf of invoice.performances) {
result += ~;
totalAmount += ~;
}
for (let perf of invoice.performances) {
volumeCredits += volumeCreditsFor(perf);
}
...
}
반복문을 파이프라인으로 바꾸기
function totalAmount(data) {
return data.performances.reduce((total, p) => total + p.amount, 0);
}
function totalVolumeCredits(data) {
return data.performances.reduce((total, p) => total + p.volumeCredits, 0);
}
조건부 로직을 다형성으로 바꾸기
function createPerformanceCaculator(aPerforamnce, aPlay) {
switch (aPlay.type) {
case 'tragedy': return new TragedyCaculator(aPerforamnce, aPlay);
case 'comedy': return new ComedyCaculator(aPerforamnce, aPlay);
default: throw new Error(`알 수 없는 장르: ${aPlay.type}`);
}
}
// ...(중략)...
class PerformanceCaculator {
constructor(aPerformance, aPlay) {
this.performance = aPerformance;
this.play = aPlay;
}
get amount() {
throw new Error('서브클래스에서 처리하도록 설계되었습니다.');
}
get volumeCredits() {
return Math.max(this.performance.audience - 30, 0);
}
}
class TragedyCaculator extends PerformanceCaculator {...}
class ComedyCaculator extends PerformanceCaculator {...}
- 이제 새로운 장르를 추가하려면 해당 장르의 서브클래스를 만들어 생성함수인
createPerformanceCaculator()
에 추가하면 된다.
- amount와 volumeCredits 계산하는 조건부 로직을 생성함수 쪽으로 옮겼는데, 같은 타입의 다형성을 기반으로 실행되는 함수가 많을수록 이렇게 구성하는 편이 유리하다.
마무리
- 리팩터링은 대부분 코드가 하는 일을 파악하는 데서 시작한다.
- 좋은 코드를 가늠하는 확실한 방법은
얼마나 수정하기 쉬운가
다.
- 단계를 잘게 나눠야 더 빠르게 처리할 수 있고, 이러한 작은 단계가 모여 상당히 큰 변화를 이룰 수 있다는 사실을 꺠닫는 것이 리팩터링을 효과적으로 하는 핵심이다.