8장 경계

외부 코드를 우리 코드에 깔끔하게 통합하는, 소프트웨어 경계를 깔끔하게 처리하는 기법과 기료를 살펴본다.

외부 코드 사용하기

패키지, 프레임워크 제공자는 최대한 많은 환경에서 사용가능하도록 적용성을 최대한 넓히려한다.

반면 사용자는 자신의 환경에 맞는 인터페이스를 바란다.

⇒ 이러한 차이 때문에 시스템의 경계에서 문제가 생긴다.

패키지, 프레임워크가 제공하는 모든 인터페이스를 드러내기 보단, 한 단계 래핑하는 객체를 만들어 클라이언트단에서 필요로 하는 인터페이스만 노출(제공)하도록 구현한다.

필요한 인터페이스만 드러냈기에 코드의 이해도 쉬워지고, 의도에 맞지 않게 사용하는 일도 없어진다.

경계 인터페이스인 Map(java.util.Map)을 사용할 때 발생할 수 있는 문제

  • Map을 만들어 여기저기 넘기다 보면 사용하는 쪽에서 clear()로 내용을 삭제 할 수 있다.

  • Map에 특정 타입이 아닌 다른 타입이 들어오게 되는 사이드 이펙트가 발생하게 될 수 있다.

감싸기 클래스인 Sensors를 만들어 사용자는 제네릭스가 사용되었는지 여부를 신경 쓸 필요가 없어지고, 필요한 인터페이스만 제공할 수 있게 되어 코드는 이해하기 쉽지만 오용하기 어렵다. 또한 Map 인터페이스가 변하더라도 나머지 프로그램에는 영향을 미치지 않는다.

public class Sensors {
    private Map sensors = new HashMap();
    
    public Sensor getById(String id) {
        return (sensor) sensors.get(id);
    }
}

꼭 이렇게 사용하는 방법도 있겠지만 요지는Map과 같은 경계 인터페이스를 이용할때는 이를 이용하는 클래스나 클래스 계열 밖으로 노출되지 않도록 주의해야 한다. Map 인스턴스를 공개 API의 인수로 넘기거나 반환값으로 사용하지 않는다.

학습 테스트

외부 코드를 가져와서 사용할 때, 사용법을 익히는데에도 많은 시간이 들고, 우리쪽 코드에 적용하여 버그가 발생했을 때, 우리쪽 코드의 문제인지, 외부 코드의 문제인지 디버깅하는데 많은 시간이 든다.

외부 코드를 사용하기 전, 외부 코드에 대한 테스트코드를 작성하여 사용법을 익히고 외부 코드가 정상적으로 동작한다는 것을 보장할 수 있다.

학습 테스트를 작성해두면, 외부 코드의 새로운 버전이 나왔을 때도 기존에 작성된 학습 테스트를 통해 어떤 차이가 있는지 확인할 수 있다.

외부코드의 새로운 버전에 대한 안전한 업데이트가 가능하다. 학습 테스트가 없다면 기존 코드와의 호환성에 문제가 생길까봐 업데이트하지않고 예전 버전을 오랫동안 사용하게 된다.

아직 존재하지 않는 코드를 사용하기

아직 사용할 외부 코드가 구현되기 전이라면, 자체적으로 현재 필요한 기능에 대한 인터페이스를 정의하고 그 인터페이스에 맞춰서 구현한다.

외부 코드가 구현된 후 어댑터 패턴을 활용해 정의한 인터페이스에 맞게 변환

애초에 외부 코드가 구현되지 않은 상태에서 인터페이스를 정의하므로, 철저히 외부코드와 분리된 형태의 구조를 짤 수 있다.

깨끗한 경계

  • 경계에 위치하는 코드는 깔끔히 분리한다.

  • 기대치를 정의하는(사용 목적을 말하는 것 같습니다.) 테스트 케이스를 작성한다.

  • 통제가 가능한 우리 코드에 의존하도록 한다.

    • 외부 패키지를 호출하는 코드를 가능한 줄여 경계를 관리하자.

    • 새로운 클래스로 랩핑하여 경계를 감싸거나 ADAPTER 패턴 적용

Last updated