개발자맛 치즈볼
thumbnail
Study

[리팩터링 2판 스터디] 2장. 리팩터링 원칙

2024.05.01.

리팩터링이란?

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

동작을 보존하는 작은 단계들을 거쳐 코드를 수정하고, 단계를 순차적으로 연결하여 큰 변화를 만들어내는 일

“누군가 ‘리팩터링하다가 코드가 깨져서 며칠이나 고생했다’ 라고 한다면, 십중팔구 리팩터링한 것이 아니다.”

기능 추가 VS 리팩터링

  • 기능 추가를 할 때는 기존 코드를 절대 건드리지 않고 새 기능을 추가하기만 해야 함
  • 리팩터링할 때는 기능 추가는 절대 하지 않기로 다짐한 뒤 오로지 코드 재구성에만 전념해야 함

리팩터링하는 이유

  • 소프트웨어 설계가 좋아짐
  • 소프트웨어를 이해하기 쉬워짐
  • 버그를 쉽게 찾을 수 있음
  • 프로그래밍 속도를 높일 수 있음

리팩터링을 해야할 때

3의 법칙

  1. 처음엔 그냥 함
  2. 비슷한 일을 두번째로 하게되면 일단 계속 진행
  3. 비슷한 일을 세번째로 하게되면 리팩터링함

수시로 리팩터링하고, 계획된 리팩터링은 최소화하기

  • 준비를 위한 리팩터링: 기능을 쉽게 추가하게 만들기
  • 이해를 위한 리팩터링: 코드를 이해하기 쉽게 만들기
  • 쓰레기 줍기 리팩터링: 비효율적으로 처리하는 코드를 깔끔하게 만들기

위 3가지 리팩터링은 모두 기회가 될때 진행함 (리팩토링 일정을 따로 잡지 않음)

그동안 리팩터링에 소홀했을 때만 따로 시간을 내서 리팩터링하기

“보기 싫은 코드를 발견하면 리팩터링하자. 그런데 잘 작성된 코드 역시 수많은 리팩터링을 거쳐야 한다.”
“무언가 수정하려 할 때는 먼저 수정하기 쉽게 정돈하고, 그다음 쉽게 수정하자”

오래 걸리는 리팩터링

대규모 리팩터링에 팀 전체가 매달리지 말고, 주어진 문제를 몇주에 걸쳐 조금씩 해결하기

코드리뷰에 리팩터링 활용하기

코드 작성자와 나란히 앉아 코드를 훑으며 리팩터링하는 페어 프로그래밍 방식 추천

리팩터링하지 말아야 할 때

  • 굳이 수정할 필요가 없을 때 (ex. 외부 API 다루듯 호출해서 쓰는 코드)
    • 내부 동작을 이해해야 할 시점에 리팩터링해야 효과를 볼 수 있기 때문
  • 처음부터 새로 작성하는게 쉬울 때

리팩터링 시 고려할 문제

* tip! 기술에 능통하지 않은 관리자에게는 리팩터링한다고 말하지 말것

새 기능 개발 속도 저하

  • 상황에 맞게 잘 조율해야 함
  • 리팩터링을 ‘클린코드’ 나 ‘바람직한 엔지니어링 습관’ 같은 도덕적 이유로 정당화하지 말것
  • 리팩터링의 본질은 코드베이스를 예쁘게 꾸미는게 아닌 오로지 경제적인 이유로 하는것임
  • 기능 추가 시간을 줄이고, 버그 수정 시간을 줄여줌으로써 개발 기간을 단축하고자 리팩터링을 하는 거란 것을 명심할 것

리팩터링의 궁극적인 목적은 개발 속도를 높여서, 더 적은 노력으로 더 많은 가치를 창출하는 것이다.

코드 소유권

  • 코드 소유권이 나뉘어 있으면 리팩터링에 방해가 됨
  • 팀원 누구나 코드를 수정할 수 있도록 코드 소유권을 팀에게 두는것을 추천함.

브랜치

  • 기능 브랜치 방식의 단점: 브랜치에서 작업할 기간이 길수록 마스터로 통합하기 어려워짐
  • 통합 주기를 최대한 짧게 잡을 것
  • CI (지속적 통합): 모든 팀원이 최소 하루 한번은 마스터와 통합해야 함
    • 마스터를 건강하게 유지해야 함
    • 거대한 기능을 잘게 쪼개야 함
    • 각 기능을 끌수있는 기능 토글을 적용하여, 미완성된 기능이 시스템을 망치지 않도록 해야함
  • CI 와 리팩터링은 궁합이 좋음

테스팅

  • 리팩터링의 첫번째 토대는 자가 테스트코드를 마련하는 것 (동작을 똑같이 유지해야 하므로)
  • 테스트 주기가 짧다면 버그를 더 쉽게 찾을 수 있으며, 리팩터링 과정에서 버그가 생길 불안감을 해소함

레거시 코드

  • 레거시 시스템을 파악할때 리팩터링이 매우 도움됨
  • 그전에 테스트를 보강해야 함

데이터베이스

  • 데이터 마이그레이션 스크립트로, 접근 코드와 DB스키마에 대한 구조적 변경을 처리함
  • 다른 리팩터링과 마찬가지로 작고 독립된 단계로 쪼개서 할것
  • 프로덕션 환경에 여러 단계로 나눠서 릴리즈하는 것이 좋음

리팩터링, 아키텍처, 애그니(YAGNI)

  • 리팩터링이 아키텍처에 미친 영향은 요구사항 변화에 자연스럽게 대응하도록 한것
  • 앞으로 필요할 유연성과 대응 방안을 추측하지 말고, 현재까지 파악한 요구사항만을 해결하는 소프트웨어를 구축하기
  • 진행하면서 요구사항을 더 이해하게 되면 아키텍처도 그에 맞게 리팩터링해서 바꾸기

YAGNI 설계방식

  • You aren’t going to need it (너 그거 필요없을걸ㅋ)
  • 당장 필요한 기능만으로 최대한 간결하게 만들라는 뜻
  • 실제로 앞으로 필요할 것 같아서 미리 구현해둔 기능 상당수가 결국 전혀 쓰이지 않거나, 미래 요구사항을 제대로 반영하지 못해 요히려 수정하기 더 어려워지는 경우가 많음
  • 자가 테스트 코드 + 리팩터링 + 지속적 통합

리팩터링 VS 성능

  • 리팩터링하면 성능이 느려질 수도 있음
  • 하지만 리팩터링을 한다면 이후에 성능을 튜닝하기 더 쉬워짐
    • 기능추가가 빨리 끝나 성능에 집중할 시간을 벌수 있음
    • 리팩터링이 잘 되어있다면 성능을 더 세밀하게 분석할 수 있음

성능 개선을 위한 방법

  • 처음엔 성능 신경쓰지 않고 코드를 다루기 쉽게 작성하기
  • 성능 최적화 단계가 오면 다음 단계를 따르기
    1. 프로파일러로 성능에 큰 영향을 주는 지점을 알아내기
      (대부분 프로그램은 전체 코드중 극히 일부에서 대부분의 시간을 소비함)
    2. 그 부분을 개선하되, 작은 단계로 나눠서 컴파일과 테스트를 거치고 프로파일러를 다시 실행하기
    3. 개선되지 않았다면 수정 내용을 되돌리기

리팩터링 자동화

소스 코드의 텍스트를 직접 조작하지 말고 IDE에서 제공하는 기능들을 잘 활용할것

© CheeseB, Powered By Gatsby.