시스템에 들어가는 모든 소프트웨어를 직접 개발하는 경우는 드물다. 때로는 패키지를 사고, 때로는 오픈 소스를 이용한다. 때로는 사내 다른 팀이 제공하는 컴포넌트를 사용한다. 어떤 식으로든 이 외부 코드를 우리 코드에 깔끔하게 통합해야만 한다.
외부 코드 사용하기
패키지 제공자나 프레임워크 제공자는 적용성을 최대한 넒히려 애쓴다. 더 많은 환경에서 돌아가야 더 많은 고객이 구매하니까. 반면, 사용자는 자신의 요구에 집중하는 인터페이스를 바란다.
한 예로 Map은 다양한 인터페이스를 제공한다. 하지만 그만큼 위험도 크다.
• clear() void – Map
• containsKey(Object key) boolean – Map
• containsValue(Object value) boolean – Map
• entrySet() Set – Map
• equals(Object o) boolean – Map
• get(Object key) Object – Map
• getClass() Class<? extends Object> – Object
• hashCode() int – Map
• isEmpty() boolean – Map
• keySet() Set – Map
• notify() void – Object
• notifyAll() void – Object
• put(Object key, Object value) Object – Map
• putAll(Map t) void – Map
• remove(Object key) Object – Map
• size() int – Map
• toString() String – Object
• values() Collection – Map
• wait() void – Object
• wait(long timeout) void – Object
• wait(long timeout, int nanos) void – Object
Map을 깔끔하게 사용한 코드다. Sensors 사용자는 제네릭스가 사용되었는지 여부에 신경 쓸 필요가 없다. 제네릭스의 사용 여부는 Sensors 안에서 결정한다.
public class Sensors {
private Map sensors = new HashMap();
public Sensor getById(String id) {
return (Sensor) sensors.get(id);
}
// 이하 생략
}
경계 인터페이스인 Map을 Sensors 안으로 숨긴다. 따라서 Map 인터페이스가 변하더라도 나머지 프로그램에는 영향을 미치지 않는다. 제네릭스를 사용하든 하지 않든 더 이상 문제가 안 된다. Sensors 클래스 안에서 객체 유형을 관리하고 변환하기 때문이다.
경계 살피고 익히기
외부 코드를 사용하면 쉽고 빠르다. 하지만 이 코드의 테스트 및 안정성은 우리의 몫이다.
우리쪽 코드를 작성해 외부 코드를 호출하는 대신 먼저 간단한 테스트 케이스를 작성해 외부 코드를 익히면 어떻까?
짐 뉴커크는 이를 학습 테스트라 부른다.
학습 테스트는 프로그램에서 사용하려는 방식대로 외부 API를 호출한다. 통제된 환경에서 API를 제대로 이해하는지를 확인하는 셈이다. 학습 테스트는 API를 사용하려는 목적에 초점을 맞춘다.
Log4j 익히기
기초적인 "hello"를 출력하는 테스트 케이스를 한다.
@Test
public void testLogCreate() {
Logger logger = Logger.getLogger("MyLogger");
logger.info("hello");
}
테스트 케이스를 돌렸더니 Appender라는 오류가 나오고 이후에는 출력 스트림이 없다고 나온다. 그래서 코드를 수정한다.
@Test
public void testLogAddAppender() {
Logger logger = Logger.getLogger("MyLogger");
logger.removeAllAppenders();
logger.addAppender(new ConsoleAppender(
new PatternLayout("%p %t %m%n"),
ConsoleAppender.SYSTEM_OUT));
logger.info("hello");
}
위처럼 학습을 통해 지식을 얻는다.
학습 테스트는 공짜 이상이다.
학습 테스트는 이해도를 높여주면서 비용은 없는 실험이다.
학습 테스트는 공짜 이상이다. 투자하는 노력보다 얻는 성과가 더 크다. 패키지가 예상대로 도는지 검증한다. 일단 통합한 이후라고 하더라도 패키지가 우리 코드와 호환되라라는 보장은 없다.
아직 존재하지 않는 코드를 사용하기
경계와 관련해 또 다른 유형은 아는 코드와 모르는 코드를 분리하는 경계다. 때로는 우리 지식이 경계를 너머 미치지 못하는 코드 영역도 있다. 때로는 알려고 해도 알 수가 없다. 때로는 더 이상 내다보지 않기로 결정한다.
깨끗한 경계
경계에서는 흥미로운 일이 많이 벌어진다. 변경이 대표적인 예다. 소프트웨어 설계가 우수하다면 변경하는데 많은 투자와 재작업이 필요하지 않다. 엄청난 시간과 노력과 재작업을 요구하지 않는다. 통제하지 못하는 코드를 사용할 때는 시간과 노력이 많이 필요하다.
'책 > Clean Code' 카테고리의 다른 글
[Clean Code] 4장 주석 (0) | 2022.09.20 |
---|---|
[Clean Code] 3장 함수 (0) | 2022.09.19 |
[Clean Code] 2장 의미 있는 이름 (2) | 2022.09.17 |
[Clean Code] 1장 깨끗한 코드 (1) | 2022.09.16 |
[Clean Code] 7장 오류 처리 (0) | 2022.09.14 |