Be-Developer

Refactoring 02 리팩터링 원칙

02 리팩터링 원칙

  • (명사) 리팩터링 : 소프트웨어 겉보기 동작은 그대로 유지한채, 코드를 이해하고 수정하기 쉽도록 내부 구조를 변경하는 기법.
  • (동사) 리팩터링 : 소프트웨어 겉보기 동작은 그대로 유지한채, 여러 리팩터링 기법을 적용해서 소프트웨어를 재구성하다.
  • 재구성(restructuring) : 코드베이스를 정리하거나 구조를 바꾸는 모든 작업, 그중 하나가 리팩터링.
  • 리팩터링과정에서 발견된 버그는 리팩터링 후에도 그대로 남아있어야 한다.
    • 겉보기 동작이 동일하기때문,
    • 포함하다보면 PR이 커질것이므로, bugfix는 다른 작업으로 나눠서 하자.
  • 두개의 모자

  • 기능을 추가할때에는 기존코드는 건드리지 않고 새기능만 추가하자. 진척도는 테스트를 추가하며 확인하자.
  • 리팩터링할때는 기능은 절대 추가하지않고, 코드 재구성만 하자. 테스트를 새로 만들지도 않는다.
    • 부득이하게 인터페이스가 수정되는 경우는 테스트수정이 필요하겠지만.
  • 작업단위에 두가지를 동시에 하더라도, 작업하는 동안 두 작업방식의 차이를 분명하게 인식하고 해야한다.

    반성! 이러면서 PR이 커지는게 대부분 이었다.

리팩터링 하는 이유

  1. 리팩터링하면 소프트웨어 설계가 좋아진다.
    • 중복코드를 제거하면 언제나 고유한 일을 수행함을 보장할 수 있다.
  2. 리팩터링하면 소프트웨어를 이해하기 쉬워진다.
  3. 리팩터링하면 버그를 쉽게 찾을 수 있다.
  4. 리팩터링하면 프로그래밍 속도를 높일 수 있다. (유지보수)

언제 리팩터링을 해야하는가

  • 3의 법칙 : 첫번째 두번째(중복이 있더라도) 그냥 진행하고, 세번째 맞닥뜨리면 진행한다.
    1. 준비를 위한 리팩터링 : 기능을 쉽게 추가하게 만들기
    • 리팩터링하기 가장 좋은 시점은 기능을 새로 추가하기 직전이다.
    • ex) func A(a,b) 에서 func A-1(a,b,c) 가 필요할때, ‘함수 매개변수화’ 리팩터링을 시도해본다.
    • 중복코드를 줄일 수 있는 방향으로 개선해보면, 버그 발생 위치를 줄일 수 있다. 2. 이해를 위한 리팩터링 : 코드를 이해하기 쉽게 만들기
    • 변수이름 수정
    • 메서드 쪼개기
    • 코드를 분석하면서 리팩터링하면, 더 깊게 이해할 수 있다. 3. 쓰레기줍기 리팩터링 (이해를 위한 리팩터링 변형)
    • 맘에안드는 코드가 있는데 당장 고칠 시간이 부족하다면, 간단히 수정할것들은 즉시 고치고, 시간이 걸리는 일은 메모로 남긴 후 일이 끝난뒤 처리한다. 4. 계획된 리팩터링과 수시로 하는 리팩터링
    • 위의 1,2,3 안은 수시로 진행할 수 있다.
    • 계획된 리팩터링은 최소한으로 줄이고, 대부분의 리팩터링은 드러나지않게 기회가 될때마다 하자.

      리팩터링과 기능개발 커밋을 분리해야하는가?

    • 필자는 리팩터링이 기능추가와 밀접하게 엮이는 경우가 많고, 리팩터링 사유에 대한 맥락이 사라지므로 반대한다. 5. 오래걸리는 리팩터링
    • ex) 라이브러리를 교체할때는 기존것과 새것 모두를 포용하는 추상인터페이스 분리.
      1. (오프라인)코드리뷰에 리팩터링 활용하기.
    • 리팩터링은 코드리뷰의 결과를 더 구체적으로 도출하는데 도움이 된다.
      • 개선안을 제시만 하지않고, 즉시 구현해볼 수 있기때문.
    • PR은 제외. 코드작성자가 직접 참석해야 맥락을 설명해줄 수 있으므로 오프라인 코드리뷰 권장.
      1. 관리자에게는 뭐라고 말해야할까
    • 어찌되었건 개발속도향상에는 리팩터링이 유리하다.
      1. 리팩터링 하지 말아야 할 때
    • 내부 동작을 이해해야할 시점에 리팩터링해야 효과를 제대로 볼 수 있다.
    • 리팩터링부터 처음부터 다시시작하는게 나은경우.

