리팩터링(2판)
해당 포스팅은 서적을 읽고 생각의 변화를 가져온 부분이나, 공감하는 부분을 일부 발췌해 저의 생각과 함께 정리한 내용입니다.
역량이 쌓여감에 따라 와닿지 않았던 부분도 다르게 다가올 수 있기때문에 책을 읽을때마다 포스팅을 수정할 예정입니다.
리팩터링 원칙
1. 3의 법칙
책에서는 저자가 지인에게 제안받은 3의 법칙을 소개하는데 내용을 아래와 같다.
- 처음에는 그냥한다.
- 비슷한 일을 두번째로 하게되면, 일단 계속 진행한다.
- 비슷한 일을 세번째 하게 되면 리팩터링 한다.
- 야구를 좋아하는 사람은 ‘스트라이크 세번이면 리팩터링하라(삼진 리팩터링)’로 기억하자.
나는 주로 비슷한 일을 두번째로 하게되면, 함수를 따로 빼는 작업을 하는 편이다.
중복되는 코드는 단 한개라도 허용하지 않겠다는 생각에서 비롯된 행동이지 않을까 스스로 생각한다.
나도 내가 왜이러는지 모르겠다.
그러다 보니 만들어 놓은 코드를 수정하는 일이 빈번하게 일어나게 되는데, 실제로 완전히 동일한 기능을 요구하는 함수(A)는 2번 이상 좀처럼 나오지 않고.
유사한 기능을 요구하는 함수(B)가 필요하게되면 함수(A)를 만들어 놓은것이 아깝다고 생각을 하게되서 수정해서 사용을 해왔다.

유사한 기능이라고 해서 함수(A)를 수정하는 것보다, 따로 함수(B)를 만드는게 코드의 관리적인 측면에서 더 좋은 방법이지 않을까 생각이 든다.
2. 리팩터링과 성능
리팩터링이라고 함은 코드의 정리와 성능 두마리의 토끼를 동시에 잡는 작업이라고 생각을 했었지만, 저자는 두개의 작업을 각각 다른 관점으로 본다고 한다.
성능에 대한 흥미로운 사실은, 대부분 프로그램은 전체 코드 중 극히 일부에서 대부분의 시간을 소비한다는 것이고, 그래서 코드 전체를 고르게 최적화한다면 그 중 90%는 효과가 거의 없기때문에 시간 낭비가 된다.
리팩터링을 하면 소프트웨어가 느려질 수도 있는건 사실이지만, 그와 동시에 성능을 튜닝하기는 더 쉬워진다.
즉, 의도적으로 성능 최적화에 돌입하기 전까지는 성능에 신경 쓰지 않고 코드를 다루기 쉽게 만드는데 집중하는것이 좋다.
나는 다루기 쉬운코드와 좋은성능을 내는 코드 두가지를 분리하지 못하고 한가지로 생각해왔다.
그러다 보니 처음부터 다루기쉬우면서도 좋은성능을 내는 코드를 작성하려고 했고, 결과적으로는 애매한 코드를 작성해오지 않았나 반성을 하게된다.
기본적인 리팩터링
1. 함수 추출
목적과 구현을 분리하는 방식이 가장 합리적인 기준
ex) 텍스트의 색을 반전시키는 기능을 구현한다면,
코드의 목적 = 강조 heighlight(), 코드의 구현 = 반전 reverse()
나는 주로 지역변수의 값을 변경하는식의 코딩을 자주한다.
function buyItem(itmes) {
let totalPrice = 0;
for(const item of itmes) {
totalPrice += item.price;
}
}
그러다 보니 한참 작업을 할때는 눈치채지 못하지만, 나중에 그 코드를 보게 되면 무엇때문에 연산을 돌리고 값을 재할당했는지 심심치 않게 고민하게 된다.
그때마다 이걸 어떡하지? 라고 생각은 하지만 어떠한 조치도 취하지않고 넘겨왔다.
function buyItem(itmes) {
let totalPrice = getCalculateTotalPrice(itmes);
}
function getCalculateTotalPrice(itmes) {
let result = 0;
for(const item of itmes) {
result += item.price;
}
return result;
}
상단의 설명처럼 목적과 구현을 분리한다는게 어떤것인지 이해가되니 참 합리적이라고 생각이 들었다(코드는 이해를 돕기위해 직접 작성한 예시코드다).
우리의 목적(buyItem())은 상품을 구매하는것이다.
그러기 위해서 전체가격을 얻기위한 구현(getCalculateTotalPrice())을 분리하니 이름을 통해서 무슨 기능을 하는지 파악하기 간편해졌다.
2. 단계 쪼개기
작업을 하다보면 설계의 miss라던지, 로직상의 문제로 인해 복잡한 연산을 겪어야할 때가 있다.
function calculation() {
const totalPrice = amount * price;
const stock = stock - amount;
const expectedPrice = stock * price;
return expectedPrice;
}
위의 예제는 정말 간단하지만 각 단계가 복잡해진다면 그것만큼 골치아픈 일이 없을것이다.
나는 시간계산, 한개의 객체의 두개의 속성을 처리하는 mapper를 작성할때 고생을 좀 했었던 기억이 난다. 한눈에 보기에 너무 어지럽고, 그 부분에 유지보수 요청이 들어오면 한숨부터 내쉬곤 했다.
function calculation() {
const totalPrice = getTotalPrice(amount, price);
const stock = getStock(stock, amount);
const expectedPrice = getExpectPrice(stock, price);
return expectedPrice;
}
function getTotalPrice(amount, price) {
const reulst = amount * price;
return result;
}
function getStock(stock, amount) {
const result = stock - amount;
return result;
}
function getExpectPrice(stock, price) {
const result = stock * price;
return result;
}
그래서 어느날 날을 잡고 각 계산을 단계별로 쪼개서 재작업을 해주니 코드가 한눈에 들어오기도 하고, 복잡한 코드가 눈앞에서 사라져 두 대상을 동시에 생각할 필요 없이 하나에만 집중할 수 있었다. 눈앞의 코드가 정리되는것만으로도 생각이 정리가 되니 신기한 경험이었다.
조건부 로직 간소화
1. 조건문 분해하기
조건문의 조건이 복잡해지면 복잡해질수록 코드가 한눈에 들어오지 않는건 누구나 알고 있는 사실이다.
한참 코드를 작성할때면
이것도 필요하고 이것도 필요해서 이렇게 조건이 필요하지…
하면서 나름의 조건을 추가해서 코드를 작성하고는 한다.
function example(today) {
if(today.isTired && today.isVeryBusy && today.isNoBreakTime) {
earlySleep();
} else {
study();
}
}
하지만 시간이 지나감에 따라서 저 조건을 세운 이유를 단번에 떠올리기 어려워진다. 당장 3일만 지나도 그 코드는 더 이상 내 코드가 아닌것만 같다(주륵…)
무엇을 하는가를 말하는 코드보다는 왜하는지를 말해주는 코드로 바꿔주는게 효과적인 작업이다.
지금 상황에 가장 잘들어맞는 이야기가 아닐까 생각이든다. 여러 조건을 들어서 하나의 조건문을 작성하는건 어렵지 않지만 나중에 그 코드를 보았을때 각 조건들이 무엇을 의미하는지 파악하기는 훨씬 어렵기 때문인것 같다.
function example(today) {
if(myConditionCheck(today)) {
earlySleep();
} else {
study();
}
}
function myConditionCheck(today) {
return today.isTired && today.isVeryBusy && today.isNoBreakTime;
}
오늘이 힘들었나?, 바빴나?, 쉬는시간이 없었나?와 같이 무엇을 했는가에 대한 체크보다는,
나의 컨디션이 어떤가? 라는 왜? 형식으로 코드를 전환하니 조건의 의도가 확실히 눈에 보이는걸 알 수 있다.

