- 출처: 도메인 주도 설계 - 에릭 에반스
- S/W 에서 표현되는 모델
S/W 에서는 모델을 표현하는 주요 패턴으로 3가지 형태가 주로 사용된다.
- Entity: 어떤 객체가 영속성과 식별성을 지닐 때
- VO: 다른 무언가의 상태를 기술하는 속성에 불과할 때
- Service: 객체보다 행동/연산으로 더 명확하게 표현되는 경우
자바라면 class, Golang 이라면 struct로 표현하기만 하면 되는데 왜 굳이 Entity와 VO라는 개념을 도입해서 나누는지 의문을 가질 수도 있다. 굳이 이렇게 하는 이유는 특정 객체가 특정 패턴을 따르면 객체의 역할이 더욱 명확해져서 설계 결정을 하는데 도움이 되기 때문이다.
Entity와 VO만 있으면 객체를 표현할 수 있는데 Service라는 개념은 왜 필요할까? 어떤 비즈니스 모델을 설계하다보면 어떤 객체보다는 어떤 행위나 연산으로 더 명확하게 표현되는 경우가 있다. 이럴 경우 억지로 Entity나 VO로 책임을 전가하기보다는 Service 로 모델을 표현하는것이 더 적절하다고 할 수 있다.
- 연관관계(Association)
UML을 사용하거나 공부해본적이 있다면 association에 대한 개념을 알고 있을것이다. 비즈니스 모델링을 할 때 객체들이 서로 관계를 맺게 되는데 이런 설계를 실제로 구현할 때 간단하게 끝나는 경우도 있지만 까다로운 경우도 많다.
예를 들어 비즈니스 모델에서 고객과 영업사원이 있을 수 있다. 이런 모델은 실세계에서 두 사람을 추상화 한것으로 생각할 수 있다. 이들이 맺는 관계를 프로그램에서 표현한다면 두 객체간의 주소값 참조로 나타낼 수 있다. 만약 DB를 사용한다면 DB에서의 조회를 캡슐화한것으로 생각할 수도 있을것이다.
즉 만약 1:N의 다중성을 프로그램으로 구현 한다면 아래 중 하나의 방식으로 구현할 수 있다.
- 인스턴스 변수가 Collection을 들고 있는 방식
- 접근자 메소드(getter) 호출 시 DB 조회 후 인스턴스화 하여 반환해주는 방식
실세계 업무 관계가 모두 1:N 이면 비즈니스 모델을 표현할 때 훨씬 수월하겠지만, 실세계의 업무 관계는 M:N으로 표현되는 경우가 많다. 이를 모델링하여 어플리케이션으로 구축할 때 그대로 M:N으로 똑같이 표현하면 업무 규칙이 매우 복잡해진다. 이때는 추상화와 필요 없는 연관관계를 과감하게 제거하는것이 중요한데 아래와 같이 3 가지의 팁을 따르면 유용한 경우가 많다.
- 탐색 방향을 부여한다.
- 한정자(qualifier)를 추가하여 다중성(multiplicity)를 줄일 수 있다.
- 중요하지 않은 연관관계를 제거한다.
- 탐색 방향을 부여한다.
위에서 3 가지의 팁을 언급했지만 예제를 살펴보지 않으면 구체적으로 이해하기가 쉽지 않다. 국가와 대통령의 관계를 한번 생각해보자.
현실세계에서는 국가와 대통령은 서로 탐색이 가능하다. 즉, "미국의 대통령들은 누구인가?"라는 식으로 관계가 있을 수 있으며, "트럼프는 어느 나라 대통령인가?"라는 관계도 있을 수 있다. 이런 현실관계를 충실하게 반영해서 양쪽으로 탐색이 가능하계 설계 했다면 이는 훌륭한 모델링일까?
어플리케이션에서 "미국의 대통령은 누구인가?"라는 기능은 필요하지만 "트럼프는 어느 나라 대통령인가?"라는 기능이 필요하지 않다면 국가 -> 대통령의 탐색방향만을 반영한 모델링이 훨씬 간단하여 이해하기 쉬울것이다.
물론 현실은 이처럼 간단하지 않아서 특정 대통령이 어느 나라의 대통령인지에 대한 기능도 필요할 수 있다. 하지만 여기서 말하고자 하는 핵심은 그런 기능이 당연히 필요할 수 있지 않느냐라는 것이 아니라 어플리케이션에서 필요 없는 연관관계를 제거하여 모델링을 단순화 시키는것이 중요하다는것이다.
- 한정자(qualifier)
한정자라는 단어가 익숙하지 않을것이다. 나도 그렇다. 한정자란 쉽게 말해서 조건을 추가해서 범위를 확실하게 한다는 개념이다. 앞에서 예를 들었던 국가와 대통령의 관계를 다시 가져와보자.
앞에서의 모델링에 의하면 미국 -> 대통령은 1:N 이다. 일장한 년도 주기로 대통령이 여러명이기 때문이다. 여기에 특정 조건을 추가해서 "xxxx년도에 미국을 통치했던 대통령은 누구인가?" 라는 식으로 년도를 추가해주면 1:N의 연관관계에서의 다중성이 1:1로 줄어들게 된다.
위는 UML로 이를 나타낸것이다. 조그마한 네모박스가 한정자를 나타낸다.
그래서 이를 어떻게 코드로 표현할 수 있는가? 한정자는 아래와 같이 보통 parameter로 나타날 가능성이 크다.
func (c country) GetPresident(year string) string {
v, ok := c.presidentOfYear[year]
if !ok {
return ""
}
return v
}
위의 코드와 같이 년도마다 대통령을 보관하는 map을 갖고 있는것이 썩 나이스하다고 볼수는 없지만 중요한 점은 그냥 GetPresidents()와 같이 호출하여 모든 대통령의 Collection을 가져오는 것이 아니라 year라는 parameter(qualifier)로 해당 년도의 특정 대통령만을 조회하고 있다는 점이다.
'Concepts > SW Design' 카테고리의 다른 글
DDD - 도메인 객체의 lifecycle과 Aggregate (0) | 2022.09.10 |
---|---|
DDD - Module (package) (0) | 2022.08.07 |
DDD - Service (0) | 2022.08.07 |
DDD - Value Object (0) | 2022.07.19 |
DDD - Entity (0) | 2022.07.17 |
댓글