Post

Code Smells

Code Smells

코드에 악취가 날 수 있는 상황들과 해결 방법들에 대해서 알아보자.


비대해진 것들 (Bloaters)


비대해진 것들은 너무 거대한 비율로 증가하여 작업하기 어려운 코드, 메서드 및 클래스이다. 일반적으로 이러한 악취는 바로 나타나지 않고, 프로그램이 발전함에 따라 시간이 지나면서 축적된다.

  • 긴 메서드 (Long Method)
  • 거대한 클래스 (Large Class)
  • 기본형 집착 (Primitive Obsession)
  • 긴 매개변수 목록 (Long Parameter List)
  • 데이터 덩어리 (Data Clumps)


긴 메서드 (Long Method)


징후와 증상


메서드가 10줄 이상의 코드를 포함한다.


문제의 원인


기존 메서드에 추가하는 것보다 새 메서드를 만드는 것이 더 어려우므로 기존 메서드에 코드가 계속해서 추가되어 스파게티 코드가 된다.


해결 방법


메서드에 대해 설명이 필요해질 경우 새 메서드로 분리해야 한다. 그리고 메서드에 설명적인 이름이 있으면, 해당 메서드가 무엇을 하는지 코드를 보지 않아도 된다.


메서드 길이를 줄이려면 메서드 추출을 사용해라.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 문제
void printOwing() {
  printBanner();

  // Print details.
  System.out.println("name: " + name);
  System.out.println("amount: " + getOutstanding());
}

// 해결
void printOwing() {
  printBanner();
  printDetails(getOutstanding());
}

void printDetails(double outstanding) {
  System.out.println("name: " + name);
  System.out.println("amount: " + outstanding);
}


지역 변수나 매개변수 때문에 메서드를 추출하기 어렵다면, 임시 변수를 질의로 바꾸기, 매개변수 객체 만들기, 객체 통째로 넘기기를 시도해라.


임시 변수를 질의로 바꾸기 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 문제
double calculateTotal() {
  double basePrice = quantity * itemPrice;
  if (basePrice > 1000) {
    return basePrice * 0.95;
  }
  else {
    return basePrice * 0.98;
  }
}

// 해결
double calculateTotal() {
  if (basePrice() > 1000) {
    return basePrice() * 0.95;
  }
  else {
    return basePrice() * 0.98;
  }
}
double basePrice() {
  return quantity * itemPrice;
}


매개변수 객체 만들기 예시

1
2
3
4
5
// 문제
Int amountInvoicedIn(start: Date, end: Date)

// 해결
Int amountInvoicedIn(date: DateRange)


객체 통째로 넘기기 예시

1
2
3
4
5
6
7
// 문제
int low = daysTempRange.getLow();
int high = daysTempRange.getHigh();
boolean withinPlan = plan.withinRange(low, high);

// 해결
boolean withinPlan = plan.withinRange(daysTempRange);


위 방법들이 모두 통하지 않는다면, 메서드를 메서드 객체로 바꾸기로 메서드 전체를 별도 객체로 옮기는 것도 방법이다.


메서드를 메서드 객체로 바꾸기 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 문제
class Order {
  // ...
  public double price() {
    double primaryBasePrice;
    double secondaryBasePrice;
    double tertiaryBasePrice;
    // Perform logn computation.
  }
}

// 해결
class Order {
  // ...
  public double price() {
    return new PriceCalculator(this).compute();
  }
}

class PriceCalculator {
  private double primaryBasePrice;
  private double secondaryBasePrice;
  private double tertiaryBasePrice;
  
  public PriceCalculator(Order order) {
    // Copy relevant information from the
    // order object.
  }
  
  public double compute() {
    // Perform long computation.
  }
}


조건문이나 반복문은 분리할 수 있다는 좋은 신호이다. 조건문에는 조건문 분해하기를, 반복문에는 메서드 추출을 적용해보자.


조건문 분해하기 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 문제
if (date.before(SUMMER_START) || date.after(SUMMER_END)) {
  charge = quantity * winterRate + winterServiceCharge;
}
else {
  charge = quantity * summerRate;
}

// 해결
if (isSummer(date)) {
  charge = summerCharge(quantity);
}
else {
  charge = winterCharge(quantity);
}


장점


코드 이해와 유지보수가 쉬워지고, 숨어있던 중복 코드를 찾기 쉽다.


객체 지향 남용 (Object-Orientation Abusers)


이 모든 악취는 객체 지향 프로그래밍 원칙의 불완전하거나 잘못된 적용이다.

  • 서로 다른 인터페이스를 가진 대안 클래스 (Alternative Classes with Different Interfaces)
  • 거부된 유산 (Refused Bequest)
  • Switch 문 (Switch Statements)
  • 임시 필드 (Temporary Field)


변경 방해자 (Change Preventers)


이러한 악취는 코드의 한 곳에서 무언가를 변경해야 하면 다른 여러 곳에서도 많은 변경을 해야 한다는 것을 의미한다. 그 결과 프로그램 개발이 훨씬 더 복잡하고 비용이 많이 든다.


불필요한 것들 (Dispensables)


불필요한 것은 무의미하고 불필요한 것으로, 그것이 없으면 코드가 더 깨끗하고 효율적이며 이해하기 쉬워진다.

  • 주석 (Comments)
  • 중복 코드 (Duplicate Code)
  • 데이터 클래스 (Data Class)
  • 죽은 코드 (Dead Code)
  • 게으른 클래스 (Lazy Class)
  • 추측성 일반화 (Speculative Generality)


결합자 (Couplers)


이 그룹의 모든 악취는 클래스 간의 과도한 결합에 기여하거나 결합이 과도한 위임으로 대체될 때 어떤 일이 발생하는지 보여준다.

  • 기능 욕심 (Feature Envy)
  • 부적절한 친밀함 (Inappropriate Intimacy)
  • 불완전한 라이프러리 클래스 (Incomplete Library Class)
  • 메시지 체인 (Message Chains)
  • 중개자 (Middle Man)


Reference


https://refactoring.guru/refactoring/smells

This post is licensed under CC BY 4.0 by the author.