Thief of Wealth

리팩터링 저자는 거의 1시간 간격으로 리팩터링을 한다고 한다.

그러다보니 저자의 작업 흐름에 리팩터링을 녹이는 방법이 여러가지 였고 이번에는 그 흐름들을 설명한다.

 

3의 법칙

1. 처음에는 그냥 한다.

2. 비슷한 일을 2번째로 하게 되면 (중복이 생겼다는 사실에 당황스럽겠지만), 일단 계속 진행한다.

3. 비슷한 일을 3번째로 하게 되면 리팩터링 한다.

 

 

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

리팩터링하기 가장 좋은 시점은 코드베이스 기능을 새로 추가하기 직전이다. 이 시점에 현재 코드를 살펴보면서,

구조를 살짝 바꾸면 다른 작업을 하기가 훨씬 쉬워질만한 부분을 찾는다.

가령 내 요구사항을 거의 만족하지만 리터럴 값 몇개가 방해되는 함수가 있을 수 있다.

함수를 복제해서 해당 값만 수정해도 되지만, 그러면 중복 코드가 생긴다.

나중에 이 부분을 변경할 일이 생기면 원래 코드와 복제한 코드를 모두 수정해야 하며, 

더 심한 경우는 복제한 코드가 어디 있는지까지 일일이 찾아내야 한다.

 

이렇게 복사해서 붙여넣는 방식으로 처리하면 나중에 새 기능을 약간 변형한 버전을 만들어야 할 때 번거로울 수 있다.

그래서 이럴 떄는 리팩터링 모자를 쓰고 함수 매개변수화하기를 적용한다.

그러고 나면 그 함수에 필요한 매개변수를 지정해서 호출하기만 하면 된다.

 

 

비유하자면 지금 위치에서 동쪽으로 100km를 이동하려는데 그 사이를 숲이 가로막고 있다면, 좀 둘러가더라도 20km 북쪽에 있는 고속도로를 타는 편이 세 배나 빠를 수 있다. 다들 '직진!'을 외치더라도, 때로는 "멈춰!, 지도를 보고 가장 빠른 경로를 찾아보자"고 말할 줄 알아야 한다.

준비를 위한 리팩터링이 바로 이런 역할을 한다.

 

버그를 잡을 때도 마찬가지다. 오류를 일으키는 코드가 세 곳에 복제되어 퍼저 있다면, 우선 한 곳으로 합치는 편이 작업하기에 훨씬 편하다.

또는 슈도 코드에 섞여 있는 갱신 로직을 분리하면, 두 작업이 꼬여서 생기는 오류를 크게 줄일 수 있다. 이처럼 준비를 위한 리팩터링으로 상황을 개선해 놓으면, 버그가 수정된 상태가 오래 지속될 가능성을 높이는 동시에, 같은 곳에서 다른 버그가 발생할 가능성을 줄일 수도 있다.

 

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

코드를 수정하려면 먼저 그 코드가 하는 일을 파악해야 한다.

그 코드를 작성한 사람은 자신일 수도 있고 다른 사람일 수도 있다.

나는 코드를 파악할 때마다 그 코드의 의도가 더 명확하게 드러나도록 리팩터링할 여지는 없는지 찾아본다.

조건부 로직의 구조가 이상하지 않은지, 살펴보기도 하고, 함수 이름을 잘못 정해서 실제로 하는 일을 파악하는데 시간이 오래 걸리지는 않는지도 살펴본다.

 

이렇게 하면 나중은 물론 지금 당장 효과를 볼 때도 많다.

저자는 오래전부터 자잘한 세부 코드에 이해를 위한 리팩터링을 해왔다.

 

워드 커닝햄이 말하길 

 

리팩터링하면 머리로 이해한 것을 코드에 옮겨 담을 수 있다. 그런 다음 수정한 코드를 테스트해보면 내 생각이 맞았는지 확인할 수 있다.

내가 이해한 것을 코드에 반영해두면 더 오래 보존할 수 있을 뿐만 아니라 동료들도 알 수 있다.

 

이렇게 하면 나중은 물론 지금 당장 효과를 볼 때도 많다.

나는 오래전부터 자잘한 세부 코드에 이해를 위한 리팩터링을 해왔다. 어떤 역할을 하는지 이해된 변수는 적절한 이름으로 바꿔주고, 긴 함수를 잘게 나누기도 한다. 그러면 코드가 깔끔하게 정리되어 전에는 보이지 않던 설게각 눈에 들어오기 시작한다.

 

