Life/컨퍼런스

[Refactoring] 마틴파울러가 말하는 리팩토링 (feat 테스트 코드를 짜는 이유)

샤아이인 2023. 1. 5.

이번 글은 유튜브의 좋은 영상을 하나 보면서, 정리하고 생각을 남기는 글 입니다.

 

영상 링크 : https://youtu.be/mNPpfB8JSIU

 

또한 추가적인 자료로 다음 PPT를 마틴파울러가 제공하고 있다.

https://martinfowler.com/articles/workflowsOfRefactoring/

 

Workflows of Refactoring

Many teams miss opportunities for refactoring by not realizing the different ways refactoring can fit into their workflows.

martinfowler.com

 

 

1. TDD(Test-Driven Development)와 리팩토링

TDD 프로세스는 다음 그림과 같다. TDD진행할때야 말로 명확한 리팩터링을 적용할 수 있다.

  1. 실패 테스트(Red) 작성
  2.  기능구현후 성공 테스트(Green)
    • 코드를 잘 짜기 보다는 기능이 동작하는 것이 중요함
  3. 리팩토링
    • 기능은 동일하게 작동하되, 중복 코드 제거 및 깔끔하게 정리한다

일반적인 주니어라면 2단계로 개발을 진행하는데, 우선 개발을 한 후에 리팩터링을 수행하게 된다.

즉 크게 코드를 작성하는 단계와, 코드를 정리하는 단계, 총 2단계로 나눠볼 수 있다.

 

그럼 왜 2단계 일까?

 

켄트백이 말하길 2가지 모드로 진행해야 함을 기억해야 한다!

바로!! "기능구현"과 "리팩토링" 단계이다! 언제든지 두 과정으로 서로 전환할 수 있다.

출처 - https://martinfowler.com/articles/workflowsOfRefactoring/#2hats

 

 

예를 들어 리팩토링 모드로 테스트를 하며 코드를 정리하다가 버그를 발견하면, 리팩토링 모드를 멈추고 기능 구현 모드로 넘어갈 수 있다.

특히 TDD 사이클 에서는 다음과 같이 나뉘게 된다.

출처 - https://martinfowler.com/articles/workflowsOfRefactoring/#tdd-hats

 

 

이렇게 2가지로 나뉘어지는 이유는 개발자가 가져야 할 자세가 다르기 때문인데, 리팩토링은 기능 개발과 달리 다음의 특징들을 갖는다.

  • 프로덕션 코드를 조금 수정하고 테스트를 실행해 기능의 이상 유/무를 확인함
  • 이슈가 있다면 롤백하고 다시 돌아가서 작업 진행
  • 리팩토링 시에는 기능을 변경하지 않아야 함
  • 버그가 나와도 버그를 수정하는 것은 기능을 바꾸는 것이므로 리팩토링이 아님

 

만약 리팩토링을 하다가 버그가 발견되면 "리팩토링 단계"에서 버그를 수정하는 것이 아니라, 리팩토링을 멈추고 "기능구현" 단계로 돌아가 고쳐야 한다.

그렇다면 언제 리팩토링을 해야 하는지 결정하는 것이 중요한데, 이에 대해서 알아보도록 하자.

 

 

 

2.  리팩토링 시점 혹은 절차

그렇다면 리팩토링을 언제 해야하는지 리팩토링의 시점을 캐치하는 것이 중요하다.

리팩토링의 시점 혹은 절차는 여러 가지로 나뉘어집니다. (대표적으로 TDD에서 수행하는 리팩토링은 TDD 리팩토링이라고 한다.)

 

다음과 같은 리팩토링 들이 있다.

  1. 쓰레기 줍기 리팩토링
  2. 이해를 위한 리팩토링
  3. 준비를 위한 리팩토링
  4. 계획된 리팩토링
  5. 장기적인 리팩토링

 

2 - 1) 쓰레기 줍기 리팩토링

  • 좋지 않은 혹은 이상한 코드를 발견하면 정리하는 것
  • 코드를 이전처럼 깨끗한 상태로 만듬
  • 아주 작은 변경사항일지라도 이전보다 더 나은 코드를 만들어야 함

보이스카우트의 룰중 하나이다, 항상 이전처럼 깨끗한 상태가 되도록 한다.

코드가 잘 동작하더라도, 코드에 대한 비판적인 생각이 든다면 그것은 리팩토링의 신호이다.

 

사실 모든것을 깨끗하게 만들 필요는 없다. 얼마나 리팩토링을 수행할 수 있을지가 더 중요하다.

할수 있는 만큼 하는것 중요합니다. 다만, 적어도 이전의 코드보다 조금이라도 더 나은 코드를 만들어야 한다는것 입니다.

 

2 - 2) 이해하기 위한 리팩토링

  • 보고도 이해가 가지 않는 코드를 발견하면 정리하는 것
  • 해당 코드를 힘들게 이해해도, 다음에 보면 이 코드는 똑같이 이해하기 어려움
  • 다음에 코드를 보는 사람은 작업이 수월하도록 이해한 로직을 코드로 녹여내야 함

이는 이해하기 어려운 코드를 만나게 되었을때에 해당된다.

퍼즐 같은 코드를 만나 어지저찌 이해했다고 해보자! 다음에 다시 본다면? 내가아닌 다른 팀원이 본다면?

아마, 지금 이해한 코드는 나중에 다시 봐도 이해하기 어려우며, 이 코드를 보는 다른 사람들도 비슷하게 시간을 낭비하게 된다.

이런경우, 코드를 리팩토링하면 다음에 코드를 보는 사람은 작업이 수월해지므로, 지금 이해한 로직을 코드로 녹여내야 한다.

 

이는 쓰레기 줍기 리팩토링과 유사한데, 쓰레기 줍기 리팩토링은 수정 대상이 이상한 코드인 반면에 이해를 위한 리팩토링은 이해하기 어려운 코드라는 점에서 차이가 있다.

 

2 - 3) 준비를 위한 리팩토링

  • 새로운 기능을 하는 코드를 작성했더니, 왜 이렇게 동작하는지 모르겠는 경우
  • 새로운 코드를 추가했더니, 기존과 구조가 달라지는 경우
  • 리팩토링을 통해 기존 코드를 수정하고, 리팩토링된 코드 위에 새로운 기능을 추가해야 함

만약 새로운 코드를 적용했을 때 코드가 적절하지 않다는 생각이 들면, 리팩토링을 통해 기존의 코드를 정리하고 다시 신규 기능을 추가해야 한다.

 

2 - 4) 계획된 리팩토링

  • 프로젝트 계획에 리팩토링 단계를 넣어 매번 코드를 깔끔하게 만듬
  • 시점이 매우 명확한 리팩토링 절차
  • 원래 팀에서 작은 단위의 리팩토링을 진행해 왔다면 할 필요 없는 단계이다.

계획된 리팩토링은 프로젝트 계획에 리팩토링을 넣어 해당 시점에 매번 코드를 정리하는 것이다.

이는 정해진 시점이 있으므로 언제 해야하는지 매우 명확하다. 하지만 리팩토링을 해야하는 이유 혹은 명분을 찾아야 하며 언제든지 쉽게 포기하고 타협할 수 있으므로 지양해야 한다.

 

역량이 좋은 팀은 알아서 수시로 리팩토링을 할 것이므로, 이는 리팩토링을 하지 않는 팀에게 필요하다.

리팩토링은 조금씩 꾸준히 항상 깨끗한 코드를 위해 진행하는게 맞지만, 물론 안하는 것보다는 이거라도 하는게 낫다.

즉, 필요악이므로 상황에 맞게 하도록 하자. 

 

2 - 5) 장기적인 리팩토링

  • 복잡한 의존성을 갖는 커다란 모듈을 수정해야 하는 경우
  • 코드를 어떻게 고치고 나면 어떻게 동작해야 하는지 장기적인 비전과 명확한 목표가 있어야 한다
  • 최대한 작은 단위로 정해진 목표에 맞게 코드를 수정하는 과정을 반복한다.

장기적인 리팩토링은 복잡한 의존성을 갖는 커다란 모듈을 수정해야 하는 경우이다.

이를 위해서는 코드를 어떻게 고쳐야 하는지 장기적인 비전과 명확한 목표가 있어야 하는데, 예를 들어 "리팩토링을 거치면 우리 코드는 이런식으로 바뀌어야 한다." 라는 구체적인 목표가 있어야 하는 것이다. 그리고 이를 향해 매주 작은 단위로 매주 매달 수정하면서 목표에 도달해야 한다.

 

리팩토링할 때 가장 좋은 방법은 최대한 작은 단위로 수행하는 것이다. 작은 단위로 코드의 수정을 반복하며 목표에 도달해야 한다.

 

 

 

3. 리팩토링이 필요한 이유

우리는 리팩토링을 왜 해야하는가?

 

일반적으로 동작하는 코드를 변경하는 일은 한번 더 작업을 하는 것이므로 시간낭비라고 생각하기 쉽다. 

하지만 Design Stamina Hypothesis에 따르면, 소프트웨어 설계에 신경쓰지 않으면 시간이 지날수록 복잡한 코드와 씨름하느라 개발 생산성이 저하된다. 

출처 - https://martinfowler.com/bliki/DesignStaminaHypothesis.html

 

반대로 설계에 신경을 쓰면 새로운 기능 개발이 쉬워지는데, 리팩토링은 코드를 항상 깔끔한 상태로 만들어서 좋은 아키텍처로 가도록 유도한다. 그래서 훨씬 더 많은 기능을 빠르게 구현할 수 있으며 이게 바로 리팩토링이 필요한 이유이다. 

 

일부는 좋은 품질(Quality) 혹은 클린 코드(Clean Code), 혹은 우리는 전문가(Professional)이므로 나쁜 코드가 아닌 올바른 방향(Right Things)을 추구해야 한다고도 한다.

 

하지만 이는 리팩토링이 필요한 본질적인 이유가 아니며, 리팩토링이 필요한 이유는 경제성(Economics)이다.

많은 기능을 빠르게 적용하기 위해 리팩토링이 필요한 것이다.

 

댓글