💭 배경
- 프로그램 곳곳에서 쓰이는 레코드 구조체의
필드 이름
은 매우 중요하다. - 데이터 구조는 프로그램을 이해하는 데 큰 역할을 한다.
- 개발을 진행할 수록 데이터를 더 잘 이해하게 되는 만큼, 그 깊어진 이해를 프로그램에 반드시 반영해야 한다.
- 레코드의 필드 이름만큼
getter
와setter
의 이름도 중요하다.
📏 절차
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;}
}
생성자를 호출하는 쪽에서 name
과 title
을 모두 사용할 수 있게 된다.
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;}
}
🗯️밑줄 친 문장들
데이터 구조는 무슨 일이 벌어지는 지를 이해하는 열쇠다.
데이터 구조가 중요한 만큼 반드시 깔끔하게 관리해야 한다. 다른 요소와 마찬가지로 개발을 진행할 수록 데이터를 더 잘 이해하게 된다. 따라서 그 깊어진 이해를 프로그램에 반드시 반영해야한다.
단, 리팩터링 도중 테스트에 실패한다면 더 작은 단계로 나눠 진행해야 한다.