logo
새로운 블로그로 이전하였습니다.

(리팩터링 2판) ch09.2 필드 이름 바꾸기

  • 리팩터링

💭 배경

  • 프로그램 곳곳에서 쓰이는 레코드 구조체의 필드 이름은 매우 중요하다.
  • 데이터 구조는 프로그램을 이해하는 데 큰 역할을 한다.
  • 개발을 진행할 수록 데이터를 더 잘 이해하게 되는 만큼, 그 깊어진 이해를 프로그램에 반드시 반영해야 한다.
  • 레코드의 필드 이름만큼 gettersetter의 이름도 중요하다.

📏 절차

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

🧑🏻‍🏭 리팩토링 실습

예시 코드

1. 객체

const food = {name: 'pizza', country: 'Italy'};

이 객체에서 ‘name’‘title’로 바꾸고 싶다고 해보자.

코드베이스 곳곳에서 사용되며, 그 중 이 ‘title’을 변경하는 곳도 있다.

2. 레코드를 클래스로 캡슐화

class Food {
	constructor(data) {
		this._name = data.name;
		this._country = data.country;
	}
	
	get name() {return this._name;}
	set name(aString) {this._name = aString;}
	get country() {return this._country;}
	set country(aCountryCode) {this._country = aCountryCode;}
}
 
const food = new Food({name: 'pizza', country: 'Italy'});
  • food 객체가 캡슐화되지 않았기에 위처럼 먼저 캡슐화를 진행한다.
  • getter, setter, 생성자, 내부 데이터 구조의 이름 변경이 필요해보인다.
  • 입력 데이터 구조를 내부 데이터 구조로 복제했으므로, 독립적으로 작업하기 위해선 이 둘을 구분해야 한다.

3. 별도의 필드를 정의하고 생성자와 접근자에서 둘을 구분해 사용

1️⃣ 필드명 변경

class Food {
	constructor(data) {
		this._title = data.name; // <-- 
		this._country = data.country;
	}
	
	get name() {return this._title;} // <--
	set name(aString) {this._title = aString;} // <--
	get country() {return this._country;}
	set country(aCountryCode) {this._country = aCountryCode;}
}

필드명을 this._name에서 this._title로 변경한다.

2️⃣ title 조건문 추가

class Food {
	constructor(data) {
		// data.title이 있으면 this._title에 넣고 없으면 name을 넣도록 조건문 추가
		this._title = (data.title !== undefined) ? data.title : data.name;
		this._country = data.country;
	}
	
	get name() {return this._title;}
	set name(aString) {this._title = aString;}
	get country() {return this._country;}
	set country(aCountryCode) {this._country = aCountryCode;}
}

생성자를 호출하는 쪽에서 nametitle을 모두 사용할 수 있게 된다.

4. 생성자를 호출하는 곳을 모두 찾아서 새로운 이름인 title을 사용하도록 하나씩 수정한다.

const food = new Food({title: 'pizza', country: 'Italy'});

5. 생성자에서 name을 사용할 수 있게 하던 코드를 제거한다.

class Food {
	constructor(data) {
		this._title = data.title; // <--
		this._country = data.country;
	}
	
	get name() {return this._title;}
	set name(aString) {this._title = aString;}
	get country() {return this._country;}
	set country(aCountryCode) {this._country = aCountryCode;}
}

6. 접근자의 이름을 바꿔준다

class Food {
	constructor(data) {
		this._title = data.title;
		this._country = data.country;
	}
	
	get title() {return this._title;} // <--
	set title(aString) {this._title = aString;} // <--
	get country() {return this._country;}
	set country(aCountryCode) {this._country = aCountryCode;}
}

🗯️밑줄 친 문장들

데이터 구조는 무슨 일이 벌어지는 지를 이해하는 열쇠다.

데이터 구조가 중요한 만큼 반드시 깔끔하게 관리해야 한다. 다른 요소와 마찬가지로 개발을 진행할 수록 데이터를 더 잘 이해하게 된다. 따라서 그 깊어진 이해를 프로그램에 반드시 반영해야한다.

단, 리팩터링 도중 테스트에 실패한다면 더 작은 단계로 나눠 진행해야 한다.


Source

리팩터링 2판, 마틴파울러