프로그래밍

[레거시 코드 활용 전략] ch12. 클래스 의존 관계, 반드시 없애야할까?

Victory_HA 2024. 1. 2. 23:55

https://gist.github.com/jonnyjava/42883d4e464167f81e2ee60a488a5ded
https://namhoon.kim/2022/03/22/method-test/012/

  • 테스트 하려는 코드에 의존관계가 존재한다면, 테스트 코드 작성이 까다로워진다.
    • 이때마다 의존 관계를 제거해줘야하는것인가? 무조건 제거는 답이 아니다.
  • 테스트는 세부적인 코드를 매번 해줘야하는가?
    • 어떤 코드를 테스트를 할 때,
    • 상위 수준의 코드에서 테스트가 커버 된다면 할 필요는 없다.

교차지점 (Interception Point)

  • 일반적으로 변경 지점에 가까운 지점
  • 클래스의 변경이 발생하는 곳
public class Invoice
{
...
    public Money GetValue()
    {
        Money total = ItemsSum();

        if (BillingDate > Date.YearEnd(OpeningDate))
        {
            if (OriginatorState == OriginatorState.FL || OriginatorState == OriginatorState.NY)
            total.Add(GetLocalShipping());
         else
            total.Add(GetDefaultShipping());
        }
        else
        {
            total.Add(GetSpanningShipping());
        }

        total.Add(GetTax());
        return total;
    }
}
  • 뉴욕으로 보내지는 운송 비용의 계산 로직을 변경해야한다.
  • 세법 변경으로 세금을 추가하여 계산해야한다.
public class Invoice
{
    private ShippingPricer shippingPricer;
    public Invoice()
    {
        shippingPricer = new ShippingPricer();
    }
...

public Money GetValue()
{
    Money total = ItemsSum();
    total.Add(shippingPricer.GetPrice());
    total.Add(GetTax());
    return total;
}
  • 계산 로직 부분 추출 후 ShippingPricer 클래스를 작성했다.

UML

  • ShippingPricer객체는 Invoice 생성자에서 생성
  • Invoice클래스에서 GetValue()를 호출
  • ShippingPricer객체는 BillingState.makeStatement() 호출

교차지점 선정하기

  • shippingPricer 변수를 사용하여 테스트 : private변수이므로 접근할 수 없음.
  • BillingStatement 클래스의 makeStatement() 메서드 테스트 코드 작성 가능,
    • but, makeStatement()에 영향을 미치는 상위코드인 GetValue()를 테스트하는게 좋다.

조임지점 (Pinch Point)

  • 조임지점이란, 몇 개의 메서드에 대한 테스트로도 많은 메서드의 변경을 감지할 수 있는 지점
  • 운영 비용의 계산 방법을 변경하고, 운송 업체를 관리하기 위한 필드를 포함하도록 Item 클래스를 변경해야 한다고 가정한다.
  • BillingStatement 클래스에서 운송 업체별로 구별하여 처리할 수 있도록 조건을 추가한다.

// 상위 수준의 교차지점이 발견될 때 장점
- 의존 관계를 많이 제거할 필요 없음
- 코드를 묶음 단위로 취급할 수 있다. (상위 수준의 코드만 테스트하기 때문에..)

테스트 코드

void testSimpleStatement() {
  Invoice invoice = new Invoice();
  invoice.addItem(new Item(0, new Money(10)); 
  BillingStatement statement = new BillingStatement(); 
  statement.addInvoice(invoice);
  assertEquals("", statement.makeStatement());
}
  • makeStatement()를 호출하기 위해선, 위의 프로세스가 필요하다.

  • 결국, makeStatement() 메서드가 모든 변경이 일어나면 최종적으로 영향을 감지할 수 있는 유일한 곳 => 조임 지점(pinch point)