성장, 그리고 노력

부족하더라도 어제보다 더 잘해지자. 노력은 절대 배신하지 않는다.

Javascript

리팩터링(Refactoring)을 하는 이유

제이콥(JACOB) 2020. 9. 5. 15:42

나는 왜 갑자기 리팩터링에 관심을 가졌을까?

 최근 실무를 하다가 고객이 보는 정산서 로직을 리팩터링 해야 되는 경우가 생겼다. 이것이 필요했던 가장 큰 이유는 첫째는 성능 이슈가 컸다. 기존에 사용하던 레거시 코드의 경우 처음에는 많은 계산 로직이 없었으나, 점점 요구 사항과 세금 관련 이슈가 많이 생기다 보니, 한 가지 서비스가 정말 많은 것들을 판단하고 계산하는 로직이 되어버린 것이다. 두 번째 이유는 첫 번째 이유로 인해 이미 너무 복잡해져 버리고 비대해져 버린 서비스 로직의 문제였다.

 평소 리팩터링을 자주하긴 했었다. 우리는 항상 보이스카우트('지나간 자리는 지금보다 깨끗이 만든다')라는 원칙을 가지고 있고, 나는 그 누구보다 그 원칙을 따랐었다. 그래서 기존 로직을 약간 수정하거나 정말 작은 규모의 리팩터링보다는 코드를 새로 다시 짜버리는 경우가 많았다. 

 하지만 이 방식으로 서버쪽 정산서 로직을 접근하려고 보니, 리스크가 너무 컸다. 정산서가 안 나온다는 건 우리 회계부서나 고객에게 둘 다 정말 큰 문제였기 때문이다. 그리고 지금까지 작성되고 추가되었던 수많은 세금 관련 로직을 모두 단시간 안에 이해하는 것은 불가능에 가까웠다. 그래서 재작성이 아닌, 작은 단위의 리팩터링에 대해 고민하기 시작했다. 

 처음에는 언어가 가진 효율성을 제공하는 방식으로 처리하려고 했다. 하지만 그것은 한계가 있었다. 지금 당장 직렬 프로그램을 병렬 프로그램으로 변경한다고 한들, 더 많은 요구 사항과 수 많은 로직의 변경이 있을 텐데, 지금의 코드를 돌아가게 하는 임시방편에 불과했기 때문이다.

 그래서 조금 더 전문적으로 리팩터링에 대해 고민하기 시작했고, 공부하였다.


 리팩터링이랑 무엇일까? 

리팩터링이란, 소프트웨어의 겉보기 동작은 그대로 유지한 채, 코드를 이해하고 수정하기 쉽도록 내부 구조를 변경하는 기법 - 마틴 파울러의 리팩토링에서 -

 단순히 읽기 어려운 코드를 깔끔하게 정리하는 것만이 리팩터링이 아니다. 리팩터링이란 동작을 보존하는 작은 단계들을 거쳐 코드를 수정하고, 이러한 단계들을 순차적으로 연결하여 큰 변화를 만들어 내는 일이다. 리팩터링 하는 동안에는 코드가 항상 정상 작동하기 때문에 전체 작업이 끝나지 않았더라도 언제든지 멈출 수 있어야 한다. 리팩터링이 나는 책에 보면 재밌는 말이 있다.

누군가 '리팩토링하다가 코드가 깨져서 며칠이나 고생했다'라고 한다면, 십중팔구 리팩터링 한 것이 아니다.

 리팩터링 과정에서 발견된 버그는 리팩터링 후에도 남아 있으면 된다. 리팩토링의 목적은 코드를 이해하고 수정하기 쉽게 만드는 것이다. 프로그램의 성능은 좋아질 수도, 나빠질 수도 있다. 하지만, 하나 확실한 것은 보기 좋고 이해하기 좋은 코드가 디버깅이나 성능 최적화하기도 쉽다는 것이다. 

 

내가 무엇을 하려고 하는지를 생각을 명확히 하자.

소프트웨어를 개발할 때 항상 내가 하려는 것이 '기능 추가'인지 '리팩터링'인지 명확히 구분하자. '기능 추가'를 한다면 기존 코드는 절대 건드리지 않고 새 기능만 추가하기만 하면 된다. 반면 '리팩터링'이라면 기능 추가를 하지 않고 오로지 코드 재구성에만 전념하면 된다. 이 작업들을 빠르게 바꿔가면서 하면 하는 일이 더 명확해지고, 무엇을 하려는지 인지할 수가 있다.

 

 

리팩터링을 하는 이유는 무엇일까?

 리팩터링은 소프트웨어의 모든 문제점을 해결하는 만병통치약은 아니지만 코드를 건강한 상태로 유지하게 도와준다. 조금 더 리팩터링을 해야 하는 이유는 알아보자.

 

