운이 좋게 조영호님 도메인 주도 설계의 사실과 오해 강의를 들을 수 있었습니다.
- DDD의 철학이 담긴 에릭 에반스의 도메인 주도 설계 책에 내용을 설명해주셨고 이에 대해서 요약한 글입니다.
DDD는 복잡한 도메인 문제를 소프트웨어로 해결하기 위한 사고 방식이자 우선 순위등의 패턴이다.
- 특정한 기술과는 무관한 사고 방식이다.
1️⃣ 동작하는 도메인 모델 만들기
도메인 정의
- 사용자가 프로그램을 사용하는 주제 영역을 의미한다.
사용자가 음식을 배달시키는 플로우
- 메뉴를 선택한다. (사용자)
- 특정 가게에서 음식을 주문한다. (사용자)
- 조리 (식당)
- 배달 (기사님)
- 결제 (사용자)
- 식사 (사용자)
모델
도메인 대상의 단순화로 당면한 문제를 해결하는 것과 관련된 측면을 추상화하고 중요하지 않은 세부사항은 생략한다.
- 위에 플로우에서 배달 도메인을 소프트웨어로 치환할 수 있는 메뉴, 주문, 결제 모델로 분리할 수 있다.
도메인 모델
- 사용자가 프로그램을 사용하는 주제 영역안에서 모델이라고 생각하면 된다.
지식 탐구와 모델링
도메인 전문가와 개발자 사이의 커뮤니케이션을 통해서 유비쿼터스 언어를 정의하고 활발한 논의를 거쳐 유용한 도메인 모델을 만드는것
모델 주도 설계
모델과 설계는 서로 영향을 주며 반복을 통해 구체화된다.
- 코드가 변경 ↔ 핵심 설계와 도메인 모델도 함께 변경
- 기술적인면은 덜어내고 도메인만 바라보고 모델링 해야한다.
- 코드 자체가 도메인을 의미하기 때문에 코드 레벨에서 도메인을 알 수 있어야 한다.
도메인 주도 설계란(DDD)
값객체, 엔티티, 팩토리, 애그리게이트 와 같은 기술적인 것에 의존하는 것이 아니다.
도메인 전문가와 개발자가 함께 지식을 탐구하여 함께 도메인을 모델을 만드는 것이다.
- 도메인 모델은 실제로 코드와 일치해야 하는데 커뮤니케이션에서 사용한 유비쿼터스 언어를 활용해야 한다.
- 소프트웨어가 해결해야 하는 문제영역의 복잡성을 낮추기 위함이다.
2️⃣ 모델 주도 설계의 빌딩 블록(전술적 패턴)
객체지향과 도메인 주도 설계
1990~2000년대 GUI 부흥으로 객체의 시대가 열렸었다.
- 대부분의 도메인 로직은 클라이언트에 위치했다.
웹이 부상으로 클라이언트에서 도메인 로직을 처리하기 힘들어 서버로 내려가게 되었다.
분산 객체 기술의 유행
분산 객체의 네트워크 통신을 위해 미들웨어(EJB 컨테이너)를 도입 했다.
- 각 미들웨어마다 트랜잭션, 보안, 영속성 개념 도입
- 컨테이너의 기술적인 지원을 받기 위해 EJB가 강요하는 인터페이스나 추상클래스 상속 문제가 발생
- 즉, 도메인과 EJB 환경 둘 다를 고민하면서 기술 관심사와 도메인 관심사가 혼재되었다.
POJO(Plain Old Java Object)
객체 지향적인 원리에 충실하면서 환경과 기술에 종속되지 않고, 필요에 따라 재활용될 수 있는 방식으로 설계된 오브젝트
- 즉, 어떤 기술에 종속받지 않은 순수한 객체
- 로드 존슨 - 어떤 특정한 구현 기술보다 객체지향 설계가 더 중요하다.
- 스프링의 기원 - EJB 컨테이너를 경량 컨테이너로 대체하면서 일반 객체를 써도 트랜잭션, 영속성을 사용할 수 있게 도와준다.
도메인 로직의 격리
도메인 주도 설계의 전제 조건은 도메인 구현을 격리하는 것이다.
- 도메인이 다른 계층으로 새어나가면 안된다.
- DDD에서 클린 아키텍처, 헥사고날 아키텍처를 이야기 하는 이유도 도메인 로직과 기술적인 요소를 분리하는 구조를 만들기 위해서 비교적 잘 변하지 않는 Entity를 바라볼 수 있도록 하기 위해서 인거 같다.
모델 주도 설계의 빌딩 블록
구현 가능한 도메인 모델을 구성하는 요소들의 목록
도메인을 표현하기 위한 빌딩 블록 (값타입, 엔티티, 서비스, 모듈등)
- 키워드로 도메인을 분류
생명주기를 관리하기 위한 빌딩 블록 (애그리거트, 리포지토리, 팩토리등)
- 객체의 라이프 사이클을 통해서 분류
- 예를 들면 주문 상품(고객이 주문을 접수하고 배달이 완료되기 까지) 리뷰(배달이 완료되고 이후)는 라이프 사이클이 다르니까 분류할 수 있을거야 느낌이 아닐까 싶다.
빌딩 블록의 목적
- 구현에 대한 가이드를 제공해서 복잡도를 낮추기 위함
애그리거트(Aggregate)
불변식을 만족시키는 객체 그룹 단위로 어떤 제약사항(불변식)에 따라 한 객체의 변경이 다른 객체에 영향을 미치는 경우를 방지할 수 있다.
- 한 트랜잭션 단위로 애그리거트 단위를 정할 수 있다.
- 애그리거트가 불변식 단위고 그 단위로 수정을 하기 때문이다.
- 애그리거트 단위로 리포지토리를 생성한다. (Aggregate Root)
- 복잡성 감소를 위해 애그리거트 간에는 ID를 이용한 참조
- JPA에서 애그리거트 단위로 읽어오니까 지연로딩을 안쓰는 경우도 있다.
- 같은 애그리거트는 객체참조를 하고 끊어진 애그리거트는 ID 참조를 하면 코드 레벨에서 애그리거트 단위를 확인하기 쉽다.
- 여러 애그리거트를 수정해야 하는 경우 별도 트랜잭션으로 분리한다.
- 예) 주문이 완료되면 사용자의 총 주문수 +1 해야 하는 경우 결과적 일관성(Eventually Consistent)에 따라서 트랜잭션을 분리한다.
- 도메인의 특성에 따라서 다르겠지만 ACID와 대조적으로 가용성과 성능을 중시하는 특성을 가진 분산 시스템의 특성인 BASE 개념
3️⃣ 더 심층적인 통찰력을 향한 리팩터링
- 애자일과 도메인 주도 설계
왜 코드 작성 전에 완벽하게 설계할 수 없을까?
- 사실 초반에 명확한 요구사항이라는 것은 없고 개발을 진행하면서 변경되고 개선되면서 점점 명확해진다.
왜 일정을 제대로 추정하지 못할까?
코드를 짜다보면 내가 생각하는 것보다 일정이 촉박하다.
- 단순 반복적인 일을 하는 것 아니라면 애초에 추정이 불가능하다.
- 상황에 따라 일정을 재조정하는 능력이 더 중요하다.
유연하지 못한 개발 방법
- 시작할 때 전체 일정을 계획한다. (분석 -> 설계 -> 구현 -> 테스트)
- 즉, 과도한 사전 설계
애자일
분석, 설계는 변경될테니 변화에 민첩하게 대응하는 방법
- XP
- 도메인 전문가와 개발자가 함께 유비쿼터스 언어로 커뮤니케이션 하며 지속적으로 도메인 모델을 리팩터링
1. 개발은 반복주기를 통해 진행되어야 한다.
도메인 주도 설계의 핵심은 도메인 모델의 리팩터링이다.
- 도메인 모델의 변경 ↔ 코드의 변경
2. 개발자와 도메인 전문가는 밀접한 관계를 가져야 한다.
- 유비쿼터스 언어를 함께 만들고 커뮤니케이션에 이용
- 함께 도메인 모델을 창조
- 도메인 전문가와 개발자가 함께 도메인에 대한 통찰을 반영해 도메인 모델을 리팩터링
4️⃣ 전략적 설계 (전략적 패턴)
중복에 대한 강박관념
하나의 도메인 모델에 모든 데이터를 다 넣는 경우 응집도가 낮고 복잡성이 증가하게 된다.
실무에서 중복이란?
실무를 하다보면 결합도나 응집도에 비하면 중복은 그렇게 중요하지 않다.
- 각자 팀마다 표현하기 편한대로 중복을 적당히 두는게 더 유용할 때가 많다. (DTO 등)
- A가 바뀔 때 B가 계속 같이 따라와서 수정하는게 중복이지 코드가 같다고 중복이 아니다.
단일 도메인 모델
- 기능 추가와 코드 수정 시 충돌이 일어날 수 있다.
- 통제하기 어려운 사이드 이펙트가 발생할 수 있다.
- 협업 오버헤드가 증가된다.
- 같이 배포해야 하기 때문에 릴리즈 일정을 협의해야 한다.
- 의미적 충돌로 인한 언어의 모호함이 발생하게 된다. (유비쿼터스 언어를 정의하는 이유)
- 서로 다른 컨텍스트에 필요한 코드들의 집합이 생기게 된다.
- 각각의 팀에서 같이 사용하는 도메인의 의미가 다르기 때문에 문제가 발생할 수 있다.
사용하는 컨텍스트에 따라 모델을 분리하자
바운디드 컨텍스트(Bounded Context)
특정한 도메인 모델이 적용되는 범위
- 같은 바운디드 컨텍스트 안에는 도메인 모델의 통합성을 유지하지만 서로 다른 바운디드 컨텍스트 사이에는 통합성에 신경 쓰지 않는다.
같은 이름의 도메인 모델이 컨텍스트에 따라서 의미가 다르고 컨텍스트 단위로 Presentation → Domain → Persistence 쪼개기 때문에 SOA(Service-Oriented Architecture)보다는 MSA 구조에 적합한거 같다.
컨텍스트 맵 (Context Map)
컨텍스트 사이의 관계와 모델 변환 방식 정의
- 각각의 바운디드 컨텍스트는 팀 단위로 관리되는데 DDD에서는 팀 간에 커뮤니케이션은 어떻게 할건지, 팀 간의 관계를 어떻게 정립할건지 정치와 협력의 영역의 이야기도 포함되어 있다.
- 즉 DDD는 값객체, 엔티티, 팩토리, 애그리게이트 와 같은 기술적인 것에 의존하는 것이 아니다.
전략적 디스틸레이션
도메인에서 중요하지 않은 문제에 더 많은 노력을 기울이지 않고 전체 도메인 모델은 시스템에서 가장 가치를 더하고 특별한 측면을 부각시켜야 한다. (코어 도메인)
- 혼란을 줄이고 적절히 주의를 집중하면 많은 노력이 시스템에서 가장 중요한 부분으로 향하게 되고 시스템 비전을 놓치지 않게 된다.
도메인에 따른 리소스 분배
- 큰 도메인을 여러 서브도메인으로 나누자
코어 도메인:
사업에 성공을 결정하는 핵심적인 서브도메인으로 회사에서 최고의 실력자를 배정한다.
제네릭 서브도메인:
타사의 여러 애플리케이션에 공통으로 존재하는 서브도메인으로 기성 소프트웨어를 구입하거나 주니어 개발자를 배정한다.
지원 서브도메인:
비즈니스의 일부로 코어 도메인을 지원하는 도메인으로 외주로 해결하거나 개발자들의 성장을 위한 기회로 활용하자
즉, 전략적 디스틸레이션의 핵심은 리소스를 집중할 영역과 시스템 구축 방법을 결정하는 것이다.
📚 참조
'개발' 카테고리의 다른 글
Spring에서 @Async 사용하기 (0) | 2024.06.17 |
---|---|
java에서 이미지 작업 및 최적화하기 (0) | 2024.06.11 |
Getter 없이 Test해보기 (1) | 2023.11.24 |
EnumMap 적용하기! (1) | 2023.11.08 |
매직넘버, 리터럴 어디까지 상수 처리해야 돼? (4) | 2023.11.06 |