🚩 높은 추상화 수준, 즉 깨끗한 시스템을 유지하는 방법
"체계적이고 탄탄한 시스템을 만들고 싶다면 흔히 쓰는 좀스럽고 손쉬운 기법으로 모듈성을 깨서는 절대로 안 된다." (p.196)
💻 시스템 제작과 시스템 사용을 분리하라
제작(Construction): 어플리케이션 객체를 제작하고 의존성을 서로 연결하는 과정
사용(Use): 제작 과정 이후 이어지는 런타임 과정
관심사(Concern) 분리
가장 흔히 쓰이는 초기화 지연(Lazy Initialization)의 한계
public Service getService() {
if (service == null)
service = new MyServiceImpl(...);
return service;
}
MyServiceImpl
이 모든 상황에 적절하지 않을 수 있음
MyServiceImpl
생성자 인수에 의존함
- 단위 테스트 시 테스트 전용
service
객체를 할당해야 함
- 객체 생성 로직의 모든 실행 경로를 테스트해야 함
- 단일 책임 원칙(SRP)에 반함
Main 분리
- 생성과 관련한 코드는 모두 main이나 main이 호출하는 모듈로 옮긴다.
- 나머지 시스템은 모든 객체가 생성되었고 모든 의존성이 적절히 연결되었다고 가정하고 객체를 사용한다.
팩토리
- Abstract Factory Pattern 사용
- 어플리케이션은
LineItem
인스턴스를 생성해 Order
에 추가한다.
- 어플리케이션은
LineItem
을 생성하는 코드는 모르지만, 생성하는 시점을 통제할 수 있다.
의존성 주입
- DI 컨테이너를 통해 의존성 관리
- Setter 메소드 or 생성자 인수를 통해 의존성 주입
- DI 컨테이너는 요청이 들어올 때 필요한 객체의 인스턴스를 만든 후 의존성 설정
💻 확장
"'처음부터 올바르게' 시스템을 만들 수 있다는 믿음은 미신이다. 대신에 우리는 오늘 주어진 사용자 스토리에 맞춰 시스템을 구현해야 한다." (p.199)
EJB1, EJB2 예시
- 비즈니스 로직이 EJB2 어플리케이션 컨테이너에 강하게 결합됨
- Concern 분리가 적절히 이루어지지 않아 확장에 어려움이 생김
Cross-cutting concern
- 어플리케이션의 객체 경계를 넘나드는 concern
- 이러한 concerns 역시 모듈화할 수 있음
- AOP(Aspect-Oriented Programming)는 cross-cutting concern에 대처해 모듈성을 확보하는 일반적인 방법론
💻 자바 Aspect 메커니즘
자바 프록시
- 프록시 API를 직접 사용하면 깨끗한 코드를 작성하기 어렵다.
- 프록시는 시스템 단위로 실행 지점을 명시하는 메커니즘도 제공하지 않아 직접적인 해결책이 될 수 없다.
순수 자바 AOP 프레임워크
- 프레임워크를 통해 POJO로 비즈니스 로직을 구현할 수 있다.
- POJO는 프레임워크에 의존하지 않고 비교적 단순하기 때문에 코드 작성이 편하다.
- 클라이언트가 직접 객체를 호출한다고 믿지만, 실제로는 객체를 감싼 프록시, 라이브러리 등과 통신하게 된다.
AspectJ 관점
- 언어 차원에서 aspect를 모듈화 구성으로 지원하는 자바 언어 확장
- 새 도구를 사용하고 새 언어 문법과 사용법을 익혀야 한다.
💻 테스트 주도 시스템 아키텍쳐 구축
- Aspect로 concern을 분리하는 방식 사용
- 어플리케이션 도메인 논리를 POJO를 작성
- 코드 수준에서 아키텍쳐 concern을 구분하고 모듈화
💻 원칙
의사 결정을 최적화하라
- 가장 지엽적인 부분까지도 가장 적합한 사람이 책임을 맡아야 한다.
- 최후의 순간에 최신 정보에 기반한 최적의 결정을 내려야 한다.
명백한 가치가 있을 때 표준을 현명하게 사용하라
- 단지 표준이라는 이유로 사용하지 말아야 한다.
- 핵심 가치를 바탕으로 유연하게 선택해야 한다.
시스템은 도메인 특화 언어가 필요하다
DSL(Domain-Specific Language)
- 간단한 스크립트 언어나 표준 언어로 구현한 API
- 도메인 개념과 그 개념을 구현한 코드 사이 간극을 최소화
- 모든 추상화 수준과 모든 도메인을 POJO로 표현