리팩터링 하면 소프트웨어 설계가 좋아진다.

 리팩터링하지 않으면 소프트웨어의 아키텍처가 무너지기 쉽다. 아키텍처가 무너지면 코드만 봐서는 설계를 파악하기 어려워지고, 이것이 어려워질수록 설계를 유지하기 어려워지며 설계가 부패하는 속도는 더욱 빨라진다. 반면 규칙적인 리팩터링은 코드의 구조를 지탱해 줄 것이다. 

  같은 일을 하더라도 설계가 나쁘면 코드가 길어지기 쉽고, 같은 일을 하는 코드가 여러 곳에서 나타날 수 있다. 그래서 중복 코드 제거는 설계 개선 작업의 중요한 한 축을 차지한다. 물론 코드량을 줄인다고 프로그램이 빨라지진 않지만, 코드량이 줄면 수정하는데 노력은 크게 달라진다. 코드가 길수록 실수 없이 수정하기 어려워지며 이해해야 할 코드량도 늘어난다.  비슷한 일을 하는 코드가 산재해 있다면 한 부분만 살짝 바꿔서는 시스템이 예상대로 작동하지 않을 수 있다(실제로 정산서 리팩터링 할 때 몸소 체험했다..). 

 반면 중복 코드를 제거하면 모든 코드가 언제나 고유한 일을 수행함을 보장할 수 있으며, 이는 바람직한 설계의 핵심이다. 

 

리팩터링하면 소프트웨어를 이해하기 쉬워진다.

 내 소스 코드는 컴퓨터가 시킨 일을 하기 위해 해석하는 데에만 쓰이지 않는다. 예를 들어 몇 달이 지나 누군가 내 코드를 수정할 때 읽게 될 수도 있다. 아니면 내가 다시 내가 짠 코드를 몇 달 후에 다시 봐야 할 수도 있다. 프로그램을 동작시키는 데만 신경 쓰다 보면 나중에 그 코드를 다룰 개발자를 배려하지 못하게 된다. 리팩터링을 통해 우리는 항상 코드의 목적이 더 잘 드러나게, 내 의도를 더 명확하게 전달하도록 개선해야 한다. 

 

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

 코드를 이해하기 쉽다는 말은 버그를 찾기도 쉽다는 말이다. 리팩터링을 하다보면 코드가 하는 일을 깊이 파악하게 되면서 새로 깨달은 것을 코드에 반영하게 된다. 

  

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

지금 당장은 리팩터링을 하면 추가적인 시간이 드니깐 시간이 더 걸린다고 생각할 수도 있다. 하지만 문득 실무를 하다 보면 이런 말을 많이 들어봤을 것이다. "예전에는 기능 추가가 바로바로 되었는데, 왜 이 기능하나 넣는데 오래 걸리죠?" 사실 이 말에 대한 이유는 간단하다. 새로운 기능을 추가할수록 기존 코드 베이스에 잘 녹여낼 방법을 찾는데 드는 시간을 늘어나고, 버그가 발생하는 일이 잦아지고 이를 해결하는 시간이 더 걸리기 때문이다. 기존 코드 베이스에 패치에 패치가 덧붙여지면서 프로그램의 동작을 파악하기가 너무 어려워진다. cmd를 누르고 몇 번을 타고 타고 들어가야지 찾을 수 있으려나.. 하여튼 이런 부담이 기능 추가 속도를 계속 떨어뜨리면서, 차라리 처음부터 새로 개발하는 편이 낫겠다고 생각하는 지경에 이른다. 

 내부 설계가 잘 된 소프트웨어는 새로운 기능을 추가할 지점과 어떻게 고칠지를 쉽게 찾을 수 있으며, 모듈화가 잘 되어 있으면 전체 코드베이스 중 작은 일부만 이해하면 된다. 코드가 명확하면 버그를 만들 가능성도 줄고, 버그를 만들더라도 디버깅하기가 훨씬 쉽다. 내부 품질이 뛰어난 코드 베이스는 새 기능 구축을 돕는 견고한 토대가 된다. 

 처음부터 좋은 설계를 하는 것은 매우 어렵다. 그래서 우리는 빠른 개발이라는 목표를 달성하기 위해 반드시 리팩터링이 필요하다. 지속적인 리팩터링을 통해 설계를 지속해서 개선해 나갈수 있다.


언제 리팩터링을 하지 말아야 할까?

 리팩터링은 항상 권장은 되지만, 무조건 해야되는 것은 아니다. 지저분한 코드를 발견했더라도 지금 굳이 수정할 필요가 없다면 수정하지 않는다. 내부 동작을 이해해야 할 시점에 리팩터링해야 효과를 제대로 볼 수 있다.  또한 리팩터링하는 것보다 처음부터 새로 작성하는게 쉬울 때도 굳이 리팩터링하지 않아도 된다. 하지만 이 시점은 뛰어난 판단력과 경험을 토대로 결정할 수 있을 것이다.

반응형

'Javascript' 카테고리의 다른 글

Object를 만드는 3가지 방법  (0) 2021.09.20
이젠 Modern JavaScript로 publish 하자  (0) 2021.05.22
언제 Promise.all을 사용해야 될까?  (1) 2020.08.22
CSS-in-JS  (0) 2020.08.19
webpack 뭐하는 걸까?  (0) 2020.08.18