리팩터링 2판 - 챕터02 스터디

Feb 06, 2025

리팩터링과 그 목적

소프트웨어의 겉보기 동작은 그대로 유지한 채, 코드를 이해하고 수정하기 쉽도록 내부 구조를 변경하는 기법

리팩터링은 기능을 추가하거나 버그를 수정하거나 성능을 향상시키기 위한 목적이 아니라, 코드를 이해하고 수정하기 쉽도록 내부 구조를 변경하는 기법입니다.

  • 구조만 변경하는 것이기 때문에 리팩터링 하는 동안에는 코드가 항상 정상 작동해야 하며
  • 같은 이유로 리팩터링 과정에서 발견된 버그는 리팩터링 후에도 그대로 남아 있어야 합니다.
  • 또한 리팩터링 시 테스트를 새로 만들지 않습니다. 물론 부득이하게 인터페이스를 변경해야할 때에는 테스트를 수정이 필요합니다.

리팩터링의 궁극적인 목표는 코드를 수정하고 쉽게 만드는 것!

리팩터링은 언제 해야 할까?

  • 준비를 위한 리팩터링(기능을 쉽게 추가하게 만들기)

    • 리팩터링하기 가장 좋은 시점은 코드베이스에 기능을 새로 추가하기 직전
  • 이해를 위한 리팩터링: 코드를 이해하기 쉽게 만들기

  • 쓰레기 줍기 리팩터링

    • 간단히 수정할 수 있는 것은 즉시 고치고, 시간이 좀 걸리는 일은 짧은 메모만 남긴 다음, 하던 일을 끝내고 나서 처리. 이것이 이해를 위한 리팩터링의 변형인 쓰레기 줍기 리팩터링
  • 계획된 리팩터링과 수시로 하는 리팩터링

    • 리팩터링 시간을 일정에 따로 잡아두지 않고, 대부분의 리팩터링을 다른일을 하는 중에 처리. 리팩터링 작업 대부분은 드러나지 않게, 기회가 될 때마다 시도
  • 오래 걸리는 리팩터링

    • 팀 전체가 리팩터링에 매달리는 데는 회의적. 주어진 문제를 몇 주에 걸쳐 조금씩 해결해가는 편이 효과적일 때가 많다. 리팩터링이 코드를 깨트리지 않는다는 장점을 활용
  • 코드리뷰에 리팩터링 활용

    • 리팩터링은 다른 이의 코드를 리뷰하는 데도 도움
  • 관리자에게는 뭐라고 말해야 할까?

    • 일정을 최우선으로 여기는 관리자는 최대한 빨리 끝내는 방향으로 진행하길 원한다면, 기능을 빠르게 구현하는 가장 빠른 방법은 리팩터링
  • 리팩터링하지 말아야 할 때

    • 지저분한 코드를 발견해도, 굳이 수정할 필요가 없는 경우

      • 내부 동작을 이해해야 할 시점에 리팩터링해야 효과를 제대로 볼 수 있음
    • 리팩터링하는 것보다 처음부터 새로 작성하는게 쉬울 때

      • 그러나 직접 리팩터링 해보기 전에 결정을 내리기는 쉽지 않음

리팩터링 시 고려할 문제

1. 리팩터링 vs 클린코드(clean code)

  • 리팩터링을 클린코드나 바람직한 엔지니어링 습관 처럼 도덕적인 이유로 정당화 해서는 X. 리팩터링의 본질은 코드 베이스를 예쁘게 꾸미는데 있지 않다. 오로직 경제적인 이유로 하는 것
  • 리팩터링의 궁극적 목표는 개발 속도를 높여서, 더 적은 노력으로 더 많은 가치를 창출하는 것

2. 코드 소유권

  • 코드 소유권이 나뉘어 있으면 리팩터링에 방해
  • 그러므로 코드 소유권을 작은 단위로 나눠 엄격히 관리하는 데 반대. 코드의 소유권을 팀에 두고, 팀원이라면 누구나 팀이 소유한 코드를 수정할 수 있게 해야 함

3. 지속적 통합(Continuous Integration) / 트렁크 기반 개발(TBD. Trunk-Based Development)

  • 기능별 브랜치의 통합 주기를 2~3일 단위로 짧게 관리하면 merge 복잡도를 줄일 수 있고, 리팩터링과 궁합도 좋음(코드가 깨지지 않음).
  • 익스트림 프로그래밍(XP. eXtreme Programming)
  • 지속적 통합 - 자가 테스트코드 - 리팩터링 등 상호 의존하는 기법들을 하나로 묶은 프로세스
  • 자가 테스트 코드는 통합 과정에서 발생하는 의미 충돌을 잡는 메커니즘으로 활용 가능. CI/CD의 핵심

4. 레거시 코드

  • 레거시 시스템을 파악할 때 리팩터링이 도움
  • 코드를 훑게 되는 횟수가 많다는 말은 그 부분을 이해하기 쉽게 개선했을 때 얻는 효과도 그만큼 크다는 뜻

5. 현재까지의 요구사항만을 해결하는 소프트웨어 구축

  • 간결한 설계, 점진적 설계, YAGNI(You Aren’t Going to Need It), 진화형 아키텍처
  • 코딩 전에 아키텍처를 확정지으려면 소프트웨어 요구사항을 사전에 모두 파악(실현 불가능)
  • 유연성 메커니즘(flexibility mechanism)이 오히려 변화에 대응하는 능력을 떨어뜨릴 때가 대부분
    • 다양한 예상 시나리오에 대응하기 위한 매개변수들을 추가
    • 리팩터링을 미루면 훨씬 힘들어진다는 확신이 들 때만 유연성 매커니즘 추가

맺음

챕터2는 코드 지침(?)식으로 서술되어 읽는데 곱씹어볼만한 내용이 굉장히 많았습니다.

스터디를 하다보면 이런 식으로 글로만 작성된 챕터가 종종 있는데, 스터디할 때 이런 챕터는 어떤 식으로 공부하고 넘기면 좋을 지 궁금한 챕터입니다.

리팩터링에서는 두 개의 모자 예시가 나오는데, 여기서 리팩터링과 기능 추가(각 두개의 모자)의 경계를 어떻게 가져가면 좋을지 고민하게 되었습니다.

아직 현업에 뛰어들진 않았지만, 실제로 서비스 중인 프로덕션 코드에서 ‘계획된 리팩터링’이란 것은 회사 사정상 못할 수도 있는건데 이 리팩터링이란 것은 엔지니어 입장에서 딜레마가 아닐지..

출처