시스템에 들어가는 모든 소프트웨어를 직접 개발하는 경우는 드물다. 패키지, 오픈소스를 이용하는 경우가 많다.
때로는 사내 다른 팀이 제공하는 컴포넌트를 사용한다.
이 장에서는 소프트웨어 경계를 깔끔하게 처리하는 기법과 기교를 살펴본다.
외부 코드 사용하기
인터페이스 제공자와 인터페이스 사용자 사이에는 특유의 긴장이 존재한다.
패키지 제공자나 프레임워크 제공자는 적용성을 최대한 넓히려 애쓴다.
사용자는 자신의 요구에 집중하는 인터페이스를 바란다.
이런 긴장으로 인해 시스템 경계에서 문제가 생길 소지가 많다.
예를 들어 java.util.map은 다양한 인터페이스를 제공한다. clear, containsKey, containsValue ...
하지만 이렇게 유언성이 큰 만큼, 문제가 생길 여지도 많다.
만약 map을 사용했는데, 중간에 clear 함수로 데이터가 삭제된다면?
map에 접근할 수만 있다면 누구든지 clear 함수를 사용할 수 있다는 이야기고, 이는 유연성과 위험도 사이에 연관성이 깊다는 것을 보여준다.
다음은 map을 조금 더 깔끔하게 사용한 코드이다.
public class Sensors {
private Map sensors = new HashMap();
public Sensor getById(String id) {
...
}
...
}
이처럼 Map을 감싸 Sensors라는 클래스를 만듬으로써 사용될 필요가 없는 인터페이스는 제거했다.
그러나 위처럼 Map 클래스를 사용할 때마다 위와 같이 캡슐화하라는 소리가 아니다.
Map(혹은 유사한 경계 인터페이스)를 여기저기 넘기지 말라는 의미이고, 공개 API의 인수로 넘기거나 반환값으로 사용하지 말라는 의미이다. 다만 그렇게 해야만 할 이유가 있다면 위와 같이 캡슐화를 사용하라.
경계 살피고 익히기
외부 코드를 사용하면 적은 시간에 더 많은 기능을 출시하기 쉬워진다.
외부 패키지를 사용해야 한다면, 테스트는 우리 책임이 아니다. 하지만 테스트를 학습 도구로써 사용할 수는 있다.
외부 코드를 익히기는 어렵다. 통합하기도 어렵다.
따라서 외부 코드를 우리의 코드에 적용하기 이전에 테스트를 통해 학습하자. 통제된 환경에서 API를 제대로 이해하는지를 확인하는 셈이다.
학습 테스트는 공짜 이상이다
학습 테스트에 드는 비용은 없다. 어쨌든 외부 코드를 사용해야 한다면, 그 코드에 대해 알아야 하므로.
오히려 필요한 지식만 확보하는 손쉬운 방법이다.
학습 테스트는 투자하는 노력보다 얻는 성과가 더 크다.
학습 테스트는 패키지가 예상되로 도는지 검증한다. 패키지의 새 버전이 나올 때마다 또 다시 검증할 수도 있다.
즉, 반대로 이야기하면 이런 경계 테스트가 있다면 패키지의 새 버전으로 이전하기 쉬워진다.
그렇지 않다면 낡은 버전을 필요 이상으로 오랫동안 사용하려는 유혹에 빠지기 쉽다.
아직 존재하지 않는 코드를 사용하기
만약 A 팀의 소프트웨어가 B 팀의 소프트웨어를 기반해서 동작한다면, A 팀은 B 팀이 개발을 완료할 때까지 기다려야 할까? 아니다!
A 팀은 자체적으로 인터페이스를 정의할 수 있다.
A 팀이 바라는 인터페이스를 구현하면 A 팀이 인터페이스를 전적으로 통제한다는 장점이 생긴다.
또한 코드 가독성도 높아지고 코드 의도도 분명해진다.
이후 B 팀이 개발을 완료하면 그제서야 A 팀의 자체적인 인터페이스에 연결만 하면 된다.
이와 같은 설계는 테스트도 아주 편하다. 적절한 FakeTransmitter 클래스를 사용하면 CommunicationsController 클래스를 테스트할 수 있다. Transmitter API 인터페이스가 나온 다음 경계 테스트 케이스를 생성해 우리가 API를 올바로 사용하는지 테스트할 수도 있다.
깨끗한 경계
경계에서는 흥미로운 일이 많이 벌어진다. 변경이 대표적인 예다.
소프트웨어 설계가 우수하다면 변경하는데 많은 투자와 재작업이 필요하지 않다.
경계에 위치하는 코드는 깔끔히 분리한다. 또한 기대치를 정의하는 테스트 케이스도 작성한다.
통제 불가능한 외부 패키지에 의존하는 대신 통제가 가능한 우리 코드에 의존하는 편이 훨씬 좋다.
Map의 예시처럼, 새로운 클래스로 경계를 감싸거나 ADAPTER 패턴을 사용해 우리가 원하는 인터페이스를 패키지가 제공하는 인터페이스로 변환하자.
'클린 코드' 카테고리의 다른 글
[클린 코드] 10장: 클래스 (0) | 2022.12.21 |
---|---|
[클린 코드] 9장: 단위 테스트 (0) | 2022.12.04 |
[클린 코드] 7장: 오류 처리 (0) | 2022.12.02 |
[클린 코드] 6장: 객체와 자료 구조 (0) | 2022.11.29 |
[클린 코드] 5장: 형식 맞추기 (0) | 2022.11.29 |