9장, 데이터 조직화

2021.11.01

1. Split Variable, 변수 쪼개기

  • 참조 목적으로 쓰는 변수는 값을 한번만 대입하는 것이 좋다.
  • 역할이 둘 이상인 변수가 있다면 쪼개는 것이 좋다.

절차

  1. 변수를 선언한 곳과 값을 처음 대입하는 곳에서 변수 이름을 바꾼다.
  2. 가능하면 이때 불변으로 선언한다.
  3. 이 변수에 두 번째로 값을 대입하는 곳 앞까지의 모든 참조(이 변수가 쓰인 곳)를 새로운 변수 이름으로 바꾼다.
  4. 두 번째 대입 시 변수를 원래 이름으로 다시 선언한다.
  5. 테스트.
  6. 반복한다. 매 반복에서 변수를 새로운 이름으로 선언하고 다음번 대입 때까지의 모든 참조를 새 변수명으로 바꾼다. 마지막 대입까지 반복.

예시

before

let temp = 2 * (height + width);
console.log(temp);
temp = height * width;
console.log(temp);

after

const perimeter = 2 * (height + width);
console.log(perimeter);
const area = height * width;
console.log(area);

2. Rename Field, 필드 이름 바꾸기

  • 데이터 필드의 이름은 데이터 구조와 프로그래밍을 이해하는데 큰 도움을 준다.

절차

  1. 레코드의 유효 범위가 제한적이라면 필드에 접근하는 모든 코드를 수정한후 테스트한다. 이후 단계는 필요 없다.
  2. 레코드가 캡슐화되지 않았다면 우선 레코드를 캡슐화한다.
  3. 캡슐화된 객체 안의 private 필드명을 변경하고, 그에 맞게 내부 메서드들을 수정한다.
  4. 테스트.
  5. 생성자의 매개변수 중 필드와 이름이 겹치는게 있따면 함수 선언 바꾸기로 변경한다.
  6. 접근자들의 이름을 바꿔준다.

예시

before

class Organization {
  get name() {...}
}

after

class Organization {
  get title() {...}
}

3. Replace Derived Variable with Query, 파생 변수를 질의 함수로 바꾸기

  • 가변 데이터의 유효범위를 가능한 좁히는 노력을 하면 좋다.
  • 값을 쉽게 계산해낼 수 있는 변수들을 제거하고, 계산 과정을 보여주는 함수를 만드는 방법으로 대신하자.

절차

  1. 변수 값이 갱신되는 지점을 모두 찾는다. 필요하면 변수 쪼개기를 활용해 각 갱신 지점에서 변수를 분리한다.
  2. 해당 변수의 값을 계산해주는 함수를 만든다.
  3. 해당 변수가 사용되는 모든 곳에 어서션을 추가하여 함수의 게산 결과가 변수의 값과 같은지 확인한다.
  4. 테스트.
  5. 변수를 읽는 코드를 모두 함수 호출로 대체한다.
  6. 테스트.
  7. 변수를 선언하고 갱신하는 코드를 죽은 코드 제거하기로 없앤다.

예시

before

get discountedTotal() {return this._discountedTotal}
set discount(aNumber) {
  const old = this._discount
  this._discount = aNumber
  this._discountedTotal += old - aNumber
}

after

get discountedTotal() {return this._discountedTotal}
set discount(aNumber) {this._discount = aNumber;}

4. Change Reference to Value, 참조를 값으로 바꾸기

  • 객체를 다른 객체에 중첩하면 내부 객체를 참조 혹은 값으로 취급 할 수 있다.
  • 값으로 활용하는 경우에 데이터를 갱신할 때는 내부객체를 통째로 대체한다.
    • 값 객체를 불변으로 활용할 수 있어서 좋다.
    • 분산 시스템과 동시성 시스템에서 유용하다.
    • 특정 객체를 여러 객체에서 공유하고 있다면, 값 객체가 아닌 참조 객체로 활용해야 한다.

절차

  1. 후보 클래스가 불변인지 혹은 불변이 될 수 있는지 확인한다.
  2. 각각의 세터를 하나씩 제거한다.
  3. 이 값 객체의 필드들을 사용하는 동치성 비교 메서드를 만든다.

예시

before

class Product {
  applyDiscount(arg) {
    this._price.amount -= arg;
  }
}

after

class Product {
  applyDiscount(arg) {
    this._price = new Money(this._price.amount - arg, this._price.currency);
  }
}

5. Change Value to Reference, 값을 참조로 바꾸기

  • 하나의 데이터 구조 안에 논리적으로 제 3의 데이터 구조를 참조하는 레코드가 여러 개 있을 때가 있다.

    • 예를 들어 주문 목록을 읽다 보면 같은 고객이 요청한 주문이 여러 개 섞여 있을 수 있다.
    • 이때 고객을 값으로도, 혹은 참조로도 다룰 수 있다.
    • 고객 데이터를 갱신할 일이 없다면 어느 방식이든 상관 없다.
  • 논리적으로 같은 데이터를 물리적으로 복제해 사용할 때, 데이터 사용을 값이 아닌 참조로 바꾼다면 데이터 갱신시 편리하다.

절차

  1. 같은 부류에 속하는 객체들을 보관할 저장소를 만든다. (이미 있다면 생략)
  2. 생성자에서 이 부류의 객체들 중 특정 객체를 정확히 찾아내는 방법이 있는지 확인한다.
  3. 호스트 객체의 생성자들을 수정하여 필요한 객체를 이 저장소에서 찾도록 한다. 하나 수정할 때마다 테스트.

예시

before

let customer = new Customer(customerData);

after

let customer = customerRepository.get(customerData);

6. Replace Magic Literal, 매직 리터럴 바꾸기

  • 매직 리터럴이란 소스 코드에 등장하는(보통은 여러 곳에) 일반적인 리터럴 값을 말한다.
    • 예를 들어 3.14라는 원주율을 적절한 이름을 가지고 있는 상수로 만들어 코드에서 참조할 수 있게 하자.

절차

  1. 상수를 선언하고 매직 리터럴을 대입한다.
  2. 해당 리터럴이 사용되는 곳을 모두 찾는다.
  3. 찾은 곳 각각에서 리터럴이 새 상수와 똑같은 의미로 쓰였는지 확인하여, 같은 의미라면 상수로 대체한 후 테스트.

예시

before

function potentialEnergy(mass, height) {
  return mass * 9.81 * height;
}

after

const STANDARD_GRAVITY = 9.81;
function potentialEnergy(mass, height) {
  return mass * STANDARD_GRAVITY * height;
}