함수 옮기기
// before
class SomeClass {
get someFunc();
}
// after
class AnotherClass {
get someFunc();
}
- 이는 클래스 이름을 바꾼게 아니라 함수가 옮겨진 것이다.
- 함수는 대부분 어떤 클래스에 속하게 된다. (자바의 경우 필수다)
- 만약 어떤 함수가 자신이 속한 모듈 A보다 모듈 B의 요소를 더 참조한다면 모듈 B로 옮겨주는 것이다.
필드 옮기기
// before
class Customer {
get plan() {
return this.plan;
}
get discountRate() {
return this.discountRate;
}
}
// after
class Customer {
get plan() {
return this.plan;
}
get discountRate() {
return this.plan.discountRate;
}
}
- 위와 비슷하게, 함수에 어떤 레코드를 넘길 때마다 또 다른 레코드의 필드도 함께 넘기고 있다면 데이터 위치를 옮길 필요가 있다.
- 서로 다른 레코드, 객체의 필드임에도 같이 움직여진다면, 한 곳으로 필드를 옮겨주는 것이다.
문장을 함수로 옮기기
// before
print(info.title);
printDetail(info);
function printDetail(info) {
print(info.content);
print(info.writer);
}
// after
printDetail(info);
function printDetail(info) {
print(info.tilte);
print(info.content);
print(info.writer);
}
- 특정 함수를 호출하는 코드가 나올 때마다 앞 혹은 뒤에서 똑같은 코드가 추가로 실행될 때, 반복 부분을 함수와 합치는 방법이다.
문장을 호출한 곳으로 옮기기
// before
printDetail(info);
function printDetail(info) {
print(info.tilte);
print(info.content);
print(info.writer);
}
// after
print(info.title);
printDetail(info);
function printDetail(info) {
print(info.content);
print(info.writer);
}
- 위와 반대로, 원래는 합쳐져 있는게 좋지만 요구사항이 바뀌어 따로 처리해줘야 하는 경우가 생길 수 있다.
- 어느샌가 하나의 함수가 두가지 이상의 역할을 담당한다면, 달라진 동작 부분을 함수에서 꺼내 해당 호출자로 옮겨야 한다.
인라인 코드를 함수 호출로 바꾸기
// before
let appliesToMess = false;
for (const s of states) {
if (s === "MA") appliesToMess = true;
}
// after
appliesToMess = states.includes("MA");
- 이미 존재하는 함수와 똑같은 일을 하는 인라인 코드를 발견했을 때, 이를 함수 호출로 바꿔주는 것이다.
- 단, 정확히 일치하는지 확실히 알아야 한다. 이 때 중요한 것이 함수의 이름이다.
- 이름은 반드시 동작 방식이 아닌 목적을 명시해줘야 한다.
문장 슬라이드하기
// before
const div = a / b;
const add = a + b;
let sum;
const sub = a - b;
// after
const div = a / b;
const add = a + b;
const sub = a - b;
let sum;
- 관련 코드끼리 모으는 작업을 말한다.
- 이 때 참고할 점은 변수를 미리 선언하고 나중에 쓰는 방식 (C 언어 방식) 보다는 변수를 실제로 사용할 때 선언함과 동시에 초기화하는 것이 가장 좋다. (이펙티브 자바에서도 나온 얘기)
반복문 쪼개기
// before
let answer = 0;
let acc = 0;
for (const n of numbers) {
answer += n;
acc += n;
}
// after
let answer = 0;
for (const n of numbers) {
answer += n;
}
let acc = 0;
for (const n of numbers) {
acc += n;
}
- 함수 뿐만 아니라, 반복문에서도 두 가지 역할을 하는 것은 좋지 않다.
- 물론 이 방식으로는 반복문을 두번 돌게 되므로 성능이 약간 느려지긴 할 것이다.
- 하지만 리팩터링과 최적화는 다른 관점으로 봐야 할 것이고, 만약 정말 병목이라면 합치는 건 어렵지 않다.
- 또한 이렇게 분리해 놓은 뒤에 함수 추출하기, 파이프라이닝하기 등으로 더 좋은 리팩토링이 가능해지므로 좋다.
반복문을 파이프라인으로 바꾸기
// before
const names = [];
for (const i of input) {
if (i.job === "Programmer") {
names.push(i.name);
}
}
// after
const names = input
.filter(i => i.job === "Programmer")
.map(i => i.name)
;
- 반복문의 경우 해당 반복문이 무엇을 하는지 코드를 자세히 확인해야 한다.
- 이 때 파이프라인을 사용하면 각 논리 과정이 무엇을 의미하는지 한눈에 보인다.
- 반복문은 가능하면 파이프라인으로 바꾸자.
죽은 코드 제거하기
- 전혀 사용하지 않는 코드, 필요없는 코드들을 주석처리하지 말자.
- 대신 그냥 없애자.
- 그럼 나중에 필요하면 어떻게? → 버전 관리 툴이 있다. (Git)
https://product.kyobobook.co.kr/detail/S000001810241