본문 바로가기
독서에서 한걸음

Replace Derived Variable with Query, Combine Functions into Transform

by oncerun 2022. 12. 11.
반응형

Replace Derived Variable with Query

 

파생된 변수를 질의 함수로 변경하는 리팩터링 기술.

 

어디선가 계산되어서 만들어진 변수라는 것이다. 이는 소스 데이터를 기반으로 어떠한 작업을 통해 만들어진 변수를 말한다.

 

이러한 변수를 사용하는 부분을 함수로 변경하는 리팩터링이다.

 

변경할 수 있는 데이터, 변수를 줄이는 방법 중 하나이다. 

즉 계산식을 그대로 함수로 표현하여 변수를 줄이는 방법이라고 볼 수 있다. 

 

변수를 줄임으로서 계산 자체가 데이터의 의미를 잘 표현하지 못하는 경우를 방지하고, 어디선가 잘못된 값으로 수정될 수 있는 가능서울 제거할 수 있다.

 

계산에 필요한 데이터가 변하지 않는 값이라면, 계산의 결과에 해당하는 데이터 역시 불변 데이터이기 때문에 해당 변수는 그대로 유지할 수 있다.

 

public class Discount {

    private double discountedTotal;
    private double discount;

    private double baseTotal;

    public Discount(double baseTotal) {
        this.baseTotal = baseTotal;
    }

    public double getDiscountedTotal() {
        return this.discountedTotal;
    }

    public void setDiscount(double number) {
        this.discount = number;
        this.discountedTotal = this.baseTotal - this.discount;
    }
}

 

Discount의 discountedTotal이라는 필드는 baseTotal - discount의 값으로 만들어진 파생 변수라는 것을 확인할 수 있다.

 

@Test
void discount() {
    Discount discount = new Discount(100);
    assertEquals(100, discount.getDiscountedTotal());

    discount.setDiscount(10);
    assertEquals(90, discount.getDiscountedTotal());
}

 

다음 테스트는 버그가 존재한다. 

 

assertEquals(100, discount.getDiscountedTotal());

 

setDiscount()가 호출되기 이전에 해당 값을 가져오려 하는데 이 값이 설정되어 있지 않아 테스트를 통과하지 못한다. 

클라이언트가 setDiscount()를 해야 한다고 암기하고 사용할 수는 없는 입장이다.

 

따라서 이러한 변수를 제거해보자.

 

public class Discount {

    private double discount;

    private double baseTotal;

    public Discount(double baseTotal) {
        this.baseTotal = baseTotal;
    }

    public double getDiscountedTotal() {
        return this.baseTotal - this.discount;
    }

    public void setDiscount(double number) {
        this.discount = number;
    }
}

 

비슷한 코드를 보자.

 

public class ProductionPlan {

    private double production;
    private List<Double> adjustments = new ArrayList<>();

    public void applyAdjustment(double adjustment) {
        this.adjustments.add(adjustment);
        this.production += adjustment;
    }

    public double getProduction() {
        return this.production;
    }
}

 

이 코드는 Adjustment값이 추가될 때 배열에 넣고 production 필드에 값을 더해가는 코드이다. 

 

이 코드의 리팩터링도 마찬가지로 appliyAdjustment()할 때 추가하지 말고 getProduction()에서 계산하여 반환하도록 만들어보자.

 

public double getProduction() {
    return adjustments.stream()
            .mapToDouble(Double::valueOf)
            .sum();
}

 

 

Combine Functions into Transform

 

관련 있는 여러 파생 변수를 만들어내는 함수가 여러 곳에서 만들어지고 사용된다면 그러한 파생 변수를 변환 함수를 통해 한 곳으로 모아둘 수 있다.

 

아마 자주 사용되는 파생 변수를 포함한 별도의 클래스를 반환하게 하는 함수를 만들어서 사용하라는 말 같다. 

 

소스 데이터가 변경될 수 있는 경우에는 Combine Functions into Class를 사용하는 게 적절하다.

 

소스 데이터가 변경되지 않는 경우에는 두 가지 방법을 모구 사용할 수 있지만, 변환 함수를 사용해서 불변 데이터의 필드로 생성해 두고 재사용할 수 있다.

 

 

이는 여러 클래스에서 동일한 파생 변수를 사용하는 필드가 있다면 이를 하나의 레코드 ( Transform)을 만들어서 공통적으로 처리하도록 할 수 있다.

 

 

 

 

반응형

'독서에서 한걸음' 카테고리의 다른 글

Divergent Change  (0) 2022.12.14
Change Reference to Value  (0) 2022.12.11
Separate Query from Modifier && Remove Setting Method  (0) 2022.12.10
Split Variable  (0) 2022.12.05
변수 캡슐화  (0) 2022.12.04

댓글