Blog

도메인 주도 개발 시작하기(1)

도메인 주도 개발 시작하기(1)

1-1. 도메인이란?

도메인 (domain): 소트프트웨어로 해결하고자 하는 문제 영역
1개의 도메인은 하위 도메인으로 더 나눌 수 있다
e.g.)
한 하위 도메인은 다른 하위 도메인과 연동하여 완전한 기능을 제공한다
특정 도메인을 위한 소프트웨어라고 해서 도메인이 제공해야 할 모든 기능을 직접 구현하는것은 아니다
일부 기능을 자체 시스템으로 구현하고, 나머지 기능은 외부 업체의 시스템을 이용할 수 있다
도메인마다 고정된 하위 도메인이 존재하는 것은 아니다

1-2. 도메인 전문가와 개발자 간 지식 공유

개발에 앞서 요구사항을 올바르게 이해하는것이 중요하다
요구사항을 올바르게 이해하는 방법에는 여러가지 방법이 있지만 비교적 간단한 방법은 개발자와 전문가가 직접 대화 하는것이다
개발자와 전문가 사이에 내용을 전파하는 전달자가 많으면 많을수록 정보가 왜곡되고 손실이 발생하게 되며, 최초 요구사항과 다른걸 만들게 된다
전문가 만큼은 아니지만 이해관계자와 개발자도 도메인 지식을 갖춰야 한다
Garbage in, Garbage Out! → 잘못된 값이 들어가면 잘못된 결과가 나온다 → 전문가나 관련자가 요구한 내용이 항상 올바른 것은 아니며 때론 본인들이 실제로 원하는 것을 정확하게 표현하지 못할 때도 있다 → 개발자는 요구사항을 이해할 때 왜 이런 기능을 요구하느지 또는 실제로 원하는 게 무엇인지 생각하고 전문가와 대화를 통해 진짜로 원하는것을 찾아야 한다

1-3. 도메인 모델

도메인 모델: 특정 도메인을 개념적으로 표현하는 것
도메인을 이해하려면 도메인이 제공하는 기능과 도메인의 주요 데이터 구성을 파악해야 한다
기능과 데이터를 함께 보여주는 객체 모델은 도메인을 모델링하기 적합하다
도메인 모델을 표현할 때 클래스 다이어그램이나 상태 다이어그램과 같은 UML 표기법만 사용해야 하는 것은 아니다
관계가 중요한 도메인이라면 그래프를 이용해서 도메인을 모델링할 수 있다
도메인을 이해하는데 도움이 된다면 표현 방식이 무엇인지는 중요하지 않다
도메인 모델은 기본적으로 도메인 자체를 이해하기 위한 개념 모델이다
개념 모델을 이용해서 바로 코드를 작성할 수 있는 것은 아니기에 구현 기술에 맞는 구현 모델이 따로 필요하다
개념 모델과 구현 모델은 서로 다른것이지만 구현 모델이 개념 모델을 최대한 따르도록 할 수는 있다
하위 도메인과 모델
도메인은 다수의 하위 도메인으로 구성된다
각 하위 도메인이 다루는 영역은 서로 다르기 때문에 같은 용어라도 하위 도메인마다 의미가 다를 수 있다
도메인에 따라 용어 의미가 결정되므로 여러 하위 도메인을 하나의 다이어그램에 모델링하면 안된다
각 하위 도메인마다 별도로 모델을 만들어야 한다

1-4. 도메인 모델 패턴

도메인 모델은 아키텍처 상의 도메인 계층을 객체 지향 기법으로 구현하는 패턴을 말한다
일반적인 애플리케이션 아키텍처는 4개의 영역으로 구성된다
표현 ( User interface or Presentation )
사용자의 요청을 처리하고 정보를 보여준다
사용자는 소프트웨어를 사용하는 사람뿐만 아니라 외부 시스템일 수도 있다
응용 (Application)
사용자가 요청한 기능을 실행한다
비즈니스 로직을 직접 구현하지 않으며 도메인 계층을 조합해서 기능을 실행한다
도메인
시스템이 제공할 도메인 규칙을 구현한다
인프라스트럭처
데이터베이스나 메시징 시스템과 같은 외부 시스템과의 연동을 처리한다
도메인 계층은 도메인의 핵심 규칙을 구현한다
e.g.)
예시 코드
도메인 모델 이란 용어는 도메인 자체를 표현하는 개념적인 모델을 의미하지만, 도메인 계층을 구현할 때 사용하는 객체 모델을 언급할 때에도 도메인 모델 이란 용어를 사용한다
개념 모델과 구현 모델
개념 모델은 순수하게 문제를 분석한 결과물이다
데이터베이스, 트랜잭션 처리, 성능, 구현 기술과 같은것을 고려하고 있지 않다
개념 모델을 구현 가능한 형태의 모델로 전환하는 과정을 거치게 된다
개념 모델을 만들 때 처음부터 완벽하게 도메인을 표현하는 모델을 만드는 시도를 할 수 있지만, 실제로 이것은 불가능하다
소프트웨어를 개발하는 동안 개발자와 관계자들은 해당 도메인을 더 잘 이해하게 된다
프로젝트 초기에 이해한 도메인 지식이 시간이 지나 새로운 통찰을 얻으면서 완전히 다른 의미로 해석되는 경우도 있다
프로젝트 초기에 완벽한 도메인 모델을 만들더라도 결국 도메인에 대한 새로운 지식이 쌓이면서 모델을 보완하거나 변경하는 일이 발생한다
처음부터 완벽한 개념 모델을 만들기보다는 전반적인 개요를 알 수 있는 수준으로 개념 모델을 작성해야 한다