이 모든 변경을 머릿속으로 시뮬레이션해볼만큼 머리가 좋지 않기 때문에, 코드를 정리하지 않았다면 영원히 보지 못하고 지나쳤을지 모를 것들이다. 랄프 존슨은 이런 초기 단계의 리팩터링을 밖을 잘 내다보기 위한 창문 닦기에 비유한다.

 

코드를 분석할 때 리팩터링을 해보면, 그렇지 않았더라면 도달하지 못해쓸 더 깊은 수준까지 이해하게 된다. 이해를 위한 리팩터링을 의미 없이 코드를 만지작 거리는 것이라고 무시하는 이 들은 복잡한 코드 아래 숨어 있는 다양한 기회를 결코 발견할 수 없다.

 

이해를 위한 리팩터링: 쓰레기 줍기 리팩터링

 

코드를 파악하던 중에 일을 비효율적으로 처리하는 모습을 발견할 때가 있다.

로직이 쓸데없이 복잡하거나, 매개변수화한 함수 하나면 될 일을 거의 똑같은 함수 여러 개로 작성해놨을 수도 있다.

이때 약간 절충을 해야 한다. 원래 하려던 작업과 관련 없는 일에 너무 많은 시간을 빼앗기긴 싫을 것이다.

그렇다고 쓰레기가 나뒹굴게 방치해서 나중에 일을 방해하도록 내버려두는 것도 좋지 않다.

 

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

이것이 이해를 위한 리팩터링의 변형이 쓰레기 줍기 리팩터링이다.

 

물론 수정하려면 몇 시간이나 걸리고 당장은 더 급한 일이 있을 수 있다.

그렇더라도 조금이나마 개선해두는 것이 좋다.

 

캠핑 규칙이 제안하듯, 항상 처음 봤을 때 보다 깔끔하게 정리하고 떠나자,

코드를 훑어볼 떄마다 조금씩 개선하다 보면 결국 문제가 해결될 것이다.

리팩터링의 멋진 점은 각각의 작은 단계가 코드를 깨뜨리지 않는 다는 것이다.

그래서 작업을 잘게 나누면 몇 달에 걸쳐 진행하더라도 그 사이 한 순간도 코드가 깨지지 않기도 한다.

 

 

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

앞에서 본 준비를 위한 리팩터링, 이해를 위한 리팩터링, 쓰레기 줍기 리팩터링은 모두 기회가 될 때만 진행한다.

나는 개발에 들어가기 전에 리팩터링 일정을 따로 잡아두지 않고, 기능을 추가하거나 버그를 잡는 동안 리팩터링도 함꼐 한다.

기능을 추가할 때든 버그를 잡을 대든, 리팩터링은 눈앞의 문제 뿐만 아니라 앞으로 할 작업에도 도움을 준다. 간과하기 쉽지만 굉장히 중요한 점이다.

리팩터링은 프로그래밍과 구분되는 별개의 활동이 아니다.

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

그래서 나는 리팩터링 시간을 일정에 따로 잡아두지 않고, 대부분의 리팩터링ㅇ르 다른 일을 하는 중에 처리한다.

 

보기 싫은 코드를 발견하면 리팩터링하자, 그런데 잘 작성된 코드 역시 수많은 리팩터링을 거쳐야 한다.

 

리팩터링은 과거에 저지른 실수를 바로잡거나 보기 싫은 코드를 정리하는 작업이라고 오해하기 쉽다.

보기 싫은 코드를 보면 리팩터링해야 함은 당연하지만, 잘 작성된 코드 역시 수많은 리팩터링을 거쳐야 한다.

 

나는 코드를 작성할 때마다 적절히 타협한다.

예컨테 매개변수화하기나 개별 함수로 나누는 기준을 정한다.

어제는 적합했던 기준이 오늘 하는 다른 작업에는 맞지 않을 수 있다.

 

이렇게 상황이 변해 기준을 변경해야 할 때, 코드가 이미 깔끔하다면 리팩터링하기가 더 쉽다.

 

무언가 수정하려 할 때는 수정하기 쉽게 정돈하고, 그런 다음 쉽게 수정하자.  - 켄트 벡

 

오랫동안 사람들은 소프트웨어 개발을 무언가를 추가하는 과정으로 여겼다.

기능을 추가하다 보면, 대개 새로운 코드를 작성해 넣게 된다.

하지만 뛰어난 개발자는 새 기능을 추가하기 쉽도록 코드를 수정하는 것이 그 기능을 가장 빠르게 추가하는 길일 수 있음을 안다.

소프트웨어 개발을 끝이 있는 작업으로 보면 안된다.

새 기능이 필요할 때마다 소프트웨어는 이를 반영하기 위해 수정된다.

