[리펙터링 2판] 9장 - 데이터 조직화
도서

[리펙터링 2판] 9장 - 데이터 조직화

반응형

  하나의 값이 여러 목적으로 사용된다면 혼란과 버그를 낳는다. 9.1절 변수 쪼개기를 적용해 용도별로 분리하고, 변수 이름 바꾸기(6.7절)을 친해지도록 하며, 파생 변수를 질의 함수로 바꾸기(9.3절)를 활용하여 변수 자체를 완전히 없애는게 해법일 때도 있다. 결국 이 장에서 말하고자 하는 바는 나눠서 잘 담아야 하는 이야기이다.

 

  예를 들어, 요리를 할 때 재료들을 한 바구니에 담지 않고 여러가지 재료들을 여러가지 그릇에 담는게 일반적이다.

요리를 할 줄 아는 사람에게 재료를 주어야 할 경우가 있다고 가정하였다. 그러면 한 바구니 안에 모든걸 담았을 때, 한 바구니 안에있는 재료들로 어떤 요리를 할지 감이 잡히지 않을 것이다. 재료가 많고 복잡한 요리일 수록 더욱 그러할께 뻔하다. 하지만 반대 경우가 되었을 시 재료들만 보고 어떤 요리를 할지 흐름을 이해할 수 있는 것과 비슷하다고 생각한다.

 

 

9.1 변수 쪼개기

내용

  • 하나의 변수에 두개 이상의 역할이 있다면 해당 변수를 나눠준다.

적용

  • 역할 하나당 변수 하나
  • 여러 용도로 쓰인 변수는 코드를 읽는 이에게 혼란을 줌

결과

  • 코드 가독성과 버그를 최소화한다.

예시

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);

 

9.2 필드 이름 바꾸기

내용

  • 데이터 구조는 프로그램을 이해하는데 큰 역할을 하기 때문에 필드 이름은 중요하다

적용

  • 개발을 진행할수록 데이터를 더 잘이해하게되고 그 깊어진 이해를 프로그램에 반영해야 한다.
  • 게터와 세터 메서드는 클래스 사용자 입장에서는 필드와 다를바 없기 때문에 구조체의 필드 이름 바뀌기와 똑같이 중요하다.

결과

  • 프로그램 전반적으로 이해하기 쉬워진다.

예시

Before

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

After

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

 

리펙터링 도중 테스트에 실패한다면 더 작은 단계로 나눠 진행해야 한다는 신호

 

9.3 파생 변수를 질의 함수로 바꾸기

내용

  • 가변 데이터는 소프트웨어에 문제를 일으키는 가장 큰 골칫거리에 속한다.
  • 가변 데이터의 유효 범위를 가능한 좁혀야 한다.

적용

  • 값을 쉽게 계산해낼 수 있는 변수들은 제거한다 
  • 예외는 피연산자 데이터가 불변이라면 계산결과도 일정하기에 그대로 두는것도 좋다.
  • 1. 데이터 구조를 감싸며 그 데이터에 기초하여 계산한 결과를 속성으로 제공하는 객체
  • 2. 데이터 구조를 받아 다른 데이터 구조로 변환해 반환하는 함수

결과

  • 계산 과정을 보여주는 코드 자체가 데이터의 의미를 분명히 드러내는 경우도 자주 있으며 변경된 값을 깜빡하고 결과 변수에 반영하지 않는 실수를 막아준다.
  • 코드 자체가 데이터의 의미를 더 분명히 드러낸다
  • 변경된 값을 실수로 결과 변수에 반영하지 않는 등의 실수를 방지한다

예시

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._baseTotal - this._discount;}
  set discount(aNumber) {this._discount = aNumber;}

 

 

9.4 참조를 값으로 바꾸기

내용

  • 객체(데이터 구조)를 다른 객체(데이터 구조)에 중첩하면 내부 객체를 참조 혹은 값으로 취급 할 수 있다.
  • 참조로 다루는 경우에는 내부 객체는 그대로 둔 채 그 객체의 속성만 갱신
  • 값으로 다루는 경우에는 새로운 속성을 담은 객체로 기존 내부 객체를 통째로 대체한다.

적용

  • 필드 값을 다룬다면 내부 객체의 클래스를 수정하여 값 객체(value object)로 만들 수 있다.
  • 값 객체는 불변 임으로 불변 데이터 구조는 다루기 쉽다.

결과

  • 값을 복제해 여러곳에 사용하여도 참조를 관리하지 않아도 된다. (분산 시스템과 동시성 시스템에 유용)

예시

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);
  }

 

특정 객체를 여러 객체에서 공유하고자 한다면, 공유 객체의 값을 변경했을 때 이를 관련 객체에 모두 알려줘야한다면 공유 객체를 참조로 다뤄야 한다.

쉽게 정리하자면 어떤 숫자를 입력받아 3이 맞냐 아니냐를 판독해야할 때, 코드에 입력받은 값을 받아오는게 아니라 3이라는 불변의 값을 넣어 비교대조 시킨다. 변수에 기준이 아닌 불변에 기준을 맞추는 격이다.

 

 

9.5 값을 참조로 바꾸기

내용

  • 하나의 데이터 구조 안에 논리적으로 똑같은 제3의 데이터 구조를 참조하는 레코드가 여러개 있을 때 문제가 되는 상황은 데이터를 갱신해야 한다.

적용

  • 데이터를 갱신할 때, 하나라도 놓치면 데이터의 일관성이 깨질 때, 복제된 데이터들을 모두 참조로 바꿔주는게 좋다.

결과

  • 갱신이 필요하면 모든 복제본을 찾아서 빠짐없이 갱신하는 처리를 하지 않아도 된다.

예시

Before

let customer = new Customer(customerData);

After

let customer = customerRepository.get(customerData.id);

 

9.5 매직 리터럴 바꾸기

내용

  • 리터럴은 문자 그대로의 뜻으로 코드를 읽는사람이 그 값의 의미를 모른다면, 숫자 자체로는 의미를 명확히 알려주지 못하므로 매직 리터럴이라 한다.

적용

  • 매직 리터럴을 존재하는 경우
  • 남성은 'm', 서울은 '본사'로 뜻할 수 있다.
  • 'const one = 1' 은 의미가 없다.

결과

  • 코드 자체로 뜻을 분명하게 드러낼 수 있다.

예시

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;
}

  자기만의 생각에 갇히지 말아야 한다는 점을 보여주는 리펙터링인 것 같다. 

 

반응형