[리팩터링 2판] - 리팩터링 원칙

Lee Jeong Min·2022년 8월 4일
0

리팩터링 2판

목록 보기
2/12
post-thumbnail

리팩터링 2판의 Chatper 02을 보고 정리한 글입니다.

리팩터링 정의

명사로서의 리팩터링

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

앞 챕터에서 확인한 함수 추출하기조건부 로직을 다형성으로 바꾸기가 이에 해당한다.

동사로서의 리팩터링

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

여기와 명사로서 정의할 때 '겉보기 동작'이라는 표현을 썻는데, 이 말의 의미는 리팩터링하기 전과 후의 코드가 똑같이 동작해야함을 의미한다.


즉, 위에서의 리팩터링 정의를 따르면 특정한 방식에 따라 코드를 정리하는 것만이 리팩터링이라고 볼 수 있다.

리팩터링하다가 코드가 깨진다고 하거나 정상 작동하지 않는다는 것은 리팩터링을 한 것이 아니다!

리팩터링과 성능 최적화

  • 리팩터링의 목적: 코드를 이해하고 수정하기 쉽게 만드는 것

    성능은 신경쓰지 않기에 프로그램의 성능은 좋아질 수도, 나빠질 수도 있다.

  • 성능 최적화의 목적: 속도 개선

    성능만을 목표로 코드를 작성하다 보면, 코드를 다루기에 더 어렵게 바뀔 수도 있다.

리팩터링 하는 이유

코드를 건강한 상태로 유지하는 데 도와주기 때문!

  • 리팩터링하면 소프트웨어 설계가 좋아진다.
    • 아키텍처 없이 단기 목표만을 위해 코드를 수정하면 코드만 보고 설계파악이 어려움
    • 코드만으로 설계 파악이 어려워질수록 설계 유지가 어렵고 부패속도 증가

규칙적인 리팩터링은 코드의 구조를 지탱해준다.

  • 리팩터링하면 소프트웨어를 이해하기 쉬워짐
    • 프로그래밍은 컴퓨터와 대화하는 것이며 컴퓨터는 정확히 코드에 따라 반응
    • 따라서 컴퓨터에게 시키려는 일과 이를 표현한 코드의 차이를 최대한 줄여야 함

훗날, 다른사람 혹은 나 자신을 위해 코드의 의도를 명확하게 전달하도록 만들자.

  • 리팩터링하면 버그를 쉽게 찾을 수 있다.

코드를 이해하기 쉽다는 말은 버그를 찾기 쉽다는 말이다.

  • 리팩터링하면 프로그래밍 속도를 높일 수 있다.

내부 설계가 잘 된 소프트웨어에 새로운 기능을 추가하는 것은 쉽다.

언제 리팩터링해야 할까?

3의법칙

  1. 처음에는 그냥 한다.
  2. 비슷한 일을 두 번째로 하게 되더라도, 일단 계속 진행한다.
  3. 비슷한 일을 세 번째 하게 되면 리팩터링한다.

스트라이크 세 번이면 리팩터링하라.

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

리팩터링하기 가장 좋은 시점은 코드베이스에 기능을 새로 추가하기 직전이다.

기능을 새로 추가하기 직전, 함수 매개변수화하기를 적용

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

코드를 수정하려면 먼저 그 코드가 하는 일을 파악해야한다. 이를 파악하고 코드의 의도가 더 명확하게 드러나도록 만들 수 있는지 확인한다. 이후 이해를 위한 리팩터링을 진행하고, 이를 통해 더 깊은 수준까지 이해할 수 있다. (복잡한 코드 아래 숨어 있는 다양한 기회를 발견할 수 있다.)

이런 초기 단계의 리팩터링은 밖을 잘 내다보기 위한 창문 닦기이다.

쓰레기 줍기 리팩터링

간단히 수정할 수 있는 것은 즉시 고치고, 시간이 좀 걸리는 일은 짧은 메모만 남긴 다음, 하던 일을 끝내고 나서 처리한다.

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

리팩터링을 그동안 해오지 않았다면 계획된 리팩터링이 필요하다. 그러나 리팩터링은 계획하여 하는 것이 아닌 수시로 프로그래밍을 하면서 기회가 될 때마다 해야한다.

