: 데이터 구조에 집중한 리팩터링들.
1. 변수 쪼개기
: 한 변수는 하나의 역할만 수행하도록 한다. 한 변수에 두번 이상 대입이 이뤄진다면 해당 변수는 여러 가지 역할을 수행한다는 신호이다.
2. 필드 이름 바꾸기
- 제일 중요한 부분. 무슨 데이터로 구성되는지를 보면 프로그램을 이해하는데 도움이 된다.
- 넓은 범위로 참조되고 있다면 1. 캡슐화를 이용하거나 2. 새로운 이름의 속성을 추가하고, 값을 복제해 하나둘씩 새로운 속성을 참조하도록 변경한다.
3. 파생 변수를 질의 함수로 바꾸기
: 사이드 이펙트가 많을 수 있는 가변 데이터를 최대한 없애거나 유효범위를 좁힌다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Before
public String getFoo() {
return this.foo;
}
public void setBar(String a) {
this.bar = a;
this.foo += this.bar;
}
// After
public String getFoo() {
return this.foo + this.bar;
}
public void setBar(String a) {
this.bar = a;
}
- foo 속성이 가변되는 범위를 줄임으로써 예상치 못한 사이드이펙트를 방지한다. 위의 상황에서는
getFoo()
호출 전에 항상setBar()
호출이 선행되어야 한다는 전제조건이 있다. 이러한 전제조건은 개발자가 한눈에 파악하기 어려우며, 이러한 이유때문에 이 리팩터링은 대부분 필연적으로 테스트가 따라야한다.
4. 참조를 값으로 바꾸기
: 같은 인스턴스를 참조하던 것을 새로운 VO 인스턴스를 생성하도록 바꾸기
- 값 객체(VO)로 다룬다. 내부 객체 속성을 바꾸지 않고 새로운 객체로 생성하도록 하면 불변이라는 특징을 갖도록 할 수 있고, 사이드 이펙트를 줄일 수 있다.
- 분산 시스템, 동시성 시스템에서 유용하다.
5. 값을 참조로 바꾸기
: 새로운 VO 인스턴스를 생성하던 것을 같은 인스턴스를 참조하도록 바꾸기
- 공유되는 데이터를 갱신할 일이 없다면 (싱글턴처럼) 같은 인스턴스를 참조하든 새롭게 생성하든 사실 문제는 없다. 후자의 경우 메모리 낭비가 있을 수 있지만, 그로 인해 문제가 되는 경우는 드물다.
- 공유되는 데이터를 갱신할 일이 있다면, 참조로 바꿔 여러 클라이언트에서 공통으로 접근하도록 하는게 좋다. 휴먼 에러는 언제든 있을 수 있고 따라서 데이터 일관성은 언제든 깨질 수 있기 때문이다.
6. 매직 리터럴 바꾸기
상수를 적극적으로 활용한다. 그런데, 상수로 변경함으로써 얻는 이득이 없다고 판단되면 그냥 raw data로 사용하는게 나을 수도 있다. 주로 비즈니스적인 숫자나 값들이 상수로 다뤄지면 좋을 것 같다.
1 2 3 4 5
// bad public static final int ONE = 1; // good public static final int NAME_LENGTH_LOWERBOUND = 1;
Reference)
리팩터링 2판