Home [리팩터링] chapter 9 데이터 조직화
Post
Cancel

[리팩터링] chapter 9 데이터 조직화

p.329 데이터 구조 리팩터링.
하나의 값이 여러 목적으로 사용된다면 혼란과 버그를 낳는다. 그러니 이런 코드를 발견하면 변수 쪼개기를 적용해 용도별로 분리하자. 한편, 파생변수를 질의함수로 바꾸기를 활용하여 변수 자체를 완전히 없애는 게 가장 좋은 해법일 때도 있다.

p.330 변수 쪼개기
for loop문에 있는 변수 i는 반복문을 한번 돌때마다 값이 바뀐다. 수집 변수는 메서드가 동작하는 중간중간 값을 저장한다. 그 외에도 변수는 긴 코드의 결과를 저장했다가 나중에 쉽게 참조하려는 목적으로 흔히 쓰인다. 이런 변수에는 값을 단 한번만 대입해야한다. 대입이 두번 이상 이뤄진다면 여러가지 역할을 수행한다는 신호다. 역할이 둘 이상인 변수가 있다면 쪼개야된다.

p.338 파생 변수를 질의 함수로 바꾸기
가변 데이터는 소프트웨어

p.343 참조를 값으로 바꾸기
객체를 다른 객체에 중첩하면 내부 객체를 참조 혹은 값으로 취급할 수 있다. 참조냐 값이냐의 차이는 내부 객체의 속성을 갱신하는 방식에서 가장 극명하게 드러난다. 참조로 다루는 경우에는 내부 객체는 그대로 둔 채 그 객체의 속성만 갱신하며, 값으로 다루는 경우에는 새로운 속성을 담은 객체로 기존 내부 객체를 통째로 대체한다. 필드를 값으로 다룬다면 내부 객체의 클래스를 수정하여 값 객체로 만들 수있다. 값 객체는 대체로 자유롭게 활용하기 좋은데, 특히 불변이기 때문이다.일반적으로 불변 데이터 구조는 다루기 더 쉽다. 불변 데이터 값은 프로그램 외부로 건네줘도 나중에 그 값이 나 몰래 바뀌어서 내부에 영향을 줄까 염려하지 않아도 된다. 값을 복제해 이곳 저곳에서 사용하더라도 서로 간의 참조를 관리하지 않아도 된다. 그래서 값 객체는 분산 시스템과 동시성 시스템에서 특히 유용하다. 한편 값 객체의 이런 특성 떄문에 이번 리팩터링을 적용하면 안 되는 상황도 있다. 예컨대 특정 객체를 열 객체에서 공유하고자 한다면, 그래서 공유 객체의 값을 변경했을 떄 이를 관련 객체 모두에 알려줘야 한다면 공유 객체를 참조로 다뤄야 한다.

기존 코드

Person class

1
2
3
4
5
6
7
8
9
class Person{
	constructor(){
		this._telephoneNumber = new TelephoneNumber();
	}
	get officeAreaCode(){return this._telephoneNumber.areaCode;}
	set officeAreaCode(arg){this._telephoneNumber.areaCode = arg;}
	get officeNumber(){return this._telephoneNumber.number;}
	set officeNumber(arg){this._telephoneNumber.number = arg;}
}

추출해서 새로 만들어진 객체(TelephoneNumber)를 갱신하는 메서드 들은 여전히 추출 전 클래스(Person)에 존재할 것이다. 어쨌든 새 클래스가 가리키는 참조가 하나뿐이므로 참조를 값으로 바꾸기에 좋은 상황.

TelephoneNumber class

1
2
3
4
5
6
7
class TelephoneNumber{
	...
	get areaCode(){return this._areaCode;}
	set areaCode(arg){this._areaCode = arg;}
	get number(){return this._number;}
	set number(arg){this._number = arg;}
}

수정된 코드

Person class

1
2
3
4
5
6
7
8
9
10
11
12
13
class Person{
	constructor(){
		this._telephoneNumber = new TelephoneNumber();
	}
	get officeAreaCode(){return this._telephoneNumber.areaCode;}
	set officeAreaCode(arg){
		this._telephoneNumber = new TelephoneNumber(arg, this.officeNumber);
	}
	get officeNumber(){return this._telephoneNumber.number;}
	set officeNumber(arg){
		this._telephoneNumber = new TelephoneNumber(this.officeAreaCode,arg);
	}
}

먼저 전화번호를 불변으로 만든다. 필드들의 세터들만 제거하면 된다. 세터 제거의 첫 단계로 세터로 설정하던 두 필드를 생성자에서 입력받아 설정하도록 한다.

TelephoneNumber class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class TelephoneNumber{
	constructor(areaCode,number){
		this._areaCode = areaCode;
		this._number = number;
	}
	get areaCode(){return this._areaCode;}
	set areaCode(arg){this._areaCode = arg;}
	get number(){return this._number;}
	set number(arg){this._number = arg;}
	equals(other){
		if(!(other instanceof TelephoneNumber)) return false;
		return this.areaCode === other.areaCode && this.number === other.number;
	}
}

대부분의 객체지향 언어는 값 기반 동치성 비교를 할 수 있도록 오버라이드 가능한 동치성 검사 수단을 제공한다. 하지만 JS는 참조기반 동치성을 값 기반 동치성으로 대체하는 일과 관련하여 언어나 핵심 라이브러리 차원에서 지원해주는게 없기 때문에 임의로 equals() 작성

This post is licensed under CC BY 4.0 by the author.

[리팩터링] chapter 8 기능 옮기기

[TS] Typescript의 class

Comments powered by Disqus.