모듈을 분리하는 가장 중요한 기준은 아마도 시스템에서 각 모듈이 자신을 제외한 다른 부분에 드러내지 않아야 할 비밀을 얼마나 잘 숨기느냐에 있을 것이다. p.235
클래스는 본래 정보를 숨기는 용도로 설계되었다. p.235
7.1 레코드 캡슐화하기
저장하는 용도로는 레코드보다 객체를 선호하는 편이다. p.236
객체를 사용하면 어떻게 저장했는지를 숨긴 채 세 가지 값을 각각의 메서드로 제공할 수 있다. 사용자는 무엇이 저장된 값이고 무엇이 계산된 값인지 알 필요가 없다. p.237
덩치 큰 데이터 구조를 다룰수록 쓰기 부분에 집중한다. p.243
setter 부분에서 데이터의 변화가 일어나기 때문에 가변 데이터라면 쓰기 부분에 집중해야 한다.
데이터 구조의 읽기 전용 프락시를 반환하는 방법도 있다. 클라이언트 내부 객체를 수정하려 하면 프락시가 예외를 던지도록 하는 것이다. p.243
읽기 전용 프록시를 만들면 프록시 객체에서 setter가 실행되면 예외가 발생하게 될 것이다.
이 상황에서 프록시를 부모 객체로 치환했을 때 setter가 기대했던 대로 작동하지 않게 된다.
그러면 리스코프 치환 원칙(LSP)을 위반하게 된다.
이러한 위반을 알면서도 읽기 전용 프록시를 사용해야 하는 경우는 언제인지 아직은 모르겠다.
때로는 새로 만든 클래스와 게터를 잘 혼합해서, 게터는 데이터 구조를 깊이 탐색하게 만들되 원본 데이터를 그대로 반환하지 말고 객체로 감싸서 반환하는 게 효과적일 수 있다. p.245
때로는 setter 적극적 사용 + getter는 deep copy 한 데이터 반환 조합으로 사용할 수 도 있다.
무조건 setter/getter로 인터페이스를 감싸는 게 좋은 것은 아니다.
7.2 컬렉션 캡슐화하기
여기서 중요한 점은 코드 베이스에서 일관성을 주는 것이다. 앞에 나온 방식 중에서 한 가지만 적용해서 컬렉션 접근 함수의 동작 방식을 통일해야 한다.
리팩토링 하는 방식도 객체 안에서 일관성 있게 적용해야 한다.
7.3 기본형을 객체로 바꾸기 (Replace Primitive with Object)
나는 단순한 출력 이상의 기능이 필요해지는 순간 그 데이터를 표현하는 전용 클래스를 정의하는 편이다. p.251
부지런히 전용 클래스를 만들어봐야겠다.
반복적으로 사용되는 개념을 기본형 타입으로 계속 두지 말고 객체로 만들어보자.
객체로 만들어두면 해당 개념에 추가적인 기능이 필요해지면 객체에 메서드를 추가할 수 있다.
class Priority {
private let value: String
init(_ value: String) {
self.value = value
}
func toString() {
return value
}
}
이 상황에서는 개인적으로 게터(value())보다는 변환 함수(toString())를 선호한다. 클라이언트 입장에서 보면 속성 자체를 받은 게 아니라 해당 속성을 문자열로 표현한 값을 요청한 게 되기 때문이다. p.253
클라이언트 관점에서 보면 Priority 객체를 string으로 표현했을 때 어떤 결과물이 나오는가를 체크하게 된다.
좀 더 맥락을 파악하기 좋다.
7.4 임시 변수를 질의 함수로 바꾸기
이번 리팩터링은 클래스 안에서 적용할 때 효과가 가장 크다. p.257
스냅숏 용도로 쓰이는 변수에는 이 리팩터링을 적용하면 안 된다. p.257
7.5 클래스 추출하기
일부 데이터와 메서드를 따로 묶을 수 있다면 어서 분리하라는 신호다. p.260
함께 묶이는 부분이 있다면 클래스로 한번 추출해보자.
다시 돌아갈 수 있도록 커밋을 자주 남기거나 임시 함수를 만들어서 작업하는 방안이 있을 것 같다.
하나씩 옮길 때마다 테스트한다. p.261
앞의 절차에도 계속 나왔을 문구인데 갑자기 눈에 들어와서 남긴다.
리팩터링을 작게 나눠서 진행하고 한 발자국 뗄 때마다 테스트를 한다.
7.7 위임 숨기기
캡슐화는 모듈들이 시스템의 다른 부분에 대해 알아야 할 내용을 줄여준다. p.268
7.8 중개자 제거하기
언제든 균형점을 옮길 수 있으니 말이다. 시스템이 바뀌면 '적절하다'의 기준도 바뀌기 마련이다. 6개월 전에는 바람직했던 캡슐화가 이제는 어색할 수 있다. 리팩터링은 결과 미안하다고 말하지 않는다. 즉시 고칠 뿐이다. p.272
개발자들은 그 순간에 적합한 코드를 작성한다.
시간이 지나면 코드도 변하고 적절함의 기준도 바뀐다.
이전에는 꼭 필요했던 것이 이제는 필요 없어지기도 한다.
지난주에 이어 이번 주에도 완독반 과제를 제출하지 못했습니다ㅠㅠ
그래도 충실히 읽고 내 생각을 기록하는데 힘쓰기로 했습니다.
리팩토링 기법들도 좋지만 그 순간에 맞는 트레이드 오프를 제대로 할 줄 아는 개발자가 되면 좋겠습니다.
'CS > Refactoring' 카테고리의 다른 글
[Refactoring] Chapter 9: 테이터 조직화 (0) | 2021.05.16 |
---|---|
[Refactoring] Chapter 8: 기능이동 (0) | 2021.05.16 |
[Refactoring] Chapter 6: 기본적인 리팩터링 (2) | 2021.04.26 |
[Refactoring] Chapter 3, 4 과제 (0) | 2021.04.17 |
[Refactoring] Chapter4를 Swift로 따라해보기 (0) | 2021.04.17 |