리팩터링시 고려할 문제

  1. 새 기능 개발 속도 저하
    • 리팩터링의 궁극적인 목적은 개발속도를 높여서, 더 적은 노력으로 더 많은 가치를 창출하는 것.
    • 그래도 상황에 맞게 조율하자.
    • 리팩터링의 본질은 코드를 예쁘게 꾸미는데에 있지 않다.
  2. 코드 소유권
    • public interface (API) 라면, 기존 메서드도 유지하고 새로 추가만 한다.
  3. 브랜치
    • conflict 방지를 위해 feature브랜치 를 하루~최장3일 안에 머지하자.
      • 최대한 기능을 잘게 쪼개고, 각 기능을 끌 수 있는 feature flag(toggle)을 응용하자.
    • ExtremePrograming , CI 빠른 머지가 권장.
  4. 테스트
    • 리팩터링을 안전하게 할수있도록 해줌.
    • CI에 통합하자.
  5. 레거시 코드
    • 레거시 코드 활용 전략(에이콘,2018) : 프로그램에서 테스트를 추가할 틈새를 찾아 시스템을 테스트해야한다.
    • 테스트를 위한 리팩터링이 일어날 수 있지만, 위험을 감내해야할 것.
    • 그래서 처음부터 자가 테스트코드가 중요하다.
  6. DB
    • evolutionary DB
      • db 스크립트도 버전컨트롤에 저장.
      • 마이그레이션 스크립트도 저장.
      • .. 위에꺼 읽어보자 1. 필드추가 2. 기존필드, 새 필드 동시 업데이트 3. 기존필드 삭제

리팩터링, 아키텍처, YAGNI

  • 리팩터링을 미루면 훨씬 힘들어진다는 확신이 들 때에만 유연성 매커니즘을 추가하자.
    • 유연성 매커니즘 : 앞으로의 요구사항을 추측해서 미리 작업.
  • YAGNI : You aren’t going to need it. 점진적설계, 간결한 설계.
  • 진화형 아키텍처는 아키텍처 관련 결정을 시간을 두고 반복해서 내릴 수 있따는 장점을 활용하는 패턴과 실천법을 추구한다.

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

  • 테스트 + CI + 리팩터링은 서로 강력한 상승효과를 발휘한다.
  • 리팩터링 + 유연성 매커니즘 -> 요구사항 변화에 빠르게 대응가능.
  • CD

리팩터링과 성능

  • 신속성이 요구되는 시스템을 제외하고는, 먼저 튜닝하기 쉽게 리팩터링하고 나서 속도를 위한 튜닝을 하자.
  • 신속성이 요구되는 시스템
    • 시간 예산 분배 : 설계를 여러 컴포넌트로 나누어 컴포넌트마다 자원(시공간) 예산을 할당.
    • 극히 일부의 코드에서 대부분의 실행시간을 소요한다. 따라서 의도적으로 성능 최적화를 다루기 전까지는 코드를 다루기 쉽게하는데에 집중하자.
  • 리팩터링을 잘 해두면
    • 성능 튜닝에 투입할 시간을 벌 수 있고(기능추가가 빠를것이기 때문)
    • 성능을 더 세밀하게 분석할 수 있다.
  • 단기적으로는 리팩터링 단계에서 성능이 느려질 수 있으나, 최적화단계에서 코드 튜닝이 쉬워지므로 더 빠른 소프트웨어를 얻게된다.

리팩터링 자동화

  • 자동 리팩터링을 제대로 구현하려면 코드를 텍스트상태가 아닌, syntex tree로 해석하여 다루어야한다.
  • 인텔리제이 리팩터링 도구
  • refactoring workbook 서적에 예제가 많음.