마치 프로그래밍할 때 if문 작성 시간을 따로 구분하지 않는 것과 같다.

오래 걸리는 리팩터링

오래 걸리는 리팩터링을 하더라도 팀 전체가 리팩터링에 매달리는 데는 회의적이다. 누구든지 리팩터링해야할 코드와 관련한 작업을 하게 될 때마다 원하는 방향으로 조금씩 개선하자.

리팩터링이 코드를 깨트리지 않는다는 장점을 활용!

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

코드리뷰 진행시, 눈으로만 코드를 보는 것이 아닌 실제로 코드를 리팩터링하여 쉽게 구현할 수 있는지 살펴보자. 이 과정을 거치면 한 차원 높은 아이디어가 떠오르기도 한다. 리팩터링은 또한 코드 리뷰의 결과를 더 구체적으로 도출하는 데에 도움된다.

코드 리뷰 진행시 코드 작성자와 참석하여 진행하는 것이 효과적이며, 나란히 앉아서 리팩터링을 하게되면 자연스럽게 짝 프로그래밍(Pair programming)이 된다.

리팩터링하지 말아야 할 때

  • 외부 API 다루듯 호출해서 쓰는 코드인 경우
  • 리팩터링하는 것보다 처음부터 새로 작성하는게 쉬운 경우

리팩터링 시 고려할 문제

리팩터링에 딸려오는 문제도 있다는 것을 인지하고, 이런 문제가 언제 발생하고 어떻게 대처할지 알아보자.

새 기능 개발 속도 저하

많은 사람들이 리팩터링 때문에 새 기능을 개발하는 속도가 느려진다고 여긴다. 그러나 리팩터링의 궁극적인 목적은 개발 속도를 높여서, 더 적은 노력으로 더 많은 가치를 창출하는 것이다. 이 점을 잘 알아둗고, 상황에 맞게 조율하여 리팩터링을 진행해야한다.

리팩터링을 과도하게 하는 경우보다 거의 하지 않는 경우가 많은데, 리팩터링을 더 자주 하도록 노력해야 한다.

리팩터링의 동력이 경제적인 효과를 위함임을 명시하자.

코드 소유권

책의 저자는 코드 소유권을 작은 단위로 나눠 관리하는 것을 반대하며, 소유권을 팀에 두고 수정권한을 주는것이 리팩터링 관점에서 더 잘 어울린다고 생각함.

브랜치

기능별 브랜치들이 독립적으로 개발되는 기간이 길어질수록 머지가 복잡해진다. 따라서 기능별 브랜치의 통합 주기를 2~3일 단위로 짧게 관리하는 지속적 통합(CI), 트렁크 기반 개발(TBD)를 제안한다.

이는 머지의 복잡도를 줄이기도하면서, 리팩터링과 궁합이 아주 좋다. 이러한 CI와 리팩터링을 합쳐서 익스트림 프로그래밍(XP)이 탄생

테스팅

리팩터링을 하면서 실수를 저지르거나 코드의 동작이 깨질 수 있다. 이때 핵심은 오류를 재빨리 잡는것에 있다. 이를 위한 테스트 스위트가 필요하고 자가 테스트 코드가 있다면 리팩터링 과정에서 버그가 생길 위험이 크다는 불안감을 해소할 수 있다.

자가 테스트코드는 통합 과정에서 발생하는 의미 충돌을 잡는 메커니즘으로 활용할 수 있어서 자연스럽게 CI와도 밀접하게 연관된다. CI에 통합된 테스트는 XP의 권장사항이자 지속적 배포(CD)의 핵심이기도 하다.

레거시 코드

레거시 시스템을 파악할 때 리팩터링이 굉장히 도움이 되며 이러한 코드를 리팩터링하기 위해서는 테스트가 있어야 한다.

테스트코드의 필요성 다시 강조

데이터베이스

데이터베이스 리팩터링은 프로덕션 환경에 여러 단계로 나눠서 릴리즈하는 것이 대체로 좋다. 이렇게 하면 프로덕션 환경에서 문제가 생겼을 때 변경을 되돌리기 쉽다.

