////
Search
Duplicate
🛋️

Chapter 2. 피드백 활용

시스템을 변경하는 방법은 크게 두 가지로 나눌 수 있는데, 저자는 이를 각각, 편집 후 기도하기보호 후 수정하기라고 부른다.
편집 후 기도하기
이는 코드 변경 계획을 신중하게 세우고, 변경 대상 코드를 이해했는지 확인한 후 변경 작업에 들어간다.
변경 완료 후에는 시스템을 실행해서 변경 사항이 제대로 동작하고 무언가 손상된 동작이 없는지 자세히 조사한다.
보호 후 수정하기
이 방식의 기본 개념은 소프트웨어를 변경할 때, 안전망을 이용하자는 것이다.
안전망은 테스트 루틴을 코드의 곳곳에 적절히 배치하여 변경 작업 수행 후, 결과가 올바른지 확인하는 것이다.
이런 테스트를 작업 결과의 정확성을 보여주기 위한 테스트라 한다. 전통적으로는 회귀 테스트라고 부른다.
회귀 테스트란 주기적으로 테스트를 실행해 정상적인 동작 여부를 확인하고 소프트웨어가 동작하는지 조사하는 것이다.
변경 대상 코드의 주변에 배치된 테스트 루틴들은 소프트웨어 바이스의 역할을 한다.
바이스란 목공예나 금속세공에서 공작물을 고정시키는 장치를 의미한다.
레거시 코드를 이용해 작업할 때 단위 테스트는 가장 중요한 요소 중 하나다. 시스템 수준의 회귀 테스트는 물론 중요하다. 하지만 소규모 수준의 부분별 테스트도 매우 중요하다.
개발 과정에서 빠른 피드백을 제공함으로써 훨씬 더 안전한 리팩토링이 가능해지기 때문이다.

단위 테스트란?

단위 테스트의 기본 개념은 독립된 개별 소프트웨어 컴포넌트를 테스트하는 것이다.
그렇다면 컴포넌트는 무엇일까? 정의는 다양하지만 시스템의 가장 원자적인 동작 단위를 의미한다.
절차적 프로그래밍에서의 단위는 보통 함수를 의미하며, 객체 지향 프로그래밍에서는 클래스를 의미한다.
함수나 클래스의 분리 테스트는 단위 테스트의 의미상 매우 중요하다. 대부분의 오류는 전체 시스템에서 일어나므로 대규모 테스트가 더 중요해 보일테지만 대규모 테스트는 몇 가지 문제가 있다.
오류 위치 파악
테스트 루틴이 테스트 대상으로 멀어질수록 테스트 실패가 의미하는 바를 파악하기 힘들어진다. 그 결과 실패가 발생한 위치를 특정하는데 오랜시간이 든다.
실행 시간
커버리지
코드 조각과 그 코드 조각을 실행시키는 값들의 연결 관계를 파악하기 어렵다.
단위 테스트는 대규모 테스트의 단점을 보완할 수 있으며 조건은 다음과 같다.
실행 속도가 빠르다.
오류 위치 파악에 도움이 된다.

상위 수준의 테스트

단위 테스트도 중요하고 상위 수준의 테스트 역시 중요하다.
상위 수준의 테스트를 적절히 작성하였을 때, 개별 클래스에 대한 테스트 루틴 작성도 쉬워질 때가 많다.

테스트를 통한 코드 보호

이제 테스트를 이용해 보호 후 수정하기라는 방식으로 코드 변경을 해야하는 것도 알았다. 그럼 구체적으로 어떻게 해야하는 걸까?
가장 먼저, 변경을 가할 코드 주위에 테스트 루틴을 배치해 안전성을 높여야한다는 점이다.
InvoiceUpdateResponder 클래스의 getResponseText 메소드와 Invoice 클래스의 getValue 메소드를 변경하고 싶다고 하자. 이 두 개의 메소드가 변경점인 것이다.
테스트를 하려면 테스트 하네스 내에서 두 클래스의 인스턴스를 생성해야 한다.
Invoice 클래스는 내부에 의존성이 없지만 InvoiceUpdateResponder는 그렇지 않다. 이 의존성들을 위해 코드를 변경해야할까?
즉, 테스트하기 어려운 이유는 무언가에 직접 의존하기 때문이다. 이런 의존성을 제거하기 위해 인터페이스를 사용해볼 수 있다.
의존 관계를 제거함으로써 영향도가 높은 코드 변경의 안전성을 담보하면서 테스트 루틴을 작성할 수 있게 된다.

레거시 코드를 변경하는 순서

변경 지점을 식별한다

코드 변경을 수행할 지점은 소프트웨어 아키텍처와 밀접하게 연결되어 있다.

테스트 루틴을 작성할 위치를 찾는다

특정 변경에 대한 테스트 루틴을 어디에 작성하면 좋을지 판단해야 한다.

의존 관계를 제거한다

테스트를 작성할 때 가장 큰 장애물 중 하나는 의존 관계다.
의존 관계가 문제가 되는 가장 대표적인 경우는 테스트 하네스 내부에서의 인스턴스 생성과 메소드 실행이다.
레거시 코드를 다룰 때는 테스트 루틴을 배치하기 위해 의존 관계를 먼저 제거해야 한다.

테스트 루틴을 작성한다

변경 및 리팩토링을 수행한다

저자는 레거시 코드에 기능을 추가할 때 TDD를 권장한다.