1-5. 도메인 모델 도출

도메인을 모델링할 때 기본이 되는 작업은 모델을 구성하는 핵심 구성요소, 규칙, 기능을 찾는것이다
요구사항에서 도메인 모델을 점진적으로 만들어나갔다
일부는 구현수준까지 만들고, 일부는 이름 정도만 결정했다
요구사항에서 출발하여 만든 모델은 요구사항 정련을 위해 도메인 전문가나 다른 개발자와 논의하는 과정에서 공유하기도 한다
모델을 공유할 때는 화이트보드나 위키와 같은 도구를 사용해서 누구나 쉽게 접근할 수 있도록 하면 좋다
문서화
문서화를 하는 주된 이유는 지식을 공유하기 위함이다
실제 구현은 코드에 있으므로 코드를 보면 다 알 수 있지만, 코드는 상세한 모든 내용을 다루고 있기 때문에 코드를 이용해서 전체 소프트웨어를 분석하려면 많은 시간을 투자해야 한다
전만적으로 상위 수준에서 정리한 문서를 참조하는 것이 소프트웨어 전반을 빠르게 이애하는데 도움이 된다
전체 구조를 이해하고 더 깊게 이해할 필요가 있는 부분을 코드로 분석해나가면 된다
도메인 지식이 잘 묻어나도록 코드를 작성하지 않으면 코드의 동작 과정은 해석할 수 있어도 도메인 관점에서 왜 코드를 그렇게 작성했는지 이해하는 데는 도움이 되지 않는다

1-6. 엔티티와 밸류

도출한 모델은 엔티티(Entity)밸류(Value) 로 구분할 수 있다
엔티티와 밸류를 제대로 구분해야 도메인을 올바르게 설계하고 구현할 수 있다
이 둘의 차이를 명확하게 이해하는 것은 도메인을 구현하는 데 있어 중요하다

1-6-1. 엔티티

엔티티의 가장 큰 특징은 식별자를 가진다
식별자는 엔티티 객체마다 고유해서 각 엔티티는 서로 다른 식별자를 갖는다
e.g.) 주문 도메인에서는 각 주문은 주문번호를 가지고 있는데, 이 주문번호는 각 주문마다 서로 다르다
엔티티의 식별자는 변경되지 않는다
엔티티의 식별자는 변경되지 않고 고유하기 때문에 두 엔티티 객체의 식별자가 같으면 두 엔티티는 같다고 판단할 수 있다

1-6-2. 엔티티의 식별자 생성

엔티티의 식별자는 다음 중 한가지 방식으로 생성한다
1.
특정 규칙에 따라 생성
2.
UUID 나 Nano ID 와 같은 고유 식별자 생성기 사용
3.
값을 직접 입력
4.
일련번호 사용 (Sequence 나 DB 의 Auto Increment Column 사용 )
리포지터리(Repository) 는 도메인 객체를 데이터베이스에 저장할 때 사용하는 구성요소이다
Auto Increment Column 을 사용할 경우 Repository 는 DB 가 생성한 식별자를 구해서 엔티티 객체에 반영한다

1-6-3. 밸류 타입

밸류 타입은 개념적으로 완전한 하나를 표현할 때 사용한다
예시 코드
밸류 타입이 꼭 두 개 이상의 데이터를 가져와야 하는 것은 아니다
의미를 명확하게 표현하기 위해 밸류 타입을 사용하는 경우도 있다
밸류 객체의 데이터를 변경할 때는 기존 데이터를 변경하기도바는 변경한 데이터를 갖는 새로운 밸류 객체를 생성하는 방식을 선호한다
밸류 타입을 불변으로 구현하는 이유
안전한 코드를 작성할 수 있다

1-6-4. 엔티티 식별자와 밸류 타입

엔티티 식별자를 위한 밸류 타입을 사용해서 의미가 잘 드러나도록 할 수 있다
예시 코드

1-6-5. 도메인 모델에 set 메서드 넣지 않기

도메인 모델에 get/set 메소드를 무조건 추가하는 것은 좋지 않은 버릇이다
set 메소드는 도메인의 핵심 개념이나 의도를 코드에서 사라지게 한다
불변 밸류 타입을 사용하면 자연스럽게 밸류 타입에는 set 메소드를 구현하지 않게 된다
set 메소드를 구현해야 할 특별할 이유가 없다면 불변 타입의 장점을 살릴 수 있도록 밸류 타입은 불변으로 구현해야 한다
DTO 의 get/set 메소드
DTO (Data Transfer Object) 는 프레젠테이션 계층과 도메인 계층이 데이터를 서로 주고받을 때 사용하는 일종의 구조체이다
DTO 가 도메인 로직을 담고 있지 않기 때문에 get/set 메소드를 제공해도 도메인 객체의 데이터 일관성에 영향을 줄 가능성이 높지 않다

1-7. 도메인 용어와 유비쿼터스 언어

에릭 에반스는 도메인 주도 설계에서 언어의 중요함을 강조하기 위해 유비쿼터스 언어(Ubiquitous Language) 라는 용어를 사용했다
코드를 작성할 때 도메인에서 사용하는 용어는 매우 중요하다
예시 코드
최대한 도메인 용어를 사용해서 도메인 규칙을 코드로 작성하게 되므로 (의미를 변환하는 과정에서 발생하는) 버그도 줄어든다
이해 관계자, 개발자가 도메인과 관련된 공통의 언어를 만들고 사용하면 소통 과정에서 발생하는 용어의 모호함을 줄일 수 있다