티스토리 뷰
마틴 파울러 - 리팩터링 (2판) 의 7장 내용 중 기억하고 싶은 것 기록 ✏️✏️
6장에서는 기본적인 리팩터링 기법들을 설명해주십니다.
(함수 추출하기 / 함수 인라인 하기 / 이름 바꾸기 / 매개변수 객체 만들기 등등)
7장에서는 캡슐화를 주제로한 리팩터링 기법들을 설명해주시는데 인상깊은 몇가지만 기록합니다.
7.1 레코드 캡슐화 하기 (Encapsulate Record)
(위의 예제랑 다른 예제에 대한 설명입니다,,)
....
클라이언트가 데이터 구조를 요청할 때 실제 데이터를 제공해도 된다.
하지만 클라이언트가 데이터를 직접 수정하지 못하게 막을 방법이 없어서
'모든 쓰기를 함수 안에서 처리한다' 는 캡슐화의 핵심 원칙이 깨지는게 문제이다.
그래서 내부데이터를 복제해서 제공한다.
get rawData() {
return _.cloneDeep(this._data)
}
7.2 컬렉션 캡슐화하기 (Encapsulate Collection)
# Getter
(게터에서 slice() 처리를 해준게 복제본 컬렉션을 반환하려고 한 것입니다)
컬렉션 변수로의 접근을 캡슐화하면서 게터가 컬렉션 자체를 반환하도록 한다면, 그 컬렉션을 감싼 클래스가 눈치채지 못하는 상태에서 컬렉션의 원소들이 바뀌어버릴 수 있다.
컬렉션 게터가 원본 컬렉션을 반환하지 않게 만들어서 클라이언트가 실수로 컬렉션을 바꿀 가능성을 차단하는 것이 낫다.
가장 흔히 사용하는 방식은 컬렉션 게터를 제공하되 내부 컬렉션의 복제본을 반환하는 것이다. 복제분을 수정해도 캡슐화된 원본 컬렉션에는 아무런 영향을 주지 않는다.
내 경험에 따르면 컬렉션에 대해서는 어느 정도 강박증을 갖고 불필요한 복제본을 만드는 편이, 예상치 못한 수정이 촉발한 오류를 디버깅하는 것보다 낫다.
# add, remove
컬렉션을 감싼 클래스에 흔히 add()와 remove()라는 이름의 컬렉션 변경자 메서드를 만든다. 이렇게 항상 컬렉션을 소유한 클래스를 통해서만 원소를 변경하도록 하면 프로그램을 개선하면서 컬렉션 변경 방식도 원하는 대로 수정할 수 있다.
==>
레코드 캡슐화하기 & 컬렉션 캡슐화하기에서 모두 getter로 얻은 데이터를 클라이언트에서 변경할 수도 있는 것을 고려해서
clone을 한 복제본을 넘겨주는 것이 인상깊었습니다. (진정한 캡슐화란 이것까지 고려해야하는 군요)
자바스크립트는 잘 모르겠지만
스위프트는 private(set) 해주면 아래의 상황에서 setter가 inaccessible하다는 컴파일에러가 나면서 read only를 보장하고
만약 이렇게 하더라도 원본 데이터가 바뀌지 않아서 신경써야할 일은 없는 것 같습니다.
7.5 클래스 추출하기 (extract class)
7.6 클래스 인라인 하기 (Inline class)
클래스 인라인 하기는 클래스 추출하기를 거꾸로 돌리는 리팩터링이다.
더 이상 제 역할을 못해서 그대로 두면 안되는 클래스는 인라인해버린다. 역할을 옮기는 리팩터링을 하고 나니 특정 클래스에 남은 역할이 거의 없을 때 이런 현상이 자주 생긴다. 이럴 땐 이 불쌍한 클래스를 가장 많이 사용하는 클래스로 흡수시킨다.
두 클래스의 기능을 지금과 다르게 배분하고 싶을 때도 클래스를 인라인한다. 클래스를 인라인해서 하나로 합친 다음 새로운 클래스를 추출하는 게 쉬울 수 도 있기 기 때문이다.
7.7 위임 숨기기 (Hide Delegate)
모듈화 설계를 제대로 하는 핵심은 캡슐화다.
서버 객체의 필드가 가리키는 위임 객체의 메서드를 호출하려면 클라이언트는 이 위임 객체를 알아야한다.
(서버 객체가 위임 객체를 제공한다는 사실을 알아야함)
만약 위임 객체의 인터페이스가 바뀌면 이 인터페이스를 사용하는 모든 클라이언트를 수정해야한다.
이러한 의존성을 없애려면 서버 자체에 위임 메서드를 만들어서 위임 객체의 존재를 숨기면 된다.
그러면 위임 객체가 수정되더라도 서버 코드만 고치면 되며, 클라이언트는 아무런 영향을 받지 않는다.
7.8 중개자 제거하기 (Remove Middle Man)
중개자 제거하기는 위임 숨기기와 반대되는 리팩터링이다.
클라이언트가 위임 객체의 또 다른 기능을 사용하고 싶을 때마다 서버에 위임 메서드를 추가해야하는데, 이렇게 기능을 추가하다보면 단순히 전달만 하는 위임 메서드들이 점점 성가셔진다. 그러면 서버 클래스는 그저 중개자(middle man) 역할로 전락하여, 차라리 클라이언트가 위임 객체를 직접 호출하는 게 나을 수 도 있다.
==>
클래스 추출하기(7.5) - 클래스 인라인하기(7.6)
위임 숨기기(7.7) - 중개자 제거하기(7.8)
이렇게 각각 대응되는데, 서로 반대되는 리팩터링 기법이 있는 것을 보며
역시 설계는 트레이드 오프임을 느꼈다.
그리고 클래스가 역할이 없어지거나 클래스가 그저 중개자 역할로 전락할 때는
그 클래스에 적절한 역할을 주기 위해 되돌리기 리팩터링(?)을 사용하신 것이 인상깊었다.
[추가]
특정 변수에 const를 붙여 읽기 전용으로 만들어서 돌려본다. (스위프트에서는 let으로 변경해서 돌려본다.)
이렇게 하면 컴파일 에러가 나기 때문에 못보고 지나친 재대입 코드를 찾을 수 있다.
코드가 길면 어디서 수정을 하는 지 파악하기 힘든데 좋은 아이디어!
'책도 읽고' 카테고리의 다른 글
리팩터링 (5) - 조건부 로직을 다형성으로 / 특이 케이스 / Assertion (0) | 2021.07.12 |
---|---|
리팩터링 (4) - 참조를 값으로 / 값을 참조로 바꾸기 (0) | 2021.07.01 |
리팩터링 (2) - 좋은 테스트 습관 (0) | 2021.04.27 |
리팩터링 (1) - 리팩터링하는 이유 / 리팩터링 원칙 (0) | 2021.04.15 |
오브젝트 (4) - 상속 주의사항 (0) | 2021.02.19 |
- Total
- Today
- Yesterday
- Django Firebase Cloud Messaging
- Dart Factory
- Watch App for iOS App vs Watch App
- Django FCM
- Sketch 누끼
- PencilKit
- Django Heroku Scheduler
- 구글 Geocoding API
- flutter build mode
- Flutter Text Gradient
- flutter deep link
- Flutter getter setter
- cocoapod
- ipad multitasking
- Flutter Spacer
- Flutter 로딩
- 플러터 얼럿
- DRF APIException
- github actions
- Python Type Hint
- ribs
- flutter dynamic link
- drf custom error
- METAL
- 장고 Custom Management Command
- 장고 URL querystring
- 플러터 싱글톤
- Flutter Clipboard
- flutter 앱 출시
- SerializerMethodField
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |