아래 내용은 레거시 코드 활용 전략 11장 (Michael C. Feathers, p.209-231) 을 읽고 정리한 내용입니다.
상황
동작 변경을 해야 하는데 이를 안전하게 수행하기 위해 테스트 코드를 작성하려 한다. 그런데 기존 코드의 어느 부분들을 테스트로 커버해야 할지 잘 모르겠다.
제안하는 방법
- 동작을 변경하기 위해 구체적으로 어느 코드 라인을 수정해야 하는지 찾아낸다.
- 해당 코드를 변경함으로써 어떤 다른 것들이 영향받는지 분석한다.
- 예: 변경해야 할 메서드를 호출하는 곳, 변경해야 할 메서드가 반환하거나 다른 메서드에 매개변수로 넘기는 객체, 변경이 필요한 메서드를 사용하는 상위/하위 클래스.
- 영향받는 것들을 충분히 커버할 수 있도록 테스트를 작성한다.
- 아래 소개된 effect sketch 의 endpoint 들을 테스트하는 것도 방법이다.
효과 구조 분석 방법: 효과 스케치 (effect sketch)
- 코드 중 한 부분의 변경이 어떤 다른 동작(메서드)이나 상태(변수)에 영향을 미치는지 분석한 관계도.
- 변경하려는 메서드가 어느 메서드들을 호출하고 반환값을 누구와 공유하는지 등을 화살표로 표현.
- 효과 스케치의 종단점을 endpoint 라고 한다. 직접적으로 변경하는 메서드와 그 효과구조의 endpoint 를 커버하는 테스트를 작성하면, 변경작업으로 인한 부작용 (side effect) 을 검토하는데 도움이 된다.
- 재활용을 통해 코드의 중복도를 낮추면 endpoint 가 줄어드는 효과를 가질 수 있다.
- 효과 스케치의 예:

교훈
- 메서드 구현시 원하는 동작을 최대한 단순한 효과구조로 구현하는 것이 바람직하다 (i.e., restrict/localize effects). 메서드 바깥으로의 효과 전파가 적을수록 프로그램 흐름의 이해 및 디버깅이 용이하기 때문이다.
- 로컬변수 사용, Immutable object 사용, Singleton state 지양 등이 그러한 노력의 일환이라 할 수 있다.
- 사용하는 프로그래밍 언어를 잘 이해하고 활용할 수 있어야 한다.
- 예를들어 JAVA 클래스의 경우 인스턴스 변수나 메서드의 access modifier 에 따라 해당 인스턴스 필드에 접근 가능한 것들의 범위가 달라진다. 이를 이해해야 인스턴스 필드를 변경했을 때 이를 사용하는 어떤 것들이 영향받을 수 있는지 추론 가능하다.
- 캡슐화(encapsulation)는 코드의 이해를 위한 하나의 수단이다. 캡슐화 자체가 목적이 아니다.
- 효과 전파를 제한하는데 캡슐화는 효과적이긴 하다.
- 그러나, 완벽하게 캡슐화되어 있지만 테스트하기 어려운 설계라면 바람직하다고만 할 수 있을까.
책에서 발췌 (번역 및 일부 내용 수정)
코드 내에서의 효과 전파는 다음의 기본적인 세 가지 행위로 인해 일어난다.
- 호출자가 사용하는 반환값이 기존과 다르게 계산되게끔 로직을 수정함으로써.
- 다른 메서드의 매개변수로 전달되어 나중에 다른곳에서도 사용될 객체를 수정함으로써.
- static 또는 global 상태를 수정함으로써.
[중간 내용 생략…]
다음은 효과 구조 분석시 사용하는 heuristic 이다.
- 구현을 변경할 메서드를 식별한다 (“타겟 메서드”라고 하자)
- 타겟 메서드가 반환값을 가진다면, 타겟 메서드의 호출자를 점검한다.
- 타겟 메서드가 내부 로직으로 인해 어떤 값들을 변경시키는지 살펴본다. 그 값을 사용하는 다른 메서드들과 그들의 호출자를 점검한다.
- 인스턴스 변수에 영향을 미친다면 이를 공유하는 것들을 점검한다.
- 로컬 변수라도 Object 타입이면 조심하자. 타겟 메서드 내에서 호출한 다른 메서드의 매개변수로 객체를 넘겼는데, 이 객체를 타겟메서드에서 또 수정하면 다른 메서드에 영향을 미치게 된다.
- 타겟 메서드 또는 타겟 메서드가 영향을 미치는 인스턴스 필드를 사용하는 상위/하위 클래스도 점검한다.
- [못이해함…]
- 위 과정 중 식별해낸 모든 메서드들 안에서 global 또는 static 상태값을 수정시키는 부분이 있는지 점검한다.