[리팩터링 2판 - ch.3] - 코드에서 나는 악취

늘보·2022년 3월 10일
0

Refactoring

목록 보기
4/4

기이한 이름

코드를 명료하게 표현하는 데 가장 중요한 요소 하나는 바로 이름 이다. 그래서 함수, 모듈, 변수, 클래스 등은 그 이름만 보고도 각각이 무슨 일을 하고 어떻게 사용해야 하는지 명확히 알 수 있도록 엄청나게 신경 써서 이름을 지어야 한다.

사실상 가장 중요하지 않을까?

중복 코드

똑같은 코드 구조가 여러 곳에서 반복된다면 하나로 통합하여 더 나은 프로그램을 만들 수 있다. 코드가 중복되면 각각을 볼 때마다 서로 차이점은 없는지 주의 깊게 살펴봐야 하는 부담이 생긴다. 그중 하나를 변경할 때는 다른 비슷한 코드들도 모두 살펴보고 적절히 수정해야 한다.

긴 함수

우리의 경험에 비춰보면 오랜 기간 잘 활용되는 프로그램들은 하나 같이 짧은 함수로 구성됐다. 짧은 함수들로 구성된 코드베이스를 얼핏 훑으면 연산하는 부분이 하나도 없어 보인다. 코드가 끝없이 위임하는 방식으로 작성되어 있기 때문이다. 하지만 이런 프로그램을 수년 동안 다루다 보면 이 짧은 함수들이 얼마나 중요한지 깨닫게 된다. 간접 호출의 효과, 즉 코드를 이해하고, 공유하고, 선택하기 쉬워진다는 장점은 함수를 짧게 구성할 때 나오는 것이다.

물론 코드를 읽는 사람 입장에서는 함수가 하는 일을 파악하기 위해 왔다 갔다 해야 하므로 여전히 부담이 된다. 짧은 함수로 구성된 코드를 이해하기 쉽게 만드는 가장 확실한 방법은 좋은 이름이다. 함수 이름을 잘 지어두면 본문 코드를 볼 이유가 사라진다.

난 어떤 경우에서는 함수가 하는 일을 파악하기 위해 왔다 갔다 해야 하기 떄문에 작은 함수가 오히려 파악하기 불편하다고 생각했었다. 결국 내가 익숙하지 않아서 그랬던 것 아닐까..?

긴 매개변수 목록

종종 다른 매개변수에서 값을 얻어올 수 있는 매개변수가 있을 수 있는데, 이런 매개변수는 매개변수를 질의 함수로 바꾸기로 제거할 수 있다. 사용중인 데이터 구조에서 값들을 뽑아 각각을 별개의 매개변수로 전닫하는 코드라면 객체 통째로 넘기기를 적용해서 원본 데이터 구조를 그대로 전달한다. 항상 함께 전달되는 매개변수들은 매개변수 객체 만들기로 하나로 묶어버린다. 함수의 동작 방식을 정하는 플래그 역할의 매개변수는 플래그 인수 제거하기로 없애준다.

여긴 아직 이해가 안됐다. 매개 변수를 질의 함수로 바꾸기? 플래그 인수 제거하기? 책에서 만든 개념이라 아직 확실하게 이해가 된 부분이 아님.

전역 데이터

전역 데이터는 우리가 겪을 수 있는 착취 중 가장 지독한 축에 속한다. 전역 데이터는 코드베이스 어디에서든 건드릴 수 있고 값을 누가 바꿨는지 찾아낼 메커니즘이 없다는 게 문제다. 그래서 마치 '유령 같은 원격작용'처럼, 버그는 끊임없이 발생하는데 그 원인이 되는 코드를 찾아내기가 굉장히 어렵다. 전역 데이터의 대표적인 형태는 전역 변수 지만 클래스 변수와 싱글톤에서도 같은 문제가 발생한다.

이를 방지하기 위해 우리가 사용하는 대표적인 리팩터링은 변수 캡슐화하기다. 다른 코드에서 오염시킬 가능성이 있는 데이터를 발견할 때마다 이 기법을 가장 먼저 적용한다. 이런 데이터를 함수로 감싸는 것만으로도 데이터를 수정하는 부분을 쉽게 찾을 수 있고 접근을 통제할 수 있게된다.

가변 데이터

데이터를 변경했더니 예상치 못한 결과나 골치 아픈 버그로 이어지는 경우가 종종 있다. 코드의 다른 곳에서는 다른 값을 기대한다는 사실을 인식하지 못한 채 수정해버리면 프로그램이 오작동한다. 특히 이 문제가 아주 드문 조건에서만 발생한다면 원인을 알아내기가 매우 어렵다.

