728x90

1. 외부 코드 사용하기

시스템에 들어가는 모든 소프트웨어를 직접 개발하는 경우는 드물다

개발하다 보면 패키지나 오픈 소스를 사용하게 되는데

이런 소스를 제공하는 입장에서는 더 많은 환경에서 돌아갈 수 있도록 적용성을 넓히려고 애쓴다

하지만 사용자 입장에서는 자신의 요구에 집중하는 인터페이스를 바라게 된다

이런 차이에서 경계가 발생한다

 

java.util.Map 을 예로 들어보자

Map은 마음만 먹으면 사용자는 어떤 객체 유형도 추가하거나 삭제할 수 있다

Map을 만들어서 여기저기 넘긴다고 가정한다면 어디서든 삭제나 추가가 가능하다는 문제가 생긴다

또한 Map 인터페이스가 변경될 경우 수정할 코드 양이 상당히 많아진다

Map<String, Sensor> sensors = new HashMap<Sensor>;
Sensor s = sensors.get(sensorId);

경계 인터페이스인 Map을 Sensors 안으로 숨겨보자

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

Map 인터페이스가 변하더라도 나머지 프로그램에는 영향을 미치지 않는다

또한 Sensors 클래스는 프로그램에 필요한 인터페이스만 제공한다

 

여기서 주의할 점은 모든 경계 인터페이스를 사용할 때마다 캡슐화하라는 뜻이 아니며,

이러한 경계 인터페이스를 이용할 때 이를 이용하는 클래스나 클래스 계열 밖으로 노출되는 것을 지양해야 한다

따라서 Map 인스턴스를 공개 API에 인수로 넘기거나 반환값으로 사용하지 않아야 한다


2. 경계 살피고 익히기

외부 코드는 익히기도 어렵고 통합하기도 어렵다

우리쪽 코드를 작성해 외부 코드를 호출하는 대신

먼저 간단한 테스트 케이스를 작성해 외부 코드를 익히는 것을 추천!

이를 학습 테스트라 부른다

 

학습 테스트는 프로그램에서 사용하려는 방식대로 외부 API를 호출한다

통제된 환경에서 API를 제대로 이해하는지 확인하는 셈이다

학습 테스트는 API를 사용하려는 목적에 초점을 맞춘다


3. log4j 익히기

아파치 log4j 패키지로 학습 테스트의 예를 들어보자

public class LogTest {
    private Logger logger;
    
    @Before
    public void initialize() {
        logger = Logger.getLogger("logger") ;
        logger.removeAl(Appenders();
        Logger.getRootLogger().removeAl LAppenders ();
    }
    
    @Test
    public void basicLogger() {
        BasicConfigurator.configure();
        logger.info("basicLogger");
    }
    
    @Test
    public void addAppenderWithStream() {
        logger.addAppender(new ConsoleAppender(
        new PatternLayout ("%p %t %m%n"),
        ConsoleAppender.SYSTEM_OUT)) ;
        logger. info("addAppenderWithStream");
    }

    @Test
    public void addAppenderwithoutStream() {
        logger.addAppender(new ConsoleAppender(
        new PatternLayout("p %t %Pon)));
        logger.info("addAppenderWithoutStream");
    }
}

4. 학습 테스트는 공짜 이상이다

학습 테스트는 투자하는 노력보다 얻는 성과가 더 크다

학습 테스트가 예상대로 동작하는지 검증할 수 있고,

패키지의 새 버전이 나온다면 학습 테스트를 돌려 차이가 있는지 확인이 가능하다

이러한 경계 테스트가 있다면 패키지의 새 버전으로 이전하기 쉬워진다

그렇지 않다면 낡은 버전을 필요 이상으로 오랫동안 사용하려는 유혹에 빠지기 쉽다


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

경계와 관련해 또 다른 유형은 아는 코드와 모르는 코드를 분리하는 경계이다

모르는 코드 부분을 인터페이스를 통해 구현하게 되면 모르는 코드 부분도 함께 통제할 수 있게 된다

나중에 해당 부분에 설계가 완료되었을 때 인터페이스를 상속받아 구현시키면 테스트도 더 쉽게 진행할 수 있다


6. 깨끗한 경계

통제하지 못하는 코드를 사용할 때는 너무 많은 투자를 하거나 향후 변경 비용이 지나치게 커지지 않도록 각별히 주의해야 한다

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

외부 패키지에 의존하는 대신 인터페이스를 통해 통제가 가능한 우리 코드에 의존하도록 해야 한다

클래스로 경계를 감싸는 방식 등을 통해 외부 패키지를 호출하는 코드를 가능한 줄여서 경계를 관리해야 한다

 

어느 방법이든 코드 가독성이 높아지며,

경계 인터페이스를 사용하는 일관성도 높아지며,

외부 패키지가 변했을 때 변경할 코드도 줄어든다


마무리 느낀 점

외부 라이브러리를 사용하는 경우는 굉장히 빈번하다

사용하던 라이브러리의 버전이 업데이트되면서 기존의 소스를 변경해야 되는 일도 꽤 있었다

책에서 나온 내용처럼 그런 부분 때문에 굉장히 오래된 버전을 사용하는 경우도 많았다

테스트 코드의 중요성을 다시 한번 느낄 수 있었던 챕터였다

728x90

'개발 서적 > 클린코드' 카테고리의 다른 글

클린코드 - 9.단위 테스트  (0) 2022.08.06
[Study] 2022/07/18  (0) 2022.07.30
클린코드 - 7.오류 처리  (0) 2022.07.05
클린코드 - 6.객체와 자료 구조  (0) 2022.06.05
클린코드 - 5.형식 맞추기  (0) 2022.06.04
복사했습니다!