리팩터링 2판 - 마틴 파울러에서 인상깊은 부분을 발췌했습니다.

리팩토링과 성능 측정

1장, p47

여기서 잠시 멈추고 방금 한 일에 대해 생각해보자. 무엇보다도 반복문을 쪼개서 성능이 느려지지 않을까 걱정할 수 있다. 이처럼 반복문이 중복되는 것을 꺼리는 이들이 많지만, 이 정도 중복은 성능에 미치는 영향이 미미할 때가 많다. 실제로 이번 리팩토링 전과 후의 실행 시간을 측정해보면 차이를 거의 느끼지 못할 것이다. 경험 많은 프로그래머조차 코드의 실제 성능을 정확히 예측하지 못한다. 똑똑한 컴파일러들은 최신 캐싱 기법 등으로 무장하고 있어서 우리의 직관을 초월하는 결과를 내어주기 때문이다. 또한 소프트웨어 성능은 대체로 코드의 몇몇 작은 부분에 의해 결정되므로 그 외의 부분은 수정한다고 해도 성능 차이를 체감할 수 없다.

하지만 ‘대체로 그렇다’와 ‘항상 그렇다’는 엄연히 다르다. 때로는 리팩터링이 성능에 상당한 영향을 주기도 한다. 그런 경우라도 나는 개의치 않고 리팩터링한다. 잘 다듬어진 코드라야 성능 개선 작업도 훨씬 수월하기 때문이다. 리팩터링 과정에서 성능이 크게 떨어졌다면 리팩터링 후 시간을 내어 성능을 개선한다. 이 과정에서 리팩터링된 코드를 예전으로 되돌리는 경우도 있지만, 대체로 리팩터링 덕분에 성능 개선을 더 효과적으로 수행할 수 있다. 결과적으로 더 깔끔하면서 더 빠른 코드를 얻게 된다.

따라서 리팩터링으로 인한 성능 문제에 대한 내 조언은 ‘특별한 경우가 아니라면 일단 무시하라’는 것이다. 리팩터링 때문에 성능이 떨어진다면, 하던 리팩터링을 마무리하고 나서 성능을 개선하자.

리팩토링과 개발 속도

2장, 83p

한 시스템을 오래 개발 중인 개발자들과 얘기하다 보면 초기에는 진척이 빨랐지만 현재는 새 기능을 하나 추가하는 데 훨씬 오래 걸린다는 말을 많이 한다. 새로운 기능을 추가할수록 기존 코드베이스에 잘 녹여낼 방법을 찾는 데 드는 시간이 늘어난다는 것이다. 게다가 기능을 추가하고 나면 버그가 발생하는 일이 잦고, 이를 해결하는 시간은 한층 더 걸린다. 코드베이스는 패치에 패치가 덧붙여지면서 프로그램의 동작을 파악하기가 거의 고대 유적 발굴만큼 어려워진다. 이러한 부담이 기능 추가 속도를 계속 떨어뜨리면서, 차라리 처음부터 새로 개발하는 편이 낫겠다고 생각하는 지경에 이른다.

언제 리팩토링해야 할까?

2장, 85p

3의 법칙

이건 돈 로버츠가 내게 제시한 가이드다.

  1. 처음에는 그냥 한다.
  2. 비슷한 일을 두 번째로 하게 되면(중복이 생겼다는 사실에 당황스럽겠지만), 일단 계속 진행한다.
  3. 비슷한 일을 세 번째 하게 되면 리팩터링한다.

야구를 좋아하는 사람은 ‘스트라이크 세 번이면 리팩터링하라(삼진 리팩터링)’로 기억하자.

리팩토링하는 이유

2장, 93p

