리팩터링 정의
소프트웨어의 겉보기 동작은 그대로 유지한 채, 코드를 이해하고 수정하기 쉽도록 내부 구조를 변경하는 기법
누군가 리팩터링하다가 코드가 깨져서 며칠이나 고생했다
라고 한다면, 십중팔구 리팩터링한 것이 아니다.
두개의 모자 🧢
- 소프트웨어를 개발할 때 목적이
기능 추가
냐 리팩터링
이냐를 명확히 구분해야 한다.
- 기능을 추가할 때는 기존 코드는 절대 건드리지 않고, 오로지 새 기능만 추가한다.
- 리팩터링할 때는 기능 추가는 절대로 하지 않고, 오로지 코드 재구성에만 전념한다.
하지만 보통 소프트웨어를 개발하는 동안 두 모자를 자주 바꿔 쓴다….
리팩토링하는 이유
-
소프트웨어 설계가 좋아진다.
-
소프트웨어를 이해하기 쉬어진다.
-
버그를 쉽게 찾을 수 있다.
-
프로그래밍 속도를 높일 수 있다.
언제 리팩터링해야 할까?
3의 법칙 3️⃣
-
처음에는 그냥 한다.
-
비슷한 일을 두 번째로 하게 되면, 일단 계속 진행한다.
-
비슷한 일을 세 번째 하게 되면 리팩터링한다.
준비를 위한 리팩터링
기능을 쉽게 추가하게 만들기
- 리팩터링하기 가장 좋은 시점은 코드베이스에 기능을 새로 추가하기 직전이다.
이해를 위한 리팩터링
코드를 이해하기 쉽게 만들기
쓰레기 줍기 리팩터링
- 간단히 수정할 수 있는 것은 즉시 고친다.
- 시간이 좀 걸리는 일은 짧은 메모만 남긴 다음, 하던 일을 끝내고 나서 처리한다.
계획된 리팩터링 vs 수시로 하는 리팩토링
- 보기 싫은 코드를 발견하면 리팩터링하자.
- 그런데 잘 작성된 코드 역시 수많은 리팩터링을 거쳐야 한다.
- 무언가 수정하려 할 때는 먼저 수정하기 쉽게 정돈하고(단, 만만치 않을 수 있다)
- 계획된 리팩터링을 하게 되는 일은 최소한으로 줄여야 한다.
- 리팩터링 작업 대부분은 드러나지 않게, 기회가 될 때 마다 해야한다.
⏳ 오래 걸리는 리팩터링
- 팀 전체가 리팩터링에 매달리는 것은 추천하지 않는다.
- 그보다는 주어진 문제를 몇 주에 걸쳐 조금씩 해결해가는 편이 효과적이다.
- 누구든지 리팩터링해야할 코드와 과련한 작업을 하게 될 때마다 원하는 방향으로 조금씩 개선하는 방식이다.
🔎 코드 리뷰에 리팩터링 활용하기
❌ 리팩터링하지 말아야 할 때
- 외부 API 다루듯 호출해서 쓰는 코드라면, 지저분해도 그냥 둔다.
- 내부 동작을 이해해야할 시점에 리팩터링해야 효과를 제대로 볼 수 있다.
- 리팩터링하는 것보다 처음부터 새로 작성하는 게 쉬울 때도 리팩토링하지 않는다.
리팩터링시 고려할 문제
새 기능 개발 속도 저하
리팩터링의 궁극적인 목적은 개발 속도를 높여서, 더 적은 노력으로 더 많은 가치를 창출하는 것이다.
- ✅ 새 기능을 구현해 넣기 편해지겠다 싶은 리팩터링이라면 주저하지 않고 리팩터링부터 한다.
- ❌ 반면 내가 직접 건드릴 일이 거의 없거나, 불편한 정도가 그리 심하지 않다고 판단되면 리팩터링하지 않는 편이다.
사람들이 빠지기 쉬운 가장 위험한 오류는 리팩터링을 클린 코드
나 바람직한 엔지니어링 습관처럼 도덕적인 이유로 정당화 하는 것이다.
- 리팩터링하도록 이끄는 동력은 어디까지나 경제적인 효과에 있다.
- ❌ 리팩터링의 본질은 코드 베이스를 예쁘게 꾸미는데 있지 않다.
- ✅ 리팩터링은 개발 기간을 단축하고자 하는 것이다.
코드 소유권
브랜치
Feature branch
방식에는 단점이 있다.
- 독립 브랜치로 작업하는 기간이 길어질수록 마스터로 통합하기가 어려워진다.
- CI에 따르면, 모든 팀원이 하루에 최소 한 번은 마스터 브랜치와 통합한다.
- 다른 브랜치들과의 차이가 크게 벌어지는 일이 줄어들어 머지의 복잡도를 낮출수 있다.
- 하지만, 마스터를 건강하게 유지하고, 거대한 기능을 잘게 쪼개는 법을 배우고, 각 기능을 끌 수 있는
feature toggle
혹은 feature flag
를 적용하여 완료되지 않은 기능이 시스템 전체를 망치지 않도록 해야 한다.
테스팅
- 리팩터링의 두드러진 특성은
프로그램의 겉보기 동작은 똑같이 유지된다는 것
이다.
- 테스트 코드는 리팩터링을 할 수 있게 해줄 뿐만 아니라, 새 기능 추가도 훨씬 안전하게 진행할 수 있도록 도와준다.
레거시 코드
- 제 기능과 맞지 않은 함수 이름을 바로 잡고, 어설픈 프로그램 구문을 매끄럽게 다듬어라.
- ⚠️ 레거시 코드를 테스트 코드 없이 명료하게 리팩터링하기는 어렵다!
- 서로 관련된 부분끼리 나눠서 하나씩 공략하는것을 추천한다.
데이터베이스
- 데이터베이스 리팩터링은 프로덕션 환경에 여러 단계로 나눠서 릴리스하는 것이 대체로 좋다는 점에서 다른 리팩터링과 다르다.
- 필드 이름을 바꿀 때, 첫 번째 커밋에서는 새로운 데이터베이스 필드를 추가만 하고 사용하지 않는다.
- 그런 다음 기존 필드와 새 필드를 동시에 업데이트 하도록 설정한다.
- 그다음에는 데이터베이스를 읽는 크라이언트들은 새 필드를 사용하는 버전으로 조금씩 교체한다.
- 이 과정에서 발생하는 버그도 해결하면서, 클라이언트 교체 작업을 모두 끝냈다면, 예전 필드를 삭제한다.
리팩터링, 아키텍처, 애그니(YAGNI)
- 유연성 메커니즘 (Flexibility Mechanism)
- 현재까지 파악한 요구사항만을 해결
- 진행하면서 요구사항을 더 잘 이해하게 되면, 그에 맞쳐서 리팩토링
YAGNI
you aren’t going to need it
- 아키텍처와 설계를 개발 프로세스에 녹이는 방식
- 진화형 아키텍처 (Evolutionary Architecture)
리팩터링과 소프트웨어 개발 프로세스
XP (Extreming Programming)
익스트림 프로그래밍
리팩터링과 성능
- 리팩터링하면 소프트웨어가 느려질 수도 있는건 사실이다.
- 하지만, 그와 동시에 리팩터링하면 성능을 튜닝하기는 더 쉬워진다.
- 성능 튜닝에 투입할 시간을 벌 수 있다.
- 또한 프로파일링을 하면 이렇게 확보한 시간을 낭비 없이 쓸 수 있다.
- 리팩터링이 잘 되어 있는 프로그램은 성능을 더 세밀하게 분석할 수 있다.