우리는 일반적으로 서비스를 구현하기 위해 도메인 모델과 함께 사용자 인터페이스, 인프라스트럭처, 외부 서비스 연동 컴포넌트 등 다양한 것을 구현해야 하는데요.
이를 구현하는 데에 있어 아무런 설계 없이 진행할 경우 서비스가 점점 방대해짐에 따라 점차 유지 보수의 어려움을 겪게 될 것입니다.
르블랑의 법칙(Leblanc's Law) : 나중은 절대 돌아오지 않는다.
우리는 이러한 문제를 일으키지 않기 위해 코드를 구현하기 전 어떤 아키텍처를 수립할지를 먼저 결정해야 합니다.
이미지 출처)https://12bme.tistory.com/505이미지 출처)https://archfirst.org/domain-driven-design-6-layered-architecture
복잡한 비즈니스 로직을 처리하기 위해 코드에서 각각의 관심사를 분리하여, 좀더 확장성 있고, 유지보수가 용이하며, 테스트하기 쉬운 코드를 얻어낼 수 있습니다.
Tip: 여기서 관심사란 사용자에게 요청을 받아오거나, 사용자에게 요청을 받은 후 비즈니스 로직을 처리하는 하나의 과정들을 이야기합니다.
위 그림에서 보듯 상위 레이어에서 하위 레이어의 의존은 허용하고 있으나, 반대로 하위 레이어에서 상위 레이어로의 의존은 허용하고 있지 않습니다.
좀 더 엄격하게 아키텍처를 적용한다면, 상위 레이어는 바로 아래의 하위 레이어만 의존하도록 설계해야 합니다.
외부(웹 혹은 Event Queue 등)로부터 들어오는 요청을 응용 레이어(Application Layer)로 전달하는 역할을 하는 레이어입니다. 기본적으로 수행해야 하는 폼 데이터 체크 및 파라미터 검증 등 유효성 처리 또한 사용자 인터페이스 레이어(Presentation Layer)에서 담당합니다.
Controller 혹은 Message Queue로 부터 메시지를 컨슘하는 EventListener가 이에 해당될 수 있습니다.
사용자 인터페이스 레이어로부터 메시지를 받아 요청에 맞는 비즈니스 로직을 수행하는 레이어입니다.
도메인 모델을 이용해서 사용자에게 제공할 기능을 구현하게 되고, 실제 도메인 로직은 도메인 레이어에 위임하게 됩니다.
Service가 이에 해당될 수 있습니다.
도메인 레이어는 핵심 도메인 로직을 수행하는 레이어로 엔티티와 Value Object로 구성되어 있습니다.
이미지 예제에서는 핵심 로직을 보기 어려운 부분이 있으나,
주문 완료, 주문 취소, 배송지 변경 등이 핵심 도메인 로직이라고 할 수 있습니다.
이미지 출처)도서:DDD START!
실질적으로 데이터를 관리하기 위해 RDB를 연동하거나 필요에 따라서 NoSQL 연동을 담당하는 레이어입니다. 사용자 인터페이스, 응용, 도메인 레이어가 아닌 오로지 인프라스트럭처 레이어에서 구현 기술을 사용하게 됩니다.
각각의 레이어간 격리가 되어있고,
이 문제를 해결하기 위해 우리가 할 수 있는 방안은 바로 DIP를 적용하는 것인데요.
DIP란 '저 수준 모듈은 고수준 모듈에게 의존해야 한다'라는 SOLID의 원칙 중 하나로 의존 역전의 원칙이라 불립니다.
위 코드에서 DIP를 적용하는 방법은 간단합니다.
OrderRepository 인터페이스를 응용 레이어로 이동시키는 것인데요.
위 다이어그램을 보면 응용 레이어가 인프라스트럭처 레이어에 존재하는 모듈에 의존하지 않고, 반대로 인프라스트럭처 레이어의 모듈이 응용 레이어에 존재하는 인터페이스에 의존하고 있는 것을 볼 수 있습니다.