이때 새로 작성해 넣는 코드보다 기존 코드의 수정량이 큰 경우가 대체로 많다.

 

오래 걸리는 리팩터링

리팩터링은 대부분 몇 분 안에 끝난다.. (음?)

길어야 몇 시간 정도이다.

하지만 팀 전체가 달려들어도 몇 주는 걸리는 대규모 리팩터링도 있다.

 

라이브러리를 새 것으로 교체하는 작업일 수도 있고,

일부 코드를 다른 팀과 공유하기 위해 컴포넌트로 빼내는 작업일 수도 있다.

 

또는 그동안 작업하면서 쌓아온 골치 아픈 의존성을 정리하는 작업일 수도 있다.

 

나는 이런 상황에 처하더라도 팀 전체가 리팩터링에 매달리는 데는 회의적이다.

그보다는 주어진 문제를 몇 주에 걸쳐 조금씩 해결해가는 편이 효과적일 때가 많다.

누구든지 리팩터링해야할 코드와 관련한 작업을 하게 될때마다 원하는 방향으로 조금씩 개선하는 식이다.

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

 

일부를 변경해도 모든 기능이 항상 올바르게 동작한다.

 

예컨대 라이브러리를 교체할 때는 기존 것과 새 것 모두를 포용하는 추상 인터페이스부터 마련한다.

기존 코드가 이 추상 인터페이스를 호출하도록 만들고 나면 라이브러리를 훨씬 쉽게 교체할 수 있다.

 

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

코드 리뷰를 정기적으로 수행하는 조직도 있다.

그렇지 않은 조직이라면 해보면 유익할 것이다.

코드 리뷰는 개발팀 전체에 지식을 전파하는 데 좋다.

경험이 더 많은 개발자의 노하우를 더 적은 개발자에게 전수할 수 있다.

대규모 소프트웨어 시스템의 다양한 측면을 더 많은 사람이 이해하는 데도 도움이 된다.

 

깔끔한 코드를 작성하는 데에도 굉장히 중요하다.

내 눈에는 명확한 코드가 다른 팀원에게는 그렇지 않을 수 있다.

자신이 하는 일에 익숙하지 않은 사람의 관점에서 바라보기란 누구나 어렵기 때문이다.

 

코드 리뷰를 하면 다른 사람의 아이디어를 얻을 수 있다는 장점도 있다.

일주일이면, 좋은 아이디어를 상당히 많이 수집할 수 있을 것이다.

이처럼 서로의 기여가 일을 더욱 편하게 만들어주므로, 나는 기회가 닿는대로 코드리뷰를 한다.

 

리팩터링은 다른이의 코들르 리뷰하는 데도 도움된다.

리팩터링을 활용하기 전에는 코드를 읽고, 그럭저럭 이해한 뒤, 몇 가지 개선사항을 제시했다.

지금은 새로운 아이디어가 떠오르면, 리팩터링하여 쉽게 구현해넣을 수 있는지부터 살펴본다.

 

쉽다면 실제로 리팩터링한다.

이 과정을 몇번 반복하면 내가 떠울린 아이디어를 실제로 적용했을 떄의 모습을 더 명확하게 볼 수 있다.

머리로만 상상하는게 아니라 눈으로 직접 확인하는 것이다.

그러다 보면 리팩터링해보지 않고는 절대 떠올릴 수 없었던 한 차원 높은 아이디어가 떠오르기도 한다.

 

리팩터링은 코드 리뷰의 결과를 더 구체적으로 도출하는 데에도 도움이 된다.

개선안들을 제시하는 데서 그치지 않고, 그중 상당수를 즉시 구현해볼 수 있기 떄문이다.

코드 리뷰를 이런 식으로 진행하면 훨씬 큰 성취감을 맛볼 수 있다.

 

코드 리뷰에 리팩터링을 접목하는 구체적인 방법은 리뷰의 성격에 따라 다르다.

흔이 쓰는 풀요청 모델 (코드 작성자 없이 검토하는 방식)에서는 그리 효과적이지 않다.

 

코드 작성자가 참석을 해야 맥락을 설명해줄 수 있고, 작성자도 리뷰어의 변경 의도를 제대로 이해할 수 있으므로, 이왕이면 참석자가 참석하는 방식이 좋다.

 

내가 경험한 가장 좋은 방법은 작성자와 나란히 앉아서 코드를 훑어가면서 리팩터링하는 것이다.

이렇게 하면 자연스럽게 (프로그래밍 과정 안에서 지속적인 코드 리뷰가 녹아있는) 짝 프로그래밍이 된다.

 

profile on loading

Loading...