Refactoring

[ 리팩토링 by 마틴 파울러 ] Chapter02. 리팩터링 원칙

noahkim_ 2021. 7. 20. 21:37

* 마틴 파울러의 "리팩토링" 책을 공부한 후 정리한 포스팅 

* 비중이 적은 내용은 생략하였음. 

 

2.1 리팩터링 정의

리팩터링 : 겉보기 동작은 그대로 유지한 채, 여러 가지 리팩토링 기법을 적용해서 소프트웨어를 재구성.

+ 특정한 방식에 따라 코드를 정리

 

작은 단계들을 거쳐 코드 수정하여 순차적으로 큰 변화를 만들어냄.

 

( 겉보기동작 : 코드의 동작은 전과 후가 완전히 같아야 함. 내부 동작은 달라져 성능은 변할 수 있음. ) 

 

성능 최적화와 비슷.

코드의 목적을 이해하고 수정하기 쉽게 만듬. 오로지 성능이 목표가 아니다.

 

2.2 두 개의 모자

소프트웨어 개발시기능 추가혹은리팩터링목표를 구분해 작업함.

 

2.3 리팩터링하는 이유

  • 설계가 좋아짐
    내부 설계가 유지되기 위함.
    지속적인 리팩토링이 이루어지지 않으면 코드 구조가 무너지고 설계를 파악하기 어렵다.
    이해해야 할 코드량도 늘어남.
  • 이해가 쉬워짐
  • 버그를 쉽게 찾을 수 있음.
    코드가 하는 일을 깊게 파악하게 됨.
  • 프로그래밍 속도를 높일 있음.
    내부 설계와 가독성이 개선되고 버그가 줄어든다는 점은 품질 향상에 직결됨.
    새로운 기능 추가시, 기존 코드베이스에 녹여낼 있음.

 

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

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

기능 추가시, 구조를 살펴보고 추가하는데 작업하기 쉬워질만한 코드를 찾아 리팩터링함.

이 과정에서 중복코드가 생기면 함수를 매개변수화하여 중복을 피하는 등의 방식으로 작업 진행

버그를 잡을 때도 만약 오류를 일으키는 코드가 세곳에 퍼져있다면, 우선 한곳에 합쳐 작업한다. 

 

이러한 준비를 위한 리팩터링으로 다른 버그가 발생할 가능성을 줄이고, 버그가 수정된 상태가 오래 지속될 가능성을 높인다

 

  • 이해를 위한 리팩터링 ( 코드를 이해하기 쉽게 만들기 )

코를 파악할 때 마다 의도가 더 명확하게 드러나도록 살펴보기

 

  • 쓰레기 줍기 리팩터링

일을 비효율적으로 처리하는 코드를 발견할 때, 만약 간단히 수정 가능하다면 바로 수정하고 오래 걸린다면 하던 일을 끝내고 나서 즉시 처리

수정하려면 몇시간이 걸릴 수도 있다. 그러나 조금씩 개선해두기. 작업을 잘게 나누어도 작은 단계가 코드를 깨뜨리지 않기 때문에 몇 달에 걸쳐 작업해더라도 괜찮다.

 

  • 계획된 리팩터링과 수시로 하는 리팩터링

리팩터링 일정을 따로 잡아두지 않고, 기능을 추가하거나 버그를 잡는 동안 리팩터랑하기

 

  • 오래 걸리는 리팩터링

- 다른 팀과 코드를 공유하기 위해 컴포넌트를 빼내는 작업

- 의존성 정리

저자는 기간을 잡아 팀 전체가 달려드는 것보다 몇 주에 걸쳐 조금씩 해결하는 편이 효과적이라 제시함.

 

  • 코드 리뷰에 리팩터링 활용하기
  • 관리자에게는 뭐라 말해야 할까?

관리자가 기술에 정통하고 설계에 잘 이해하고 있다면 리팩토링 필요성을 쉽게 설득할 수 있다. 

하지만 기술을 모르는 관리자와 고객은 코드베이스의 건강 상태가 생산성에 미치는 영향을 모른다.

 

저자는 리팩토링시 소프트웨어를 빠르게 만드는 데 아주 효과적이라 한다. 

현재 설계가 적합하지 않다면 리팩터링 먼저 하고 함수를 추가하는 편이 빠르다.

버그 수정도 마찬가지다. 그러므로 관리자를 설득하여 리팩토링하며 코딩하라 제시한다.

 

  • 리팩터링하지 말아야 할 때

- 외부 API를 호출할 때

- 아예 처음부터 다시 작성하는게 빠를 때

 

2.5 리팩터링 시 고려해야 할 문제

  • 새 기능 개발 속도 저하

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

경제적인 이유로 하는것임. 

리팩터링은 기능 추가 시간을 줄이고, 버그 수정 시간을 줄여준다.

 

  • 코드 소유권

리팩토링 시 모듈의 내부뿐 아니라 시스템의 다른 부분과 연동하는 방식에도 영향을 주는 경우가 많음.

