[Refactoring] # 여러 함수를 클래스로 묶기

mechaniccoder·2021년 9월 30일
0
post-thumbnail

하나의 데이터를 놓고 관련된 작동을 하는 함수를 하나의 클래스로 묶어주자. 이러면 함수들이 공유하는 환경을 명확하게 표현할 수 있다.

Code

before

// 레코드를 캡슐화해야 한다.
const reading = {
  customer: "seunghwan",
  quantity: 10,
  month: 5,
  years: 2021,
};

const acquireReading = () => {};

// client1
const aReading = acquireReading();

// baseCharge를 getter를 통해 필요할때 계산되게 해야 한다.
const base = baseRate(aReading.month, aReading.year) * aReading.quantity;

// client2
const aReading = acquireReading();

// basecharge의 계산 로직이 반복되고 있다.
const base = baseRate(aReading.month, aReading.year) * aReading.quantity;
const taxablecharge = Math.max(0, base - taxThreshold(aReading.year));

// client3
const aReading = acquireReading();
// 여기서만 baseCharge를 함수로 호출하고 있다.
const basicChargeAmount = calculateBaseCharge(aReading);

function calculateBaseCharge(aReading) {
  return baseRate(aReading.month, aReading.year) * aReading.quantity;
}

위의 코드를 보면, aReading이라는 데이터를 중심으로 2가지의 동작을 클래스의 메서드로 묶어줄 수 있다.

1. baseCharge 계산하는 함수
2. taxableCharge 계산하는 함수

각각을 클래스의 getter로 선언해 사용하는 곳에서는 객체의 프로퍼티로 접근해 결과를 얻을 수 있다.

after

// 1. 먼저 레코드를 캡슐화해주자.
class Reading {
  constructor(data) {
    this._customer = data.customer;
    this._quantity = data.quantity;
    this._month = data.month;
    this._year = data.year;
  }

  get customer() {
    return this._customer;
  }

  get quantity() {
    return this._quantity;
  }
  get month() {
    return this._month;
  }
  get year() {
    return this._year;
  }
  // 2. calculateBaseCharge함수를 클래스 안으로 옮긴 뒤에, 함수 이름을 변경한다.
  get baseCharge() {
    return baseRate(this.month, this.year) * this.quantity;
  }

  get taxableCharge() {
    return Math.max(0, this.baseCharge - taxThreshold(aReading.year));
  }
}

// client3
const rawReading = acquireReading();
const aReading = new Reading(rawReading); // 데이터를 얻은 뒤에, 바로 객체를 만들어주자.
const basicChargeAmount = aReading.baseCharge;

// 위의 Reading클래스를 재사용해서 client1, client2에서 중복되는 코드를 제거한다.

// client1
const rawReading = acquireReading();
const aReading = new Reading(rawReading);
const baseCharge = aReading.baseCharge;

// client2
const rawReading = acquireReading();
const aReading = new Reading(rawReading);
const taxableCharge = Math.max(
  0,
  aReading.baseCharge - taxThreshold(aReading.year)
);

// client2 - extract function
// 세금 계산 코드를 함수로 추출하자.
function taxableCharge(aReading) {
  return aReading.baseCharge - taxThreshold(aReading.year);
}

// client2
const taxableCharge = taxableCharge();

// taxableCharge도 클래스의 메서드로 추출하자.

// client2

const taxableCharge = aReading.taxableCharge;

/**
 *  getter를 활용해 필요한 시점에 계산해서 클라이언트에 데이터를 전달하도록 했는데,
 *  이것의 장점은 데이터가 갱신된다고 하더라도, 계산해서 데이터를 제공하기 때문에 안정적이다.
 * */

소감

데이터를 중심으로 연관된 동작을 하는 함수들을 데이터와 함께 클래스로 묶어준다. 이로 인해 응집도를 높일 수 있는 리팩토링이라고 생각한다. 그리고 계산된 로직으로 결과값을 반환함으로써 데이터가 변경되더라도 안정적인 결과를 반환한다는 말에 깊이 공감했다.

Reference

  • Refactoring: Improving the Design of Existing Code (2nd Edition) p202-207.
profile
세계 최고 수준을 향해 달려가는 개발자입니다.

0개의 댓글