Study
[리팩터링 2판 스터디] 2장. 리팩터링 원칙
2024.05.01.
리팩터링이란?
소프트웨어의 겉보기 동작은 그대로 유지한 채, 코드를 이해하고 수정하기 쉽도록 내부 구조를 변경하는 기법
동작을 보존하는 작은 단계들을 거쳐 코드를 수정하고, 단계를 순차적으로 연결하여 큰 변화를 만들어내는 일
“누군가 ‘리팩터링하다가 코드가 깨져서 며칠이나 고생했다’ 라고 한다면, 십중팔구 리팩터링한 것이 아니다.”
기능 추가 VS 리팩터링
- 기능 추가를 할 때는 기존 코드를 절대 건드리지 않고 새 기능을 추가하기만 해야 함
- 리팩터링할 때는 기능 추가는 절대 하지 않기로 다짐한 뒤 오로지 코드 재구성에만 전념해야 함
리팩터링하는 이유
- 소프트웨어 설계가 좋아짐
- 소프트웨어를 이해하기 쉬워짐
- 버그를 쉽게 찾을 수 있음
- 프로그래밍 속도를 높일 수 있음
리팩터링을 해야할 때
3의 법칙
- 처음엔 그냥 함
- 비슷한 일을 두번째로 하게되면 일단 계속 진행
- 비슷한 일을 세번째로 하게되면 리팩터링함
수시로 리팩터링하고, 계획된 리팩터링은 최소화하기
- 준비를 위한 리팩터링: 기능을 쉽게 추가하게 만들기
- 이해를 위한 리팩터링: 코드를 이해하기 쉽게 만들기
- 쓰레기 줍기 리팩터링: 비효율적으로 처리하는 코드를 깔끔하게 만들기
위 3가지 리팩터링은 모두 기회가 될때 진행함 (리팩토링 일정을 따로 잡지 않음)
그동안 리팩터링에 소홀했을 때만 따로 시간을 내서 리팩터링하기
“보기 싫은 코드를 발견하면 리팩터링하자. 그런데 잘 작성된 코드 역시 수많은 리팩터링을 거쳐야 한다.”
“무언가 수정하려 할 때는 먼저 수정하기 쉽게 정돈하고, 그다음 쉽게 수정하자”
오래 걸리는 리팩터링
대규모 리팩터링에 팀 전체가 매달리지 말고, 주어진 문제를 몇주에 걸쳐 조금씩 해결하기
코드리뷰에 리팩터링 활용하기
코드 작성자와 나란히 앉아 코드를 훑으며 리팩터링하는 페어 프로그래밍 방식 추천
리팩터링하지 말아야 할 때
- 굳이 수정할 필요가 없을 때 (ex. 외부 API 다루듯 호출해서 쓰는 코드)
- 내부 동작을 이해해야 할 시점에 리팩터링해야 효과를 볼 수 있기 때문
- 처음부터 새로 작성하는게 쉬울 때
리팩터링 시 고려할 문제
* tip! 기술에 능통하지 않은 관리자에게는 리팩터링한다고 말하지 말것
새 기능 개발 속도 저하
- 상황에 맞게 잘 조율해야 함
- 리팩터링을 ‘클린코드’ 나 ‘바람직한 엔지니어링 습관’ 같은 도덕적 이유로 정당화하지 말것
- 리팩터링의 본질은 코드베이스를 예쁘게 꾸미는게 아닌 오로지 경제적인 이유로 하는것임
- 기능 추가 시간을 줄이고, 버그 수정 시간을 줄여줌으로써 개발 기간을 단축하고자 리팩터링을 하는 거란 것을 명심할 것
리팩터링의 궁극적인 목적은 개발 속도를 높여서, 더 적은 노력으로 더 많은 가치를 창출하는 것이다.
코드 소유권
- 코드 소유권이 나뉘어 있으면 리팩터링에 방해가 됨
- 팀원 누구나 코드를 수정할 수 있도록 코드 소유권을 팀에게 두는것을 추천함.
브랜치
- 기능 브랜치 방식의 단점: 브랜치에서 작업할 기간이 길수록 마스터로 통합하기 어려워짐
- 통합 주기를 최대한 짧게 잡을 것
- CI (지속적 통합): 모든 팀원이 최소 하루 한번은 마스터와 통합해야 함
- 마스터를 건강하게 유지해야 함
- 거대한 기능을 잘게 쪼개야 함
- 각 기능을 끌수있는 기능 토글을 적용하여, 미완성된 기능이 시스템을 망치지 않도록 해야함
- CI 와 리팩터링은 궁합이 좋음
테스팅
- 리팩터링의 첫번째 토대는 자가 테스트코드를 마련하는 것 (동작을 똑같이 유지해야 하므로)
- 테스트 주기가 짧다면 버그를 더 쉽게 찾을 수 있으며, 리팩터링 과정에서 버그가 생길 불안감을 해소함
레거시 코드
- 레거시 시스템을 파악할때 리팩터링이 매우 도움됨
- 그전에 테스트를 보강해야 함
데이터베이스
- 데이터 마이그레이션 스크립트로, 접근 코드와 DB스키마에 대한 구조적 변경을 처리함
- 다른 리팩터링과 마찬가지로 작고 독립된 단계로 쪼개서 할것
- 프로덕션 환경에 여러 단계로 나눠서 릴리즈하는 것이 좋음
리팩터링, 아키텍처, 애그니(YAGNI)
- 리팩터링이 아키텍처에 미친 영향은 요구사항 변화에 자연스럽게 대응하도록 한것
- 앞으로 필요할 유연성과 대응 방안을 추측하지 말고, 현재까지 파악한 요구사항만을 해결하는 소프트웨어를 구축하기
- 진행하면서 요구사항을 더 이해하게 되면 아키텍처도 그에 맞게 리팩터링해서 바꾸기
YAGNI 설계방식
- You aren’t going to need it (너 그거 필요없을걸ㅋ)
- 당장 필요한 기능만으로 최대한 간결하게 만들라는 뜻
- 실제로 앞으로 필요할 것 같아서 미리 구현해둔 기능 상당수가 결국 전혀 쓰이지 않거나, 미래 요구사항을 제대로 반영하지 못해 요히려 수정하기 더 어려워지는 경우가 많음
- 자가 테스트 코드 + 리팩터링 + 지속적 통합
리팩터링 VS 성능
- 리팩터링하면 성능이 느려질 수도 있음
- 하지만 리팩터링을 한다면 이후에 성능을 튜닝하기 더 쉬워짐
- 기능추가가 빨리 끝나 성능에 집중할 시간을 벌수 있음
- 리팩터링이 잘 되어있다면 성능을 더 세밀하게 분석할 수 있음
성능 개선을 위한 방법
- 처음엔 성능 신경쓰지 않고 코드를 다루기 쉽게 작성하기
- 성능 최적화 단계가 오면 다음 단계를 따르기
- 프로파일러로 성능에 큰 영향을 주는 지점을 알아내기
(대부분 프로그램은 전체 코드중 극히 일부에서 대부분의 시간을 소비함) - 그 부분을 개선하되, 작은 단계로 나눠서 컴파일과 테스트를 거치고 프로파일러를 다시 실행하기
- 개선되지 않았다면 수정 내용을 되돌리기
- 프로파일러로 성능에 큰 영향을 주는 지점을 알아내기
리팩터링 자동화
소스 코드의 텍스트를 직접 조작하지 말고 IDE에서 제공하는 기능들을 잘 활용할것