리팩터링 2판 스터디: 1장 '리팩터링: 첫 번째 예시'
이 글은 리팩터링 2판 스터디 시리즈 중 하나입니다.
회사에서 마틴 파울러의 #리팩터링 2판을 읽으며 함께 스터디를 진행하게 되었습니다. 한 챕터를 공부할 때마다 간단한 요약을 블로그에 올리기로 했어요.
요약
- 기능을 추가하기 전에 먼저 그렇게 하기 쉬운 형태로 리팩터링하자.
- 리팩터링 과정은 최대한 작은 단계로 쪼개고, 테스트-컴파일-커밋의 원칙을 지키자.
- 지역 변수는 유효 범위(scope)를 신경써야 하기 때문에 기능 분리를 어렵게 한다.
- 덧: 경험상으로 (특히 뛰어난 IDE가 있는 요즘에는) 지역 변수가 그렇게까지 많은 영향을 주지 않는 것 같지만, 작은 변수 하나하나가 모여 도무지 이해할 수 없는 거대한 함수를 만들곤 하니 새겨들어야겠어요.
- 코드를 읽기만 해도 무슨 일을 하는지 알 수 있도록 이름을 정성들여 짓자.
- 리팩터링이 성능에 미치는 영향은 미미하니 일단 리팩터링을 하자.
- 덧: 특히 공감이 되는 부분입니다. 제가 작업하는 코드가 실행되는 환경은 대체로 성능이 넉넉한 PC나 요즘 스마트폰이기도 하고, 리팩터링으로는 알고리즘의 복잡도 자체가 변하지는 않으니까요.
- 간결한 코드보다 하는 일이 명료한 코드를 쓰자.
- 가변 데이터는 오류를 일으키기 쉽다.
- 덧: 데이터에는 잘못이 없지만, 우리는 잘못을 저지르죠. 가변 데이터를 다룰 때에는 실수하기 쉬우니 웬만하면 불변 데이터를 사용해 봅시다.
- 조건부 로직이 복잡해지기 전에 객체 다형성 등을 사용하여 읽기 쉽게 만들자.
- 덧: 저는 자바스크립트의 클래스가 정말 적응하기 어렵더라고요. 책임 연쇄 패턴(chain-of-responsibility pattern) 등을 적극적으로 활용해 봅시다.
인용
1장은 코드 하나를 리팩터링하는 과정을 따라가는 형식으로 개괄적 내용을 다루고 있습니다. 여기에 나오는 개념들은 모두 이후 챕터에서 다시 등장하기 때문에 벌써부터 전부 머릿속에 넣으려고 노력할 필요까지는 없어보여요.
p.27
프로그램이 새로운 기능을 추가하기에 편한 구조가 아니라면, 먼저 기능을 추가하기 쉬운 형태로 리팩터링하고 나서 원하는 기능을 추가한다.
경험 많은 개발자로서 내가 장담하건대, 어떤 방식으로 정하든 반드시 6개월 안에 다시 변경하게 될 것이다. 새로운 요구사항은 수색 대원처럼 한두 명씩이 아니라, 한 부대씩 몰려오기 마련이다.
p.28
리팩터링하기 전에 제대로 된 테스트부터 마련한다. 테스트는 반드시 자가진단하도록 만든다.
p.32
리팩터링은 프로그램 수정을 작은 단계로 나눠 진행한다. 그래서 중간에 실수하더라도 버그를 쉽게 찾을 수 있다.
p.34
자바스크립트와 같은 동적 타입 언어를 사용할 때는 타입이 드러나게 작성하면 도움된다. 그래서 나는 매개변수 이름에 접두어로 타입 이름을 적는데, 지금처럼 매개변수의 역할이 뚜렷하지 않을 때는 부정 관사(a/an)를 붙인다.
(개인적으로는 그냥 JSDoc이나 타입스크립트를 사용하는 편이 좋은 것 같아요.)
p.39
지역 변수를 제거해서 얻는 가장 큰 장점은 추출 작업이 훨씬 쉬워진다는 것이다. 유효범위를 신경 써야 할 대상이 줄어들기 때문이다. 실제로 나는 추출 작업 전에는 거의 항상 지역 변수부터 제거한다.
p.44
이름짓기는 중요하면서도 쉽지 않은 작업이다. 긴 함수를 작게 쪼개는 리팩터링은 이름을 잘 지어야만 효과가 있다. 이름이 좋으면 함수 본문을 읽지 않고도 무슨 일을 하는지 알 수 있다. [...] 흔히 코드를 두 번 이상 읽고 나서야 가장 적합한 이름이 떠오르곤 한다.
p.47
반복문을 쪼개서 성능이 느려지지 않을까 걱정할 수 있다. 이처럼 반복문이 중복되는 것을 꺼리는 이들이 많지만, 이 정도 중복은 성능에 미치는 영향이 미미할 때가 많다. [...] 똑똑한 컴파일러들은 최신 캐싱 기법 등으로 무장하고 있어서 우리의 직관을 초월하는 결과를 내어주기 때문이다. 또한 소프트웨어 성능은 대체로 코드의 몇몇 작은 부분에 의해 결정되므로 그 외의 부분은 수정한다고 해도 성능 차이를 체감할 수 없다.
따라서 리팩터링으로 인한 성능 문제에 대한 내 조언은 '특별한 경우가 아니라면 일단 무시하라'는 것이다. 리팩터링 때문에 성능이 떨어진다면, 하던 리팩터링을 마무리하고 나서 성능을 개선하자.
p.55
복사를 한 이유는 함수로 건넨 데이터를 수정하기 싫어서다. 가변 데이터는 금방 상하기 때문에 나는 데이터를 최대한 불변처럼 취급한다.
p.63
모듈화하면 각 부분이 하는 일과 그 부분들이 맞물려 돌아가는 과정을 파악하기 쉬워진다. 간결함이 지혜의 정수일지 몰라도, 프로그래밍에서만큼은 명료함이 진화할 수 있는 소프트웨어의 정수다.
p.64
조건부 로직은 코드 수정 횟수가 늘어날수록 골칫거리로 전락하기 쉽다. 이를 방지하려면 프로그래밍 언어가 제공하는 구조적인 요소로 적절히 보완해야 한다. [...] 방법은 다양하지만, 여기서는 객체지향의 핵심 특성인 다형성을 활용하는 것이 자연스럽다.
p.73
일반적인 경우를 기본으로 삼아 슈퍼클래스에 남겨두고, 장르마다 달라지는 부분은 필요할 때 오버라이드하게 만드는 것이 좋다.
p.75
[...] 조건부 로직을 생성 함수 하나로 옮겼다. 같은 타입의 다형성을 기반으로 실행되는 함수가 많을수록 이렇게 구성하는 쪽이 유리하다.
p.77
리팩터링을 효과적으로 하는 핵심은, 단계를 잘계 나눠야 더 빠르게 처리할 수 있고, 코드는 절대 깨지지 않으며, 이러한 작은 단계들이 모여서 상당히 큰 변화를 이룰 수 있다는 사실을 깨닫는 것이다. 이 점을 명심하고 그대로 따라주기 바란다.
Dani Soohan Park (@heartade)
Follow this blog at Fediverse: @heartade@blog.heartade.dev
Follow my shorter shoutouts at Fediverse: @heartade@social.silicon.moe
Follow me at Bluesky: @heartade.dev