Search

Chapter03 - 코드의 구린내

중복 코드

한 클래스의 두 메서드 안에 같은 코드가 들어있는 경우 → 메서드 추출
한 클래스의 두 하위 클래스에 같은 코드가 있는 경우 → 메서드 추출 후 상향
경우에 따라 템플릿 메서드 형성을 시도
중복 코드가 메서드 가운데에 있다면 주변 메서드 추출을 해보자.
서로 상관없는 두 클래스 안에 중복 코드가 있을 때는 한 클래스 안의 중복 코드를 클래스 추출이나 모듈 추출을 적용해 제 3의 클래스나 모듈로 떼어낸 후 그것을 다른 클래스에서 호출하는 방법 or 메서드를 떼서, 클래스 간에 메시지를 전달.

장황한 메서드

짧은 메서드를 쓰려면, 기본적으로 메서드명을 잘 정해야한다.
메서드명은 기능 수행 방식이 아니라 목적을 나타내는 이름으로 정함.
이를 위해서는 메서드를 훨씬 과감하게 쪼개야 함.
메서드에 매개변수와 임시변수가 많으면 메서드 추출을 실시하기가 까다로움. → 수많은 매개변수와 임시변수를 새로 만든 메서드의 매개변수로 넘겨야한다. 가독성 안 좋음
따라서 임시 변수를 메서드 호출로 전환하던가, 임시변수를 메서드 체인으로 전환하도록.
긴 매개변수는 매개변수 세트를 객체로 전환, 객체를 통째로 전달해보자
이래도 임시변수와 매개변수가 너무 많을 때는 메서드를 메서드 객체로 전환하는 기법을 사용해보자.
조건문과 루프도 메서드로 빼야함.
조건문을 추출하려면 조건문 쪼개기
루프를 컬렉션 클로저 메서드로 전환을 실시한 후, 클로저 메서드 호출과 클로저 자체에 메서드 추출을 실시

방대한 클래스

인스턴스 변수가 너무 많으면 중복 코드가 존재하기 마련이다.
클래스 추출, 연관되있는 변수를 골라 클래스로 빼내자.
클래스 안의 일부 변수가 접두어나 접미어가 같다면 하나의 클래스로 추출해보자.
하위클래스가 적절한거 같으면 하위클래스 추출을, 추출할 클래스가 대리자로 부적절할 거 같으면 모듈 추출을 하면 됨.

과다한 매개변수

원래는 필요한 모든 걸 매개변수로 전달해야했는데, 이제는 다른 객체에게 요청하면 된다.
따라서 모든 데이터를 전달하는 것보다, 모든 데이터를 가져올 수 있는 메서드만 전달하면 됨.
사용 가능한 방법, 매개변수 세트를 메서드로 전환, 객체를 통째로 전달, 매개변수 세트를 객체로 전환
예외적으로 호출되는 객체가 호출 객체에 의존하면 안 될 때

수정의 산발

한 클래스가 다양한 원인 때문에 다양한 방식으로 자주 수정될 때
새 데이터베이스를 생성할 때마다 이 3개의 메서드를 수정해야하고, 새 금융 상품을 추가할 때마다 4개의 메서드를 수정해야하네 라는 생각이 든다면, 여러 개의 변형 객체로 분리하는 것이 좋다.

기능의 산재

수정의 산발과 비슷하지만 정 반대
수정할 때 여러 클래스에서 수많은 자잘한 부분을 고쳐야한다면 이 문제를 의심.
수정할 부분이 여기 저기 있다면 힘들다.
메서드 이동, 필드 이동을 적용해서 수정할 부분들을 전부 하나의 클래스로 넣어야함.

잘못된 소속

객체의 핵심 - 데이터와 그 데이터에 사용되는 프로세스를 한 데 묶는 기술
어떤 메서드가 자신이 속하지 않은 클래스에 더 많이 접근한다면 잘못된 소속의 구린내가 풍긴다.
소속이 잘못된 메서드가 흔히 접근하는 대상은 데이터
다른 객체 있는 읽기 메서드를 자주 호출한다면, 더 자주 접근하는 클래스로 옮겨야하지 않을까?
메서드 이동을 하거나, 메서드의 일부분만 소속이 잘못됬다면, 메서드를 추출후에 메서드 이동을 시킨다.

데이터 뭉치

동일한 데이터 항목이 여러 위치에 몰려 있을 수 있다.
몰려 있다면 객체로 만들어야한다.
필드들을 대상으로 클래스 추출 기법

강박적 기본 타입 사용

기본 타입은 아무런 기능도 제공하지 못한다. 돈이나 우편 번호 등도 객체로 전환해 관리하면 더 편한다.

switch 문

