- 소프트웨어 경계를 깔끔하게 처리하는 기법을 알 수 있다
1. 외부 코드 사용하기
- 인터페이스 제공자는 적용성을 최대한 넓히려 한다
- 인터페이스 사용자는 자신의 요구에 집중하는 인터페이스를 바란다
- 이러한 양방향의 차이로 인해 시스템 경계에서 문제가 생길 수 있다
Map
- 외부 라이브러리 중 컬렉션이 있고 이중 자주 쓰이는 것으로 java.util.Map이 있다
- 이 맵은 api로 clear, containsKey, entrySet 등의 다양하고 많은 함수를 제공한다
- Map 인터페이스가 변할 경우 해당 인터페이스를 사용해서 만든 인스턴스가 많다면 수정할 코드가 많아진다
- 일급 콜렉션을 사용한다면 Map을 콜렉션으로 숨기면서 불변성도 보장할 수 있고 해당 일급 콜렉션만 수정하면 되기에 변경의 범위가 축소된다
- 즉 Map 인스턴스를 공개 API의 인수로 넘기거나 반환값으로 사용하지 않는다
경계 살피고 익히기
- 간단한 테스트 케이스(학습 테스트)를 작성해서 외부 코드를 익힌다
- 프로그램에서 사용하려는 방식대로 외부 API를 호출한다
- 통제된 환경에서 API를 제대로 이해하는지 확인하며 API를 사용하려는 목적을 명확하게 인지한다
@Test
public void testLogCreate(){
Logger logger = Logger.getLogger("MyLogger");
logger.info("hello");
}
@Test
public void testLogCreate(){
Logger logger = Logger.getLogger("MyLogger");
ConsoleAppender appender = new ConsoleAppender();
logger.addAppender(appender);
logger.info("hello");
}
@Test
public void testLogCreate(){
Logger logger = Logger.getLogger("MyLogger");
logger.removeAllAppenders();
logger.addAppender(new ConsoleAppender(
new PatternLayout("%p %t %m%n"),
ConsoleAppender.SYSTEM_OUT));
logger.info("hello");
}
public class LogTest {
private Logger logger;
@Before
public void setup() {
logger = Logger.getLogger("logger");
logger.removeAllAppenders();
Logger.getRootLogger().removeAllAppenders();
}
@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 %m%n")));
logger.info("addAppenderWithoutStream");
}
}
- 학습 테스트를 함으로써 API에 대한 이해도를 높이고 새로운 버전으로 업데이트 되더라도 기존에 작성한 학습 테스트를 통해 호환성 체크도 할 수 있고 그에 따른 적용도 가능하다
3. 아직 존재하지 않는 코드를 사용하기
- 경계의 또 다른 유형은 아는 코드와 모르는 코드를 분리하는 것이다
- 협업을 하다보면 아직 다른 팀에서 완성하지 못한 API를 사용해야 하는 경우가 있다
- 다른 팀에서 아직 API를 제작하지 못했다면 해당 API에서 인터페이스를 추출해 Controller에서 분리한 뒤 Fake 구현체를 생성해서 사용하며, API가 제작이 완료되면 Adapter를 이용해 간극을 메워준다
- 이렇게 Fake 구현체 클래스를 사용하면 controller도 테스트 할 수 있다
깨끗한 경계
- 외부 패키지를 호출하는 코드를 줄여 경계를 관리하며 새로운 클래스나 Adapter patter을 이용한다
- 외부 패키지의 수정이나 변경에 대응 범위가 작아지고 경계를 분명히 해 코드 가독성이 높아진다
개인적인 감상
- 가장 처음 맡았던 프로젝트에서 외부 api를 사용했었는데 그때 adater 패턴에 대해 알았다면 조금 더 깔끔하게 만들 수 있었지 않았을까 싶다
- 테스트 케이스를 만들어 본 적이 없기 때문에 외부 api를 호출할 때 학습 테스트를 만든다는 것을 처음 알았다
- 일급 컬렉션이라는 개념이 제대로 정립되지 않아서 추가적인 검색이 필요하다
일급 컬렉션
- Collection을 Wrapping하면서, Wrapping한 Collection 외 다른 멤버 변수가 없는 상태를 일급 컬렉션이라 한다
public class Person {
private String name;
private List<Car> cars;
}
public class Car {
private String name;
private String oil;
}
public class Person {
private String name;
private Cars cars;
}
public class Cars {
private List<Car> cars;
}
public class Car {
private String name;
private String oil;
}
- 일급 컬렉션은 List cars 외 다른 멤버 변수가 없다
- 일급 컬렉션을 사용하면 상태과 로직을 따로 관리할 수 있기 때문에 로직이 사용되는 클래스의 부담을 줄일 수 있고, 중복코드를 줄일 수 있다