[리팩터링 2판] 02. 리팩터링 원칙

2장에서는 리팩터링의 원칙에 대해서 알아보자
주요 키워드 : YAGNI, CI

2.0. Impact Sentences

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

난 뛰어난 프로그래머가 아니에요. 단지 뛰어난 습관을 지닌 괜찮은 프로그래머일 뿐이에요.

YAGNI - You Aren’t Going to Need It

당장 필요한 기능만으로 만들라


2.1. 리팩터링의 정의

명사 리팩터링

: 함수 추출하기, 조건부 로직을 다형성으로 바꾸기처럼 이름 붙은 리팩토링 기법들만 해당

동사 리팩터링

: 여러 리팩토링을 적용하다.

지금껏 수많은 사람이 코드를 정리하는 작업을 모조리 ‘리팩터링’이라고 표현하고 있는데, 앞에서 제시한 정의를 따르면 특정한 방식에 따라 코드를 정리하는 것만이 리팩터링이다.

재구성

: 코드베이스를 정리하거나 구조를 바꾸는 모든 작업. 리팩터링은 재구성 중 특수한 형태

성능최적화

: 리팩터링은 코드를 이해하고 수정하기 쉽게 만드는 것. 성능은 좋아질 수도 나빠질 수도 있다. 성능 최적화는 속도 개선에만 신경쓰기 때문에 코드는 다루기에 어렵게 바뀔 수도 있다.


2.2. 두개의 모자

소프트웨어를 개발할 때 목적이 기능추가인지 리팩터링인지를 명확히 구분해 작업해야 한다. 이는 마치 모자를 바꿔 쓰는 것처럼 수행할 수 있다.

  • 기능추가 모자 : 기존 코드는 건드리지 않고 새 기능을 추가하기만 한다.
  • 리팩터링 모자 : 기능 추가는 절대 하지 않고 코드 재구성에만 전념한다.


2.3. 리팩터링 하는 이유

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


2.4. 언제 리팩터링 해야할까?

  • 준비를 위한 리팩터링
    기능을 쉽게 추가하게 만들기
  • 이해를 위한 리팩터링
    코드를 이해하기 쉽게 만들기
  • 쓰레기 줍기 리팩터링
    쓰레기가 나뒹굴게 방치해서 나중에 일을 방해하게 내버려둘 수는 없다.
    간단히 수정할 수 있는 것은 즉시 고치고, 시간이 좀 걸리는 일은 짧은 메모를 남긴 다음, 하던 일을 끝내고 나서 처리한다.
  • 계획된 리팩터링과 수시로 하는 리팩터링
    프로그래밍과 구분되는 별개의 활동이 아니다.
    마치 프로그래밍할 때 if문 작성시간을 따로 구분하지 않듯, 기회가 될 때마다 해야한다.
  • 오래 걸리는 리팩터링
    골치 아픈 의존성 정리하는 상황이더라도 팀전체가 리팩터링에 매달리는 것에는 회의적이다.
    주어진 문제를 몇 주에 걸쳐 조금씩 해결해가는 편이 효과적이다.
  • 코드리뷰에 리팩터링 활용하기
    가장 좋은 방법은 작성자와 나란히 앉아서 코드를 훑어가면서 리팩터링하는 것이다. (pair programming)
  • 관리자에게는 뭐라고 말해야 할까?
    가치 있는 기능을 만들어내지 못하는 작업이라고 오해하여 리팩터링이 금지가 된 조직도 있다. 그러나 프로 개발자에게 주어진 임무는 새로운 기능을 빠르게 구현하는 것이고, 가장 빠른 방법은 리팩터링이다.
  • 리팩터링하지 말아야 할 때
    리팩터링하면 안되는 상황도 있다.
    • 외부 API 다루듯 호출해서 쓰는 코드라면 지저분해도 그냥 둔다. 내부 동작을 이해해야 할 시점에 리팩터링해야 효과를 제대로 볼 수 있다.
    • 리팩터링하는 것보다 처음부터 새로 작성하는 게 쉬울 때에도 리팩터링하지 않는다.