코드의 소유자가 다른 팀이라서 나에게는 쓰기 권한이 없는 경우도 있음.

 

코드 소유권이 나뉘어 있으면 리팩터링에 방해가 됨. 클라이언트에 영향을 주지 않고서는 원하는 형태로 변경할 수 없기 때문.

이러느 경우에는 함수 이름 바꾸기를 적용하여 기존 함수도 그대로 유지하고 함수 본문에서 새 함수를 호출하도록 수정함.

 

저자는 복잡한 상황을 피하기 위해 코드 소유권을 작은 단위로 나누어 관리하지 말라 제시함.

 

  • 브랜치

CI를 적용하여 머지의 복잡도를 낮추는 전략을 사용함. 

마스터를 건강하게 유지하고, 거대한 기능을 잘게 쪼개는 법을 배우고 기능 플래그를 적용하여 완료되지 않은 기능이 시스템 전체를 망치지 않도록 함.

 

  • 테스팅

리팩토링 시 겉보기 동작이 실수로 인해 달라질 수 있다. 이러한 경우를 대비하기 위해 테스트코드도 같이 코딩해준다. 

테스트 코드는 리팩토링을 할 수 있게 해줄 뿐만 아니라, 새 기능 추가도 훨씬 안전하게 진행할 수 있도록 도와줌. 

실수로 만든 버그를 빠르게 찾아서 제거할 수 있음.

또한 리팩토링 과정에서 버그가 생길 위험에 대한 불안감 해소 가능.

 

  • 레거시 코드

물려받은 레거시 코드는 대체로 복잡하고 테스트도 제대로 갖춰지지 않은 것이 많다. 

이러한 경우에는 테스트를 보강하여 레거시 시스템을 파악 및 버그를 피한다. 또한 리팩토링을 하여 함수를 입맛에 맞게 바꿀 수 있다.

 

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

리팩터링이 아키텍처에 미치는 실질적인 효과는 요구사항 변화에 자연스럽게 대응하도록 코드베이스를 잘 설계해준다는 데 있음.

아키텍처를 확정짓기 전 요구사항을 사전에 모두 파악해야 하는데, 업무시에 추가적으로 요구사항이 발생한다. 

 

유연성 매커니즘을 소프트웨어에 심어 코딩한다.

다양한 시나리오에 대응하기 위해 이를 염두하여 코딩한다. 하지만 이 모든 상황을 고려하다보면 오히려 변화에 대응하는 능력을 떨어뜨림.

 

리팩토링을 활용하면 일단 주어진 요구사항에 맞는 아키텍처를 디자인 한 후, 추가적인 요구사항을 리팩터링해서 바꾼다. 

그 과정에서 소프트웨어의 복잡도에 지장을 주지 않는 메커니즘은 마음껏 추가하지만, 복잡도를 높일 수 있는 유연성 매커니즘은 반드시 검증을 거친 후에 추가함. 이런식으로 설계하는 것을 YAGNI(“you aren’t going to need it) 라한다. 

이러한 경향은 진화형 아키텍처 원칙이 발전하는 계기가 됐다.

( 진화형 아키텍처는 아키텍처 관련 결정을 시간을 두고 반복해 내릴 수 있다는 장점을 활용하는 패턴과 실천법을 추구한다)

 

2.8 리팩터링과 성능

리팩터링 시 실제로 속도가 느려지는 경우가 많다. 

‘ 직관적인 설계 ‘ vs ‘ 성능 ‘ 

이러한 경우 성능을 튜닝하여 극복한다. 설계가 잘 되어있다면 기능 추가가 빨리 끝나므로 성능 튜닝에 집중할 수 있다.

 

또한 통계적으로 속도를 느리게 하는 코드는 전체의 ’10%’ 이다.

프로파일러로 프로그램을 분석하여 시간과 공간을 많이 잡아먹는 지점을 알아내서 그 부분을 개선한다. 

 

결국 리팩터링은 성능 좋은 소프트웨어를 만드는 기여한다. 단기적으로 보면 성능이 느려지는 원인이 있으나, 최적화 단계에서 튜닝하기 훨씬 쉬워지므로 결국 빠른 소프트웨어를 만들게 된다.

 


 

'패스트캠퍼스'라는 온라인 프로그래밍 교육 사이트에서 8주간의 리팩토링 책 완독반에 신청하였다. 

지금 8주차가 끝나고 책을 완독하였다. 

처음에 내용이 이해하기 쉽지 않았다. 디자인패턴과 객체지향에 능통하지 않아서..

리팩토링의 필요성은 코딩하면서 알게 되었는데 혼자 책으로 하려니.. 완독반을 신청하게 된것 같다

 

지금 정리하면서 두번째 내용을 보는데 그 당시 흐릿했던 내용이 지금 보니 새롭고 이해가 간다.. 신기하다

혹시나 누군가 이 포스팅을 보고 내가 리팩토링 공부하면서 정리한 내용이 도움이 되었으면