Code Smell 02.

코드에서 나는 악취 목록

by Dichter

7. Divergent Change

소프트웨어의 구조를 변경하기 쉬운 형태로 조직해야 한다. 소프트웨어는 자고로 소프트해야 마땅하기 때문이다. 코드를 수정할 때는 시스템에서 고쳐야 할 딱 한 군데를 찾아서 그 부분만 수정할 수 있기를 바란다. 이렇게 할 수 없다면 (서로 밀접한 악취인) Divergent Change와 Shotgun Surgery 중 하나가 풍긴다.

뒤엉킨 변경은 단일 책임 원칙(Single Responsibility Princicple, SRP)이 제대로 지켜지지 않을 때 나타난다. 즉, 하나의 모듈이 서로 다른 이유들로 인해 여러 가지 방식으로 변경되는 일이 많을 때 발생한다. 예컨대 지원해야 할 데이터베이스가 추가될 때마다 함수 세 개를 바꿔야 하고, 금융상품이 추가될 때마다 또 다른 함수 네 개를 바꿔야 하는 모듈이 있다면 뒤엉킨 변경이 발생했다는 뜻이다. 데이터베이스 연동과 금융 상품 처리는 서로 다른 맥락에서 이뤄지므로 독립된 모듈로 분리해야 프로그래밍이 편하다. 그래야 무언가를 수정할 때 해당 맥락의 코드만 이해해도 진행할 수 있다. 이렇게 분리하는 일이 중요함을 예전부터 알고 있었지만 나이를 먹어 두뇌 회전이 느려지는 요즘에는 더더욱 중요한 일이 돼버렸다. 개발 초기에는 맥락 사이의 경계를 명확히 나누기가 어렵고 소프트웨어 시스템의 기능이 변경되면서 이 경계도 끊임없이 움직이기 때문이다.

데이터베이스에서 데이터를 가져와서 금융 상품 로직에서 처리해야 하는 일처럼 순차적으로 실행되는 게 자연스러운 맥락이면, 다음 맥락에 필요한 데이터를 특정한 데이터 구조에 감아 전달하는 식으로 단계를 분리한다. 전체 처리 과정 곳곳에서 각기 다른 맥락의 함수를 호출하는 빈도가 높다면, 각 맥락에 해당하는 적당한 모듈들을 만들어서 관련 함수들을 모은다.


8. Shotgun Surgery

산탄총 수술은 뒤엉킨 변경과 비슷하면서도 정반대다.

이 냄새는 코드를 변경할 때마다 자잘하게 수정해야 하는 클래스가 많을 때 풍긴다. 변경할 부분이 코드 전반에 퍼져 있다면 찾기도 어렵고 꼭 수정해야 할 곳을 지나치기 쉽다.

이럴 때는 함께 변경되는 대상들의 함수나 필드를 옮겨 모두 한 모듈에 묶어두면 좋다. 비슷한 데이터를 다루는 함수가 많다면 여러 함수를 클래스로 묶는다. 데이터 구조를 변환하거나 보강하는 함수들은 변환 함수로 묶자.


9. Feature Envy

기능 편애는 흔히 어떤 함수가 자기가 속한 모듈의 함수나 데이터보다 다른 모듈의 함수나 데이터와 상호작용할 일이 더 많을 때 풍기는 냄새다. 우리는 실행 과정에서 외부 객체의 게터 메서드 대여섯 개를 호출하도록 작성된 함수를 수없이 봤다. 다행히 해결하기는 쉽다. 이 함수가 데이터와 가까이 있고 싶어 한다는 의중이 뚜렷이 드러나므로 소원대로 데이터 근처로 옮겨주면 된다. 때로는 함수의 일부에서만 기능을 편애할 수 있다. 이럴 때는 그 부분만 독립 함수로 빼낸 다음 원하는 모듈로 보내준다.


10. Data Clumps

데이터 항목들은 어린아이 같은 면이 있다. 서로 어울려 노는 걸 좋아한다. 그래서 데이터 항목 서너 개가 여러 곳에서 항상 함께 뭉쳐 다니는 모습을 흔히 목격할 수 있다. 클래스 두어 개의 필드에서, 혹은 여러 메서드의 시그니처에서 함께 발견되기도 한다. 이렇게 몰려다니는 데이터 뭉치는 보금자리를 따로 마련해줘야 한다.

가장 먼저 필드 형태의 데이터 뭉치를 찾아서 클래스로 추출하여 하나의 객체로 묶는다. 다음은 메서드 시그니처에 있는 데이터 뭉치 차례다. 먼저 매개변수들을 객체로 만들거나 객체를 통째로 넘기는 방법을 적용해서 매개변수 수를 줄여본다. 그 즉시 메서드 호출 코드가 간결해질 것이다. 데이터 뭉치가 앞에서 새로 만든 객체의 필드 중 일부만 사용하더라도 걱정할 필요 없다. 새 객체로 뽑아낸 필드가 두 개 이상이기만 해도 확실히 예전보다 나아지기 때문이다.

데이터 뭉치인지 판별하려면 값 하나를 삭제해보자. 그랬을 때 나머지 데이터만으로는 의미가 없다면 객체로 환생하길 갈망하는 데이터 뭉치라는 뜻이다.


11. Primitive Obsession

대부분의 프로그래밍 언어는 정수, 부동소수점 수, 문자열 같은 다양한 기본형을 제공한다. 라이브러리를 통해 날짜 같은 간단한 객체를 추가로 제공하기도 한다.

이 냄새는 문자열을 다루는 코드에서 특히 흔하다. 전화번호를 단순히 문자 집합으로만 표현하기엔 아쉬움이 많다. 최소한 사용자에게 보여줄 때는 일관된 형식으로 출력해주는 기능이라도 갖춰야 한다. 이런 자료형들을 문자열로만 표현하는 악취는 아주 흔해서, 소위 '문자열화된' 변수라는 이름까지 붙었다.


12. Repeated Switches

순수한 객체 지향을 신봉하는 사람들과 이야기하다 보면 주제는 곧 switch문의 사악함으로 흘러가기 마련이다. 이들은 코드에 등장하는 switch문은 모조리 다형성을 이용하여 없애야 할 대상이라고 주장한다. 하지만 분기 조건에 몇 가지 기본형만 쓸 수 있던 예전과 달리, 문자열 등의 더 복잡한 타입까지 지원하는 발전된 switch문을 제공하는 언어도 많아졌다. 그러니 이제는 똑같은 조건부 로직(switch/case문이나 길게 나열된 if/else문)이 여러 곳에서 반복해 등장하는 코드에 집중해보자.

중복된 switch문이 문제가 되는 이유는 조건절을 하나 추가할 때마다 다른 switch문들도 모두 찾아서 함께 수정해야 하기 때문이다. 이럴 때 다형성은 반복된 switch문이 내뿜는 사악한 기운을 제압하여 코드 베이스를 최신 스타일로 바꿔주는 세련된 무기인 셈이다.

작가의 이전글Code Smell 01.