1회독 후기 2021.01.20
나는 리팩토링을 해본적이 없다. 그럼에도 이책을 읽게된 이유는 2가지다.
먼저 리팩토링을 해서 개선될 코드를 처음부터 작성하면 되지 않을까? 라는 생각이었다. 나중에 다시 손댈바엔 처음부터 손대는게 낫지않을까 했다.
두번째는 내 코딩스타일에 대한 고민이었다.
코드를 작성하고 돌아가게하는것에는 문제가 없지만(?) 과연 이렇게 작성하는게 좋은방법일까 하는 생각이 매순간 들었기 때문에, 좋은 코드란 무엇인가를 접해보고 싶은 마음이 컷다.
책을 읽어보니 다른사람이 코드를 정리하는 규칙같은 방법들을 알 수 있어서 좋았고, 코드를 작성할때 베이스로 깔려야 하는 생각들을 알 수 있어서 좋았다.
목적과 구현을 분리하는 방식이 가장 합리적인 기준
무엇을 하는가를 말하는 코드보다는 왜하는지를 말해주는 코드로 바꿔주는게 효과적인 작업이다.
이런 생각들은 스스로 생각하고 깨닫기 어려운 문제라고 생각하기 때문에 좋은영향을 받았다고 생각한다.
또 간간히 책의 내용을 프로젝트에 적용할때면
이건 이래서 이런식으로 하는걸 추천한다고 했었지…
스스로 되뇌일 때마다 정말 기분이 좋았다. 하하

그에 반해서 아쉬운점은 방대한 책의 내용중에서 내가 이해하고 공감할 수 있는 내용들이 많지 않았다는 점이다.
아무래도 코딩경험이 많지 않아서가 아닐까 생각이드는데, 코딩이라는건 지식적으로 암기하고 하는게 아니라 경험을 바탕으로 쌓여가는 기술이라고 생각하기 때문에
당장 이해가 가지 않는 부분에 있어서는 미련을 버리고 다음 책을 읽을때를 기약하기로 했다. 그동안에 경험이 축적되서 다음번엔 더욱 알차게 책을 읽을 수 있었으면 좋겠다.
Leave a comment