1. 전역 데이터
- 전역 데이터 (예, 자바의 public static 변수)
- 전역 데이터는 아무 곳에서나 변경될 수 있다는 문제가 있다.
- 어떤 코드로 인해 값이 바뀐 것인지 파악하기 어렵다.
- 클래스 변수(필드)도 비슷한 문제를 겪을 수 있다.
- "[[#1.1 변수 캡슐화하기 |변수 캡슐화하기]]"를 적용해서 접근을 제어하거나 어디서 사용하는지 파악하기 쉽게 만들 수 있다.
- 파라켈수스의 격언, "약과 독의 차이를 결정하는 것은 사용량일 뿐이다."
1.1 변수 캡슐화하기
변수를 변경하는 것보다 변수를 사용하는 메서드를 변경하는 것이 더욱 쉽다.
- 메서드는 점진적으로 새로운 메서드로 변경할 수 있으나, 데이터는 한 번에 모두 변경해야 한다.
- 데이터 구조를 변경하는 작업을 그보다는 조금 더 수월한 메소드 구조 변경 작업으로 대체할 수 있다.
- 데이터가 사용되는 범위가 클수록 캡슐화를 하는 것이 더 중요해진다.
- 함수를 사용해서 값을 변경하면 보다 쉽게 검증 로직을 추가하거나 변경에 따르는 후속 작업을 추가하는 것이 편리하다.
- 불변 데이터의 경우에는 이런 리팩토링을 적용할 필요가 없다.
2. 가변 데이터
- 데이터를 변경하다보면 예상치 못했던 결과나 해결하기 어려운 버그가 발생하기도 한다.
- 함수형 프로그래밍 언어는 데이터를 변경하지 않고 복사본을 전달한다. 하지만 그 밖의 프로그래밍 언어는 데이터 변경을 허용하고 있다. 따라서 변경되는 데이터 사용 시 발생할 수 있는 리스크를 관리할 수 있는 방법을 적용하는 것이 좋다.
- 관련 리팩토링
- "[[#1.1 변수 캡슐화하기 |변수 캡슐화하기]]"를 적용해 데이터를 변경할 수 있는 메서드를 제한하고 관리할 수 있다.
- "[[#2.1. 변수 쪼개기|변수 쪼개기]]"를 사용해 여러 데이터를 저장하는 변수를 나눌 수 있다.
- "[[Duplicated Code#2. 코드 분리하기|코드 정리하기]]"를 사용해 데이터를 변경하는 코드를 분리하고 피할 수 있다.
- "[[Duplicated Code#1. 함수 추출하기 |함수 추출하기]]"로 데이터를 변경하는 코드로부터 사이드 이펙트가 없는 코드를 분리할 수 있다.
- "[[#2.2. 질의 함수와 변경 함수 분리하기|질의 함수와 변경 함수 분리하기]]"를 적용해서 클라이언트가 원하는 경우에만 사이드 이펙트가 있는 함수를 호출하도록 API를 개선할 수 있다.
- 가능하다면 "[[#2.3. 세터 제거하기|세터 제거하기]]"를 적용한다.
- 계산해서 알아낼 수 있는 값에는 "[[#2.4. 파생 변수를 질의 함수로 바꾸기|파생 변수를 질의 함수로 바꾸기]]"를 적용할 수 있다.
- 변수가 사용되는 범위를 제한하려면 "여러 함수를 클래스로 묶기" 또는 "[[#2.5. 여러 함수를 변환 함수로 묶기|여러 함수를 변환 함수로 묶기]]"를 적용할 수 있다.
- "[[#2.6. 참조를 값으로 바꾸기|참조를 값으로 바꾸기]]"를 적용해서 데이터의 일부를 변경하기 보다는 데이터 전체를 교체할 수 있다
2.1. 변수 쪼개기
- 어떤 변수가 여러번 재할당 되어도 적절한 경우
- 반복문에서 순회하는데 사용하는 변수 또는 인덱스
- 값을 축적시키는데 사용하는 변수
- 그 밖의 경우에 재할당 되는 변수가 있다면 해당 변수는 여러 용도로 사양되는 것이며 변수를 분리해야 더 이해하기 좋은 코드를 만들 수 있다.
- 변수 하나 당 하나의 책임을 지도록 만든다.
- 상수를 활용하자 (JS -> const, Java -> final)
2.2. 질의 함수와 변경 함수 분리하기
- "눈에 띌만한" 사이드 이펙트 없이 값을 조회할 수 있는 메서드는 테스트하기도 쉽고, 메서드를 이동하기도 편하다.
- 명령-조회 분리 규칙
- 어떤 값을 리턴하는 함수는 사이드 이펙트가 없어야 한다.
- "눈에 띌만한 사이드 이펙트"
- 가령, 캐시는 중요한 객체 상태 변화는 아니다. 따라서 어떤 메소드 호출로 인해, 캐시 데이터를 변경하더라도 분리할 필요는 없다.
2.3. 세터 제거하기
- 세터를 제공한다는 것은 해당 필드가 변경될 수 있다는 것을 뜻한다
- 객체 생성 시 처음 설정된 값이 변경될 필요가 없다면 해당 값을 설정할 수 있는 생성자를 만들고 세터를 제거해서 변경될 수 있는 가능성을 제거해야 한다.
2.4. 파생 변수를 질의 함수로 바꾸기
- 변경할 수 있는 데이터를 최대한 줄이도록 노력해야 한다.
- 계산해서 알아낼 수 있는 변수는 제거할 수 있다.
- 계산 자체가 데이터의 의미를 잘 표현하는 경우도 있다.
- 해당 변수가 어디선가 잘못된 값으로 수정될 수 있는 가능성을 제거할 수 있다.
- 계산에 필요한 데이터가 변하지 않는 값이라면, 계산의 결과에 해당하는 데이터 역시 불변 데이터기 때문에 해당 변수는 그대로 유지할 수 있다.
2.5. 여러 함수를 변환 함수로 묶기
- 관련있는 여러 파생 변수를 만들어내는 함수가 여러 곳에서 만들어지고 사용된다면 그러한 파생 변수를 "변환 함수"를 통해 한 곳으로 모아둘 수 있다.
- 소스 데이터가 변경될 수 있는 경우에는 "여러 함수를 클래스로 묶기"를 사용하는 것이 적절하다.
- 소스 데이터가 변경되지 않는 경우에는 두 가지 방법을 모두 사용할 수 있지만, 변환 함수를 사용해서 불변 데이터의 필드로 생성해 두고 재사용할 수도 있다.
2.6. 참조를 값으로 바꾸기
- 레퍼런스 객체 vs 값 객체
- 값 객체는 객체가 가진 필드의 값으로 동일성을 확인한다.
- 값 객체는 변하지 않는다.
- 어떤 객체의 변경 내역을 다른 곳으로 전파시키고 싶다면, 레퍼런스 아니라면 값 객체를 사용한다.