본문 바로가기

Dev.

리팩터링 할려고? 그래.. 테스트코드는 있고?

 

리팩터링을 무작정 하는 것보다 테스트 코드가 작성되어 있는 상태에서 하는 것이 개발시간을 줄이는 방법입니다. 리팩터링을 한다는 것이 기존의 복잡한 코드를 수정해서 개선하는 일인데, 수정한 코드가 정상적으로 돌아가는지는 일일이 테스트를 해보는 수 밖에 없습니다. 이런 부담감을 줄이기 위해서는 테스트 코드가 필요로 합니다.

 

 

 

목차

  • 리팩터링이 주는 부담감
  • 테스트 주도 개발 TDD
  • 필터를 리팩터링 해본 실전
  • 테스트 코드 작성 방법
  • 테스트 코드 구축의 기본! 모킹
  • 마무리

 

 

리팩터링이 주는 부담감

개발자 모두 리팩터링이 얼마나 중요하고, 어떤 효과를 주는지는 알고 있습니다. 하지만 개발자조차도 리펙터링은 무섭습니다. 특히 코드끼리 독립적이지 않고 서로 얽혀 있다면, 부담감은 가중됩니다. 좋은 뜻으로 기존 코드를 깨끗하게 만들었지만, 예상치 못한 곳에서 오류가 빵빵 터지기 시작합니다.

설령 서비스단에서 오류를 내지 않더라도, 리팩터링 하는 동안 디버깅 하는데 대부분의 시간을 쏟게 될겁니다. 잘 고쳐졌는지 그러다가 안되면 로그를 하나하나 찍어보겠죠. 그러다 오류가 나면 오류 메시지를 파악하려 노력합니다. 어디서부터 잘못된 건지 데이터 하나한 확인 합니다.

하하하.. 🤣

하지만 이런 끔찍한 과정을 겪지 않고도 리팩터링을 할 수 있는 방법이 있습니다. 바로 테스트 코드부터 작성하는 겁니다. 기존 기능이 모두 테스트를 통과하는 테스트 코드를 미리 작성해 놓고, 리팩터링을 합니다. 그러면 리팩터링을 하는 동악 테스트가 통과하는 지만 확인하면 됩니다. 이 방법은 테스트 코드 작성하는 것이 익숙하다면 훨씬 빨리 리팩터링 할 수 있는 방법입니다.

 

테스트 주도 개발 TDD

마틴 파울러가 쓴 도서 중 하나인 [리펙터링]에서도 테스트 코드 구축에 대해 1 단락을 할애합니다. 여기에서도 테스트 코드에 대한 가치를 계속 강조합니다. 여기서 더 나아가 테스트 코드를 작성하는 시점까지 언급합니다. 여러분들은 어떤 시점이 테스트 코드를 작성하기 가장 적절하다고 생각하시나요?

  • 코드를 작성하기 전
  • 코드를 작성하던 중
  • 코드를 작성한 후

마틴 파울러가 내린 답을 보자면, 코드를 작성하기 전이라고 합니다. 코드를 작성하기 전에 미리 테스트 코드를 작성하고 그다음 구현하고자 했던 코드를 구현하는 겁니다. 우린 이런 개발 방법을 TDD라고 합니다. Test-Driven Development라고 하며 해석하면 '테스트 주도 개발'이라고 부릅니다. 말 그대로 테스트 코드로 개발을 이끌어 가는 방법입니다.

여기서 Driven이라는 단어는 테스트 코드의 가치를 높여주는 표현이라고 생각합니다. 시점만 놓고 본다면 DAT라고 해도 되는 거잖아요 Development After Test!!.🥴 하지만 테스트 코드가 개발을 이끌어 간다는 표현은 테스트 코드가 단순히 검증을 위한 도구가 아님을 시사합니다. TDD에 대해 참 할 말이 많지만, TDD는 '테스트는 설계를 위한 도구다'(준비 중..) 글에서 더 이야기해보도록 하겠습니다.

 

 

필터를 리펙터링 해본 실전

직방에서 파트너 제휴를 맺은 중개사들이 사용하는 사이트에 사용되는 필터를 리펙터링 한 경험이 있습니다. 복잡한 필터가 3군데에서 사용되고 각각의 필터는 개별적으로 작성되어 있었습니다. 게다가 제가 작성한 필터 코드가 가독성면에서 저품질이라고 판단되었습니다.

  • 필터 코드의 중복을 없앤다.
  • 필터 코드의 가독성을 높인다.
  • 필터의 비즈니스 로직만 리펙터링 한다.

이 3가지의 목표를 가지고 리펙터링을 진행했었습니다. 이때 무작정 리펙터링을 감행하던 과거와는 달리 계획에 의한 리펙터링을 진행했었습니다.

  • 리펙터링 범위를 정하고
  • 범위에 해당하는 코드에 대한 테스트 코드 작성
  • 모든 테스트를 성공시키기
  • 리펙터링 진행
  • 모든 테스트 성공시키기
  • 1개만 교체하기
  • 모두 교체하기

