코드에서 나는 악취

Minju Kim·2022년 12월 14일
28

리팩터링 2판

목록 보기
3/3
post-thumbnail
post-custom-banner

‘적용 방법’을 아는 것과 ‘제때 적용’할 줄 아는 것은 다르다. 리팩터링이 필요한, 때로는 아주 절실한 코드들에 일정한 패턴이 있다. 따라서 먼저 이 장을 읽고 코드가 풍기는 냄새(악취)가 무엇인지 찾자. 그런 다음 여러가지 리팩터링 기법을 찾아 읽고 그 냄새를 없애는 데 도움이 될지 생각해보도록 하자.

기본적인 악취

1. 기이한 이름

코드 이해력, 가독성 X

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

2. 중복 코드

실수와 에러 발생할 확률이 높아진다.

똑같은 코드 구조가 여러 곳에서 반복된다면 하나로 통합하여 더 나은 프로그램을 만들 수 있다. 코드가 중복되면 각각을 볼 때마다 서로 차이점은 없는지 주의 깊게 살펴봐야 하는 부담이 생긴다.

3. 긴 함수

이해하기 어려움, 재사용성 떨어짐

오랜 기간 잘 활용되는 프로그램들은 하나같이 짧ㅇ은 함수로 구성했다. 간접 호출의 효과, 즉 코드를 이해하고, 공유하고, 선택하기 쉬워진다는 장점은 함수를 짧게 구성할 때 나오느 것이다.

짧은 함수로 구성된 코드를 이해하기 쉽게 만드는 가장 확실한 방법은 좋은 이름이다. 함수 이름을 잘 지어두면 본문 코드를 볼 이유가 사라진다. 그러기 위해서는 훨씬 적극적으로 함수를 쪼개야 한다. 함수로 묶는 코드는 여러 줄일 수도 있고 단 한 줄일 수도 있다. 심지어 원래 코드보다 길어지더라도 함수로 뽑는다. 단, 함수 이름에 코드의 목적을 드러내야 한다.

4. 긴 매개변수 목록

사용하기 어려움, 잦은 실수

매개변수 목록이 길어지면 그 자체로 이해하기 어려울 때가 많다.

5. 전역 데이터

최악, 유령같은 버그 출몰

전역데이터는 악취 중 가장 지독한 축에 속한다. 유령같은 원격작용처럼, 버그는 끊임없이 발생하는데 그 원인이 되는 코드를 찾아내기가 굉장히 어렵다. 접근자 함수들을 클래스나 모듈에 집어넣고 그 안에서만 사용할 수 있도록 접근 범위를 최소로 줄이는 것도 좋다.

6. 가변 데이터

예상하지 못한 곳에서 데이터를 변경

데이터를 변경했더니 예상치 못한 결과나 골치 아픈 버그로 이어지는 경우가 종종 있다. 따라서 함수형 프로그래밍에서는 데이터는 절대 변하지 않고, 데이터를 변경하려면 반드시 변경하려는 값에 해당하는 복사본을 만들어서 반환한다는 개념을 기본으로 삼고 있다.

나쁜 냄새(고급레벨)

한 곳에서 너무 많은 일을 하거나, 여러 모듈이 다 엮여있는 경우

1. 뒤엉킨 변경(Divergent Change)

다양한 이유로 수정을 해야함

소프트웨어의 구조를 변경하기 쉬운 형태로 조직해야 한다. 코드를 수정할 때는 시스템에서 고쳐야 할 딱 한 군데를 찾아서 그 부분만 수정할 수 있기를 바란다. 다시 말해, 한 책임만 가지고 있는 모듈로 만들어야 한다. 뒤엉킨 변경은 단일 책임 원칙(Single Responsibility Principle)SRP가 제대로 지켜지지 않을 때 나타난다.

2. 산탄총 수술(Shotgun Surgery)

한 모듈/클래스/함수를 수정하면 다른 곳에서도 수정해야 한느 경우
코드를 변경할 때마다 자잘하게 수정해야 하는 클래스가 많을 때 나는 냄새이다.

3. 기능 편애(Feature Envy)

다른 모듈과 더 밀접하게 상호작용

프로그램을 모듈화 할 때는 코드를 여러 영역으로 나눈 뒤 영역 안에서 이뤄지는 상호작용은 최대한 늘리고, 영역 사이에서 이뤄지는 상호작용은 최소로 줄이는 데 주력한다. 디자인 패턴 중 전략 패턴, 방문자 패턴, 자기위임을 사용하면 뒤엉킨 변경 냄새를 없앨 수 있다. 가장 기본이 되는 원칙은 함께 변경할 대상을 한데 모으는 것이다.

4. 데이터 뭉치(Data Clumps)

여러곳에서 항상 함께 쓰임

데이터 항목은 서로 어울려 노는 것을 좋아한다. 몰려다니는 데이터 뭉치는 보금자리를 따로 마련해줘야 마땅하다.

5. 기본형 집착(Primitive Obsession)

관련된 코드가 여기저기

자신에게 주어진 문제에 딱 맞는 기초 타입(화폐, 좌표, 구간 등)을 직접 정의하기를 몹시 꺼리는 사람이 많다.

6. 반복되는 switch문(Repeated Switches)

새로운 타입이 추가되면 여기저기 업데이트

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

기타 냄새들

1. 반복문(Loops)

절차형의 코드 → 사이드 이펙

2. 성의 없는 요소(Lazy Element)

불필요한 함수, 클래스, 인터페이스

3. 추측성 일반화(Speculative Generality)

혹시 모르니, 미래를 위해서 써 놓은 코드

4. 임시 필드(Temporary Field)

특정한 상황에서만 사용됨, 이해도 낮음

5. 메세지 체인(Message Chains)

내부 로직이 노출됨

6. 중개자(Middle Man)

단순 전달만 하는 불필요한 코드

7. 내부자 거래(Insider Trading)

모듈 사이 데이터 거래 → 결합도 높아져 복잡해짐

8. 거대한 클래스(Large Class)

중복 코드 많아질 수 있으며, 뒤엉킨 변경이 일어날 수 있다.

9. 서로 다른 인터페이스의 대안 클래스들 (Alternative Classes with Different Interfaces)

비슷한 역할인데 인터페이스가 다른경우 → 서로 대체성이 낮아짐, 재사용성이 낮아짐.

10. 데이터 클래스(Data Class)

필요한 로직이 여기저기

11. 상속 포기(Refused Bequest)

상속의 오용, 남용은 위험함

12. 주석(Comments)

필요 없는 주석은 악!

profile
⚓ A smooth sea never made a skillful mariner
post-custom-banner

3개의 댓글

comment-user-thumbnail
2022년 12월 22일

좋은글 같아서 들어왔는데... 역시 '주'님...👍👍👍

답글 달기
comment-user-thumbnail
2022년 12월 23일

헐.. 너무 적용할게 많네요 ㅠㅠ 자주 보겠습니다

답글 달기
comment-user-thumbnail
2022년 12월 23일

정말 공감가는 글입니다.
제가 지양하는 개발들이 많이 나열되어 있네요 👍👍👍

답글 달기