이런 이유로 함수형 프로그래밍에서는 데이터는 절대 변하지 않고, 데이터를 변경하려면 반드시 (원래 데이터는 그대로 둔 채) 변경하려는 값에 해당하는 복사본을 만들어서 반환한다는 개념을 기본으로 삼고 있다.

뒤엉킨 변경

뒤엉킨 변경은 단일 책임 원칙(SRP)이 제대로 지켜지지 않을 때 나타난다. 즉, 하나의 모듈이 서로 다른 이유들로 인해 여러 가지 방식으로 변경되는 일이 많을 때 발생한다.

예컨대 지원해야 할 데이터베이스가 추가될 때마다 함수 세 개를 바꿔야 하고, 금융 상품이 추가될 때마다 또 다른 함수 네 개를 바꿔야하는 모듈이 있다면 뒤엉킨 변경이 발생했다는 뜻이다. 데이터베이스 연동과 금융 상품 처리는 서로 다른 맥락에서 이뤄지므로 독립된 모듈로 분리해야 프로그래밍이 편하다. 그래야 무언가를 수정할 때 해당 맥락의 코드만 이해해도 진행할 수 있다.

산탄총 수술

산탄총 수술은 뒤엉킨 변경과 비슷하면서도 정반대다. 이 냄새는 코드를 변경할 때마다 자잘하게 수정해야 하는 클래스가 많을 때 풍긴다. 변경할 부분이 코드 전반에 퍼져 있다면 찾기도 어렵고 수정해야 할 곳을 지나치기 쉽다.

이럴 때는 함께 변경되는 대상들을 모두 한 모듈에 묶어두면 좋다. 우리는 작은 함수와 클래스에 지나칠 정도로 집착하지만, 코드를 재구성하는 중간 과정에서는 큰 덩어리로 뭉쳐지는데 개의치 않는다.

기능 편애

프로그램을 모듈화할 때는 코드를 여러 영역으로 모듈화 한 뒤 영역 내부에서 이뤄지는 상호작용은 최대한 늘리고 영역 사이에서 이뤄지는 상호작용은 최소로 줄이는데 주력한다.

모듈의 응집도는 높이고, 결합도는 줄이라는 말이다.

  • 응집도: 모듈 내부의 상호작용의 정도

  • 결합도: 모듈 사이(외부)의 상호작용의 정도

반복문

반복문은 프로그래밍 언어가 등장할 때부터 함께 한 핵심 프로그래밍 요소다. 하지만 이제는 1970년대에 유행하던 나팔바지나 솜털 무늬 벽지보다 못한 존재가 됐다.

지금은 일급 함수를 지원하는 언어가 많아졌기 때문에 반복문을 파이프라인으로 바꾸기 를 적용해서 시대에 걸맞지 않은 반복문을 제거할 수 있게 됐다. filtermap같은 파이프라인 연산을 사용하면 코드에서 각 원소들이 어떻게 처리되는지 쉽게 파악할 수 있다.

추측성 일반화

추측성 일반화는 '나중에 필요할거야'라는 생각으로 당장은 필요 없는 모든 종류의 hooking 포인트와 특이 케이스 처리 로직을 작성해둔 코드에서 생긴다. 그 결과는 관리하기 어려워진 코드다. 미래를 대비해 작성한 부분을 실제로 사용하게 되면 다행이지만, 그렇지 않는다면 쓸데없는 낭비일 뿐이다. 당장 걸리적거리는 코드는 눈앞에서 치워버리자.

주석

주석은 악취가 아닌 향기를 입힌다. 문제는 주석을 탈취제처럼 사용하는 데 있다. 주석이 장황하게 달린 원인이 코드를 잘못 작성했기 때문인 경우가 의외로 많다.

주석이 많으면 이 장에서 소개한 온갖 악취를 풍기는 코드가 나오기 쉽다. 실제로 악취가 너무 심해서 리팩터링으로 냄새를 걷어내고 봤더니 상당향의 주석이(애초에 코드만 제대로 작성했다면 필요 없음) 군더더기 였던 적이 많았다.

주석을 남겨야겠다는 생각이 들면, 가장 먼저 주석이 필요 없는 코드로 리팩터링 해본다.

뭘 할지 모를 때라면 주석을 달아두면 좋다. 현재 진행 상황뿐만 아니라 확실하지 않은 부분에 주석을 남긴다. 코드를 지금처럼 작성한 이유를 설명하는 용도로 달 수도 있다. 이런 정보는 나중에 코드를 수정해야 할 프로그래머에게, 특히 건망증이 심한 프로그래머에게 도움될 것이다.

0개의 댓글