덕분에 놀라운 경험을 했는데요. 필터가 경우의 수가 많고, 조건이 많아서 리팩터링이 쉽지 않을 거라는 예상과는 다르게, 실제로 테스트 코드를 작성해서 리펙터링한 코드는 동작을 시켰을 때도 아무런 버그가 보이지 않았습니다. 또한 오히려 기존에 지나쳤던 버그를 발견할 수 있었습니다. 특히 제가 작성한 코드가 버그가 없다고 자신할 수 있었습니다.

리펙터링을 위한 테스트 코드의 품질을 이 충분한지에 대한 기준은 주관적일 수 있습니다. 단순히 테스트 커버리지를 가지고 테스트코드의 품질을 논할 수는 없습니다. 테스트 커버리지는 테스트를 하지 않은 영역을 찾는데 그칩니다.

마틴 파울러의 리팩터링에서도 여기에 대해서 언급합니다. 그리고 그는 '테스트 결과가 초록색인 것만 보고도 리팩터링 과정에서 생겨난 버그가 하나도 없다고 확신할 수 있다면 테스트 코드는 제 역할을 다했다'라고'👍🏻 이야기합니다

그 외에도 실전에서 경험한 리팩터링 경험을 올려놓은 '[실전] 프런트 기준 컴포넌트 개선한 경험 공유'(링크) 도 있으니 한번 봐보시길 추천합니다.

 

 

테스트 코드 작성 방법

테스트 코드와 관련된 내용은 따로 더 자세히 다루겠습니다. 다만 여기서는 큰 맥락만 집어볼게요.

테스트 코드 작성 시

중요하게 생각해야 할 것들을 정리해 보면,

A. 실패할 상황에서는 반드시 실패하게 만들자

B. 테스트는 위험요인 중심으로 작성해야 한다

C. 테스트 코드도 중복을 피해야 한다. 다만 각 테스트 환경이 독립적이라는 대전제하에 진행되어야 한다

D. 테스트 코드의 흐름은 '설정(조건)-실행(발생)-검증(결과)' 이어야 한다. 영어로 표현하면 Given-When-Then 이라고도 한다

E. 문제가 생길 경계 조건을 생각해 보고 그 부분을 집중적으로 테스트하자

 

A, B, C, E는 사실 너무 당연한 내용입니다. 그리고 자신의 기준대로 조절을 해도 무방해 보입니다. 하지만 특히 D 테스트 코드를 어떤 흐름으로 작성할 것이냐는 기준이 있는 것이 좋습니다. 아마 아시는 분들은 다 아시겠지만,

 

Given - 준비
When - 실행
Then - 검증

 

이것이 보편적인 흐름입니다. 이런 기준이 없으면 테스트 코드도 제각각 작성하기 마련이죠. 테스트 코드 작성법에 대해서는 'Jest 테스트 코드 작성법'(준비중..) 에서 살펴보겠습니다.

 

테스트 코드 구축의 기본! 모킹

사실 테스트 코드의 절반은 외부 모듈이나 패키지, 또는 API 등등을 모킹을 하는데서 부터 시작합니다. 테스트를 작성 시 테스트 경계와 목표를 정확하게 하고 시작할 필요가 있는데요. 이때 내가 하고자하는 테스트 외의 범위는 모킹을 하여, 임시로 결과값을 다룰 수 있도록 합니다.

테스트를 작성하는데 있어서 중요한 내용이지만, 리펙터링을 알아보는 글이기 때문에 모킹에 대해서는 'Jest로 모킹하는 방법들'(준비중) 에서 다뤄보도록 하겠습니다.

 

 

마무리

리팩터링을 안정감 있게 진행하려면, 테스트 코드가 구축되어 있어야 한다는 내용을 다뤄봤습니다. 실제로 현업에서 리팩터링을 한다는 건 개발자 입장에서 부담스러운 일이 아닐 수 없습니다. 복잡한 코드를 개선하기 위해서 고쳤지만, 너무 복잡하거나 코드간의 의존성이 높아서 예상치 못한 버그가 생길 우려가 큽니다. 이럴 경우 외부에서 봤을 때, 리팩터링은 잘해야 본전인 작업인거죠.

우리가 '내부에 개발자가 필요한 이유, 리팩터링'(링크) 에서도 봤지만 리팩터링을 꾸준히 하지 않으면, 결국 기술 부채가 쌓이고 개발 생산성이 낮아질 것입니다. 이에 대해서는 '기술부채 잡는 품격있는 코드'(링크) 에서 자세히 알아봤죠.

이렇게 해야만하는 작업이라면 좀 더 마음 편하게 할 수 있으면 좋겠는데, 그 해결방안이 테스트 코드 구축인 겁니다. 코드를 고치고 나서 고친 코드가 테스트를 통과하기만 한다면, 찜찜한 마음없이 다른 작업을 빨리 해낼 수 있겠죠?

 

 
 

아래는 개발 커뮤니티 링크입니다. 들어오셔서 기술 정보, 트렌드 정보, 유료스터디, 무료스터디, 모각코 등등을 이용해 보세요.