객체 지향 코드에서는 switch-case 문이 적게 사용된다.
switch문은 무조건 중복을 발생시킨다.
객체지향의 재정의를 사용하는게 무조건 좋다.
switch 문은 고민할 필요없이 재정의로 바꿔야한다.
switch 문을 돌릴 데이터가 필요한데, 이 값은 메서드나 클래스 안에 들어가 있을 것.
메서드 추출을 실시해서 switch문을 일단 메서드로 빼내고, 분류 부호가 있는 클래스로 메서드를 이동한 다음
분류부호를 하위 클래스로 전환하고, 상태/전략 패턴으로 전환한다.
상속 구조라면 조건문을 재정의로 전환
하나의 메서드에 영향을 미치는 case문이 2~3개 밖에 없고, 나중에 모든 case문을 수정할 일이 없으면 재정의로 전환하는 건 과하다.
매개변수를 메서드로 변환하는 것이 낫다.
조건문이 있는 여러 case문 중 하나가 널일 때는 Null 검사를 널 객체에 위임을 실시하면 된다.

평행 상속 계층

기능의 산재의 특수한 상황
한 클래스의 하위 클래스를 만들 때마다, 매번 다른 클래스의 하위 클래스도 만들어야한다.
서로 다른 두 상속 계층의 클래스명 접두어가 같으면 이 문제를 의심할 수 있다.

직무유기 클래스

비용 대비 효율성이 떨어진다면 제거해야 함.
하위 클래스나 모듈의 경우에는 계층 병합해야함.

막연한 범용 코드

아직은 필요 없는 기능을 수행하고자 온갖 호출과 case문을 넣으려하는 순간 범용 코드의 구린내가 풍긴다.
별다른 기능이 없는 클래스나 모듈은 계층 병합
불필요한 위임을 제거하려면 클래스 내용 직접 삽입
메서드에 사용되지 않은 매개변수가 있으면 매개변수 제거
메서드명이 이상하다면 메서드명 변경

임시 필드

특정 상황에서만 할당되는 필드가 있으면 안 된다.
떠돌이 변수들을 마련해주려면 클래스 추출을 실시
Null 검사를 널 객체에 위임을 실시해서 그 변수들의 값이 올바르지 않을 경우를 대비한 대체 컴포넌트 작성하면 경우에 따라 조건문 삭제 가능

메시지 체인

메시지 체인은 클라이언트가 1번에게, 1번이 2번에게, 2번이 3번에게 객체를 요청하는 연쇄적 요청을 얘기함.
그 사이의 관계들을 수정할 때마다 클라이언트도 수정된다.
대리 객체 은폐를 실시해야함. ⇒ 일단은 보기에 체인을 끊어내는게 목적인듯.

과잉 중개 메서드

어떤 클래스의 인터페이스를 보니, 절반도 넘는 메서드가 기능을 다른 클래스에 위임한다면 실시하자.
가능한 방법들
과잉 중개 메서드 제거 ⇒ 원리가 구현된 객체에 직접 접근
메서드들의 내용을 호출 객체에 직접 삽입해도 된다.
부수적인 기능이 있다면 위임을 상속으로 전환 기법을 사용

지나친 관여

지나치게 밀접한 나머지, 서로의 private을 알아내느라 과도한 시간 낭비를 할 때가 있다.
메서드 이동과 필드 이동을 실시해서 관여를 끊어놔야함.
클래스의 양방향 연결을 단방향으로 전환
공통으로 필요한 부분이 있다면, 클래스 추출을 사용해서 별도의 안전한 클래스로 빼내면 됨.
대리 객체 은폐를 실시하여 중계 메서드 역할을 하게 만들어도 됨.
상속으로 인해 지나친 관여가 발생하는 경우가 많다. 상위클래스에서 하위 클래스를 빼내야할 경우에는 상속을 위임으로 전환 기법을 적용하자.

인터페이스가 다른 대용 클래스

기능은 같은데 시그니처가 다른 메서드에는 메서드명 변경을 실시

미흡한 라이브러리 클래스

라이브러리 클래스에 넣어야할 메서드가 두 개뿐이라면 외래 클래스에 메서드 추가 기법을 실시
부가 기능이 많다면 국소적 상속확장 클래스 사용 기법을 실시

데이터 클래스

필드와 읽기,쓰기 메서드만 들어있는 클래스
오직 데이터 보관만 담당한다.
필드 캡슐화를 진행하자. 컬렉션 필드가 있으면 그 필드가 적절히 캡슐화되어있는지 확인하여 캡슐화되어있지 않다면 컬렉션 캡슐화 기법을 적용.
또는 쓰기 메서드 제거를 적용
또는 메서드 이동을 실시하여 기능을 그 데이터 클래스로 이동.
메서드 전체를 옮길 수 없다면 메서드 추출을 실시해서 옮길 수 있는 것만 이동

방치된 상속물

상속을 받았으나 사용하지 않는 경우
잘못된 계층 구조 때문이라고 설명할 수 있고, 메서드 하향, 필드 하향을 실시해서 합쳐야 함.

불필요한 주석

주석은 불필요하다. 주석이 없이도 설명가능해야함.