2.5. 리팩터링 시 고려할 문제

  • 새 기능 개발 속도 저하
    준비를 위한 리팩터링을 하면 변경을 훨씬 쉽게 할 수 있다고 확신한다.

    사람들이 빠지기 쉬운 가장 위험한 오류는 리팩터링을 클린 코드바람직한 엔지니어링 습관처럼 도덕적인 이유로 정당화하는 것이다.

    리팩토링의 본질은 오로지 경제적인 이유로 하는 것이다.

  • 코드 소유권
    고객에게 API로 제공되거나, 함수를 호출하는 코드의 소유자가 다른 팀인 경우 함수 이름을 바꾸는 것조차 간단하지 않을 때가 있다. 그래서 코드 소유권을 작은 단위로 나눠 엄격히 관리하는 데 반대한다. 팀원이라면 누구나 팀이 소유한 코드를 수정할 수 있게 해야 한다.
  • 브랜치
    기능 단위 브랜치로 개발시 머지가 복잡해지는 문제를 줄이기 위해서 지속적 통합(Continuous Integration)을 해야한다. 이는 리팩터링과의 궁합도 좋다.
  • 테스트
    자가 테스트 코드를 마련해야한다.
  • 레거시 코드
    대규모 레거시 시스템을 테스트코드 없이 리팩터링하기는 어렵다. 쉽게 해결할 방법은 없다. 내가 선호하는 방식은 서로 관련된 부분끼리 나눠서 하나씩 공략하는 것이다.
  • 데이터베이스
    데이터베이스가 리팩터링하기 어려운 영역이지만, 요새는 그렇지만도 않다.
    • 예를 들어 필드의 이름을 변경하는 경우, 예전 필드를 사용하는 데이터 모두 새 필드를 사용하도록 변환해야 한다.
    • 이 변환을 수행하는 코드를 간단히 작성 후, 선언된 데이터 구조나 접근 루틴을 변경하는 코드와 함께 버전 관리 시스템에 저장한다.
    • 데이터베이스를 다른 버전으로 이전할 때마다 련재 버전에서 원하는 버전 사이에 있는 모든 마이그레이션 스크립트를 실행한다.


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

복잡도를 높일 수 있는 유연성 매커니즘은 반드시 검증을 거친 후에 추가한다.
유연성 매커니즘이란 다양한 예상 시나리오에 대응하기 위해 함수에 매개변수들을 추가하는 것을 말한다.

YAGNI (You Aren’t Going to Need It)

  • 앞으로 어느 부분에 유연성이 필요하고 어떻게 해야 그 변화에 가장 잘 대응할 수 있을지 추측하지 않고, 그저 현재까지 파악한 요구사항만을 해결하는 소프트웨어를 구축한다. 단, 이 요구를 멋지게 해결하도록 설계한다.
  • 간결한 설계, 점진적 설계라고도 부른다.
  • 나중에 문제를 더 깊이 이해하게 됐을 때 처리하는 것이 낫다.


2.7. 리팩터링과 소프트웨어 개발 프로세스

  • 자가 테스트 코드

  • 지속적 통합

  • 리팩터링

서로 강력한 상승효과YAGNI 방식으로 개발을 진행할 수 있다.


2.8. 리팩터링과 성능

시스템을 잘 알더라도 섣불리 추측하지 말고 성능을 측정해봐야 한다.

  • 일단 성능에 신경 쓰지 않고 코드를 다루기 쉽게 만드는데 집중
  • 그 후 성능최적화 수행
    • 프로파일러로 시간과 공간을 많이 잡아먹는 지점을 알아내서 그 부분들을 개선


2.9. 리팩터링의 유래

리팩터링이라는 용어의 정확한 유래를 찾을 수는 없다. 여러 경험을 통해 저자는 리팩토링이 정말 중요한 기법이라는 걸 깨달았지만 프로그래머가 읽을 만한 책이 하나도 없었다. 그래서 저자가 책을 썼고, 리팩터링이라는 개념을 업계에서 잘 받아들였다.


2.10. 리팩터링 자동화

인텔리제이 IDEA나 이클립스 등 자동 리팩터링을 지원하는 도구를 사용하는 것이 좋다.


2.11 요약

  • 재구성이 아닌 리팩토링특정한 방식으로 코드를 정리하는 것을 말한다.
  • 기능추가모자🎓를 쓸 때는 기능추가만, 리팩터링 모자👒를 쓸 때는 리팩터링만 수행한다.
  • if문 작성시간을 구분하지 않듯, 리팩터링은 기회가 될 때마다 해야한다.
  • 프로 개발자는 새로운 기능을 빠르게 구현하는 것이 필요하고, 가장 빠른 방법은 리팩토링이다.
  • 리팩터링은 이쁘게? ❌ 오로지 경제적인💸 이유로 하는 것이다.

  • YAGNI : 그저 현재까지 파악한 요구사항만을 해결하는 소프트웨어를 구축하는 간결한 설계방식
  • 자가 테스트코드 & 지속적 통합 (CI) & 리팩터링으로 YAGNI를 수행하면 궁합이 좋다.


댓글남기기