목차6개 항목
출처와 참고
마틴 파울러의 『리팩터링』(2판) 1~2장을 읽으며 riverkim.kr에 남긴 메모를 다시 정리한 노트다. 책: 리팩토링. 「새로 입사한 개발자가 프로젝트에 기여하는 방법 한 가지」의 내용을 더해 보강했다.
리팩터링이란
리팩터링(refactoring)은 소프트웨어의 겉보기 동작은 그대로 둔 채, 코드를 이해하고 고치기 쉽도록 내부 구조를 바꾸는 일이다. 명사로는 그런 개별 기법(함수 추출, 변수 인라인 등)을, 동사로는 그 기법들을 연달아 적용해 코드를 재구성하는 행위를 가리킨다.
동작이 바뀌면 리팩터링이 아니다. 버그 수정이나 기능 추가와 섞지 않는다.
핵심 원칙
| 원칙 | 내용 |
|---|---|
| 기능을 넣기 쉬운 구조부터 | 새 기능을 넣기 불편한 구조라면, 먼저 넣기 쉬운 모양으로 리팩터링한 다음 기능을 추가한다 |
| 테스트가 먼저 | 리팩터링 전에 믿을 수 있는 테스트를 준비한다. 테스트는 결과를 스스로 판정(자가 진단)해야 한다 |
| 작게 바꾸고 매번 확인 | 아무리 작은 수정이라도 바꾼 뒤에는 테스트한다. "컴파일 → 테스트 → 커밋"을 작은 단위로 반복한다 |
| 두 개의 모자 | 기능 추가 모자를 썼을 때는 기존 코드를 고치지 않고 기능만 더한다. 리팩터링 모자를 썼을 때는 기능을 더하지 않고 구조만 바꾼다. 둘을 자주 바꿔 쓰되, 지금 어느 모자를 썼는지 늘 의식한다 (켄트 벡의 비유) |
| 3의 법칙 | 처음엔 그냥 한다. 비슷한 일을 두 번째 하면 일단 넘어간다. 세 번째 하게 되면 리팩터링한다 |
| 성능은 다듬은 뒤에 | 반복문을 쪼개는 등 리팩터링이 성능을 떨어뜨릴까 걱정되더라도 먼저 구조를 정리한다. 잘 다듬어진 코드라야 성능 개선도 쉽다. 정말 느려졌다면 그다음에 측정하고 개선한다 |
왜 하나
- 설계가 좋아진다. 시간이 지나며 무너지는 구조를 계속 바로잡는다.
- 코드를 이해하기 쉬워진다. 다음에 읽을 사람(미래의 나 포함)의 시간을 아낀다.
- 구조가 드러나면 버그가 잘 보인다.
- 결과적으로 프로그래밍 속도가 빨라진다. 좋은 코드인지 가늠하는 가장 확실한 기준은 얼마나 수정하기 쉬운가다.
코드에서 바로 써먹는 습관
책의 첫 예제(공연료 청구서 프로그램)에서 나온 작은 습관들이다.
- 함수의 반환값을 담는 변수는 항상
result라고 이름 붙인다. 역할이 바로 보인다. - JavaScript 같은 동적 타입 언어에서는 매개변수 이름에 타입을 드러낸다. 역할이 뚜렷하지 않은 매개변수는
aPerformance처럼 부정관사를 붙인다. - 한 번만 쓰는 임시 변수는 밖에 두지 말고 쓰는 자리에 바로 넣는다(변수 인라인). 함수 추출이 쉬워진다.
컨벤션 위반을 대량으로 고칠 때
스타일 가이드 위반이 코드베이스 전체에 퍼져 있으면 한 번에 다 고치고 싶어진다. 그러나 포매터를 전체에 일괄 적용하면 git blame 이력이 덮이고 리뷰할 수 없는 거대한 변경이 생긴다.
| 원칙 | 내용 |
|---|---|
| 보이스카우트 규칙 | 「캠프장은 처음 왔을 때보다 깨끗하게 해 두고 떠난다.」 작업하다 만난 곳을 조금씩 정리한다 |
| 규칙은 도구에 담는다 | 팀 규약을 린터·정적 분석 설정 파일(ESLint, Checkstyle 등)에 담아 모두 같은 기준으로 검사한다. 새 프로젝트는 경고 0을 유지한다 |
| 위험이 낮은 규칙부터 | 동작에 영향이 없는 규칙(공백, import 순서)부터 고치고, 영향이 큰 규칙은 나중에 |
| 주제별로 작은 PR | 규칙 하나당 PR 하나. 리뷰와 병합이 쉽다 |
| 규칙의 예외부터 확인 | 원문 가이드를 다시 읽어 예외 조건까지 파악한 뒤 고친다 |
정규식으로 일괄 치환할 때는 순서를 지킨다.
1. 검색(grep, rg)으로 대상 범위를 먼저 확인
2. 치환(sed 등): 백업을 남기거나 Git 작업 트리가 깨끗한 상태에서
3. diff로 결과 검증
4. 테스트 실행
5. 백업 파일을 빼고 커밋이력을 덮는 일괄 포맷 커밋을 꼭 해야 한다면 그 커밋을 .git-blame-ignore-revs에 등록해 git blame에서 건너뛰게 한다.
정리
- 리팩터링은 동작을 유지한 채 구조만 바꾸는 일이다. 기능 추가와 같은 커밋에 섞지 않는다.
- 테스트가 안전망이다. 작은 단계마다 테스트를 돌린다.
- 기능 추가 전에 구조부터 정리하고, 같은 일을 세 번째 할 때 리팩터링한다.
- 성능은 깨끗한 코드 위에서 측정한 뒤 개선한다.
관련 노트: 코드 리뷰 원칙과 체크리스트, 코드 리뷰에서 자주 나온 지적, 프론트엔드에서의 TDD, Simple Design, 기술 부채