하지만 내가 볼 때 사람들이 빠지기 쉬운 가장 위험한 오류는 리팩터링을 ‘클린 코드’나 ‘바람직한 엔지니어링 습관’처럼 도덕적인 이유로 정당화하는 것이다. 리팩터링의 본질은 코드 베이스를 예쁘게 꾸미는 데 있지 않다. 오로지 경제적인 이유로 하는 것이다. 리팩터링은 개발 기간을 단축하고자 하는 것이다. 기능 추가 시간을 줄이고, 버그 수정 시간을 줄여준다. 스스로 그렇게 인식하는 데 그치지 말고 다른 사람과 대화할 때도 이 점을 명심해야 한다. 리팩터링하도록 이끄는 동력은 어디까지나 경제적인 효과에 있다. 이를 명확히 이해하는 개발자, 관리자, 고객이 많아질수록 앞에서 본 소프트웨어 개발 진행 그래프에서 ‘좋은 설계’ 곡선을 더 많이 볼 수 있다.

YAGNI

  • YAGNI: You Aren’t Gonna Need It

2장, 100-101p

한 가지 방법은 향후 변경에 유연하게 대처할 수 있는 유연성 메커니즘을 소프트웨어에 심어두는 것이다. 가령 함수를 정의하다 보면 범용적으로 사용할 수 있겠다는 생각이 들 때가 있다. 그래서 다양한 예상 시나리오에 대응하기 위한 매개변수들을 추가한다. 이런 매개변수가 바로 유연성 메커니즘이다. 물론 메커니즘들이 대개 그렇듯 치러야 할 비용이 있다. 매개변수를 생각나는 대로 추가하다 보면 당장의 쓰임에 비해 함수가 너무 복잡해진다. 또한 깜박 잊은 매개변수가 있다면 앞서 추가해둔 매개변수들 때문에 새로 추가하기가 더 어려워진다. 간혹 유연성 메커니즘을 잘못 구현할 때도 있다. 요구사항이 당초 예상과 다르게 바뀌기 때문일 때도 있고, 내가 설계한 매커니즘 자체에 결함이 있어서일 때도 있다. 이 모든 상황을 고려하다 보면 유연성 매커니즘이 오히려 변화에 대응하는 능력을 떨어뜨릴 때가 대부분이다.

잘못된 상속 패턴

3장, 130-131p

서브클래스는 부모로부터 메서드와 데이터를 물려받는다. 하지만 부모의 유산을 원치 않거나 필요 없다면 어떻게 해야 할까? 수많은 유산 중에서 관심 있는 몇 개만 받고 끝내려는 경우는 얼마든지 있을 수 있다.

(중략)

상속 포기 냄새는 서브클래스가 부모의 동작은 필요로 하지만 인터페이스는 따르고 싶지 않을 때 특히 심하게 난다. 구현을 따르지 않는 것은 이해할 수 있지만 인터페이스를 따르지 않는다는 것은 상당히 무례한 태도다. 이럴 때는 서브클래스를 위임으로 바꾸기나 슈퍼클래스를 위임으로 바꾸기를 활용해서 아예 상속 메커니즘에서 벗어나보자.

테스트의 완벽함을 추구할 필요가 없다

4장, 143p

(중략) 명심하자! 테스트는 위험 요인을 중심으로 작성해야 한다! 테스트의 목적은 어디까지나 현재 혹은 향후에 발생하는 버그를 찾는 데 있다. 따라서 단순히 필드를 읽고 쓰기만 하는 접근자는 테스트할 필요가 없다. 이런 코드는 너무 단순해서 버그가 숨어들 가능성도 별로 없다.

테스트를 너무 많이 만들다 보면 오히려 필요한 테스트를 놓치기 쉽기 때문에 아주 중요한 포인트다. 나는 적은 수의 테스트만으로 큰 효과를 얻고 있다. 잘못될까봐 가장 걱정되는 영역을 집중적으로 테스트하는데, 이렇게 해서 테스트에 쏟는 노력의 효과를 극대화하는 것이다.

테스트 코드를 집안일처럼 느끼지 말자

4장, 148p

자, 내가 스스로 작성한 코드를 적으로 돌리고 있음이 느껴지는가? 나는 의식적으로 프로그램을 망가뜨리는 방법을 모색하는데, 이런 마음 자세가 생산성과 재미를 끌어올려준다. 내 마음 속에 잠재하는 사악한 욕구를 충족시켜주기 때문인 것 같다.