즉, 데이터베이스의 필드의 이름을 변경하는 코드를 작성하고 선언된 데이터 구조나 접근 루틴을 변경하는 코드와 함께 버전 관리 시스템에 저장하는 식으로 리팩터링 진행

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

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

일반적으로 소프트웨어를 실제로 사용해보고 업무에 미치는 영향을 직접 확인하고 나서야 정말로 원하는 바를 알게되는데 이를 대처하는 한가지 방법은 유연성 메커니즘이다. 그러나 이러한 유연성 메커니즘을 생각나는대로 추가하게되면 너무 복잡해지므로 리팩터링을 미루면 훨씬 힘들어진다는 확신이 들 때만 유연성 메커니즘을 미리 추가하자.

이런식으로 설계하는 방식을 간결한 설계, 점진적 설계, YAGNI("you aren't going to need it") 등으로 부른다.

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

자가 테스트코드, 지속적 통합, 리팩터링이라는 세 기법을 이용하여 YAGNI 설계 방식으로 개발을 진행할 수 있다.

참고로 자가 테스트코드와 리팩터링을 묶어 테스트 주도 개발(TDD)라고 한다.

이를 이용하여 요구사항 변화에 재빠르게 대응하고 안정적인 선순환 구조를 코드베이스에 심을 수 있고, 좋은 아이디어를 프로덕션 코드로 반영하는 시간을 단축할 수 있다. 또한 고치는 데 시간을 잡아먹는 버그의 수를 줄여 소프트웨어의 신뢰성도 높일 수 있다.

리팩터링과 성능

책에선 크라이슬러 종합 보상의 사례의 교훈을 언급하며, 시스템에 대해 잘 알더라도 섣불리 추측하지말고 성능을 측정해보아야한다는 말을 한다. 이처럼 성능과 관련한 부분은, 전체 코드 중 극히 일부에서 대부분의 시간을 소비한다는 것이다.

'90%의 시간은 낭비'는 통계에서 착안하여 성능 최적화에 돌입하기 전까지는 성능에 신경 쓰지 않고 코드를 다루기 쉽게 만드는데 집중한다. 그다음 성능 최적화 단계에서 프로파일러로 프로그램을 분석하고, 그 부분들을 개선하면 적은 노력으로 훨씬 큰 효과를 볼 수 있다.

리팩터링을 잘 해두면 이런 식의 최적화에 두 가지 면에서 도움이 된다.

  • 성능 튜닝에 투입할 시간을 벌 수 있다.
  • 리팩터링이 잘 되어 있는 프로그램은 성능을 더 세밀하게 분석할 수 있다.

단기적으로 보면 리팩터링 단계에서 성능이 느려질 수 있지만 최적화 단계에서 코드를 튜닝하기 훨씬 쉬워지기 때문에 결국 더 빠른 소프트웨어를 얻게 된다.

리팩터링의 유래

1980년 스몰토크를 활용한 개발을 할때, 워드와 켄트의 XP와 리팩터링 개념이 등장하고 이러한 개념들이 스몰토크 개발 문화에 중요한 요소로 자리잡음. 이후 디자인 패턴 책 저자 중 한명인 랄프 교수의 제자인 빌에 의해 리팩터링에 대한 최초 연구가 진행됨

이러한 개념(리팩터링)이 현재 업계에서도 잘 받아들여지고 사용됨

리팩터링 자동화

자동 리팩터링을 제대로 구현하려면 텍스트 상태가 아닌 구문 트리로 해석하여 다뤄야한다. 또한 변경된 구문 트리를 다시 화면에 텍스트로 바꿔 표현해야하기 때문에 구현하기가 어렵다.

최근에는 언어 서버(Language Server)라는 기술이 뜨고 있고, 언어 서버란 구문 트리를 구성해서 텍스트 에디터에 API 형태로 제공하는 소프트웨어이다.

더 궁금하다면 아래 자료 참고

언어 서버 프로토콜

profile
It is possible for ordinary people to choose to be extraordinary.

0개의 댓글