일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- spring cloud netflix zuul
- Dynamic Routing
- Eureka
- 탐색
- java #jvm #reference #gc #strong reference
- BFS
- unittest
- spring cloud netflix eureka
- 서비스스펙
- container image #docker #layer #filesystem #content addressable
- Spring Data Redis
- spring cloud netflix
- docker
- reactive
- dfs
- code refactoring
- unit
- springcloud
- zuul
- netflix eureka
- test
- forkandjoinpool #threadpool #jvm #async #non-blocking
- Java
- 단위테스트
- microservice architecture
- 설계
- spring cloud
- netflix
- api-gateway
- Today
- Total
phantasmicmeans 기술 블로그
DDD Quickly - 3. 모델 주도 설계 본문
기본적으로 우리는 비즈니스 도메인에 깊이 뿌리내린 모델을 만들어야한다. (핵심 개념을 매우 정확하게 반영하는 모델을 만들어야한다.)
그 다음 우리는 이 모델들을 코드로 구현하는 작업을 수행한다. 최고의 모델을 만들었음에도 코드로 적절하게 바꾸지 못하면, 결국 신뢰할 수 없는 소프트웨어가 만들어진다.
어느 도메인이든 다양한 모델로 표현되고, 각 모델들은 다양한 코드로 표현될 수 있다. 또한 특정 문제에 대한 해법도 여러가지 일 수 있다.
우리는 이중 무엇을 택할 것인가?
우리가 품게되는 근본적인 질문은 모델을 코드로 어떻게 변환할 것인가?
하는 것이다.
분석 모델 설계 기법
- 코드 설계와 분석을 분리하고
- 분석과 코드 설계를 보통 서로 다른사람이 작업하도록 한다.
- 분석 모델은 비즈니스 도메인 분석 결과물일 뿐이고,
소프트웨어 구현은 염두에 두지 않는다
.
이를 바탕으로 만들어진 모델은 분석적인 측면에서는 올바른 모델이다.
- BUT 코드 설계를 염두에 두지 않은 모델이기에 코드 설계 작업을 하기 수월하지 않음
- 개발자들은 모델과의 별개의 설계를 하기도 함 > 모델과 코드 사이에 더 이상 매핑 관계가 존재하지 않게 된다.
분석 모델
의 주요 이슈 중 하나는 분석가들이 분석 모델에 내재된 결함이나 도메인 자체의 복잡성을 미리 알 수 없다는 것이다.
- 매우 중요한 세부 사항들이 설계하고 구현하는 과정에서 발견되기도 한다.
- 도메인에 충실한 모델이 객체의 영속성에 대해 심각한 문제를 지녔거나 수용 불가능할 수도 있음
- 결국 개발자들의 의지에 따라 어떤 결정을 내려야 함 > 점점 기존 의도와는 다르게 다른 설계를 하게되며, 모델과는 점점 달라진다.
도메인 모델링과 설계를 밀접하게 관련시켜라
분석가들이 도메인에 대해 토론하고 상당한 지식을 공유하는데, 이 정보들을 다소 압축된 형태로 모델을 통해 표현하고 개발자들은 이 문서를 해독함으로써 모든것을 이해해야한다.
개발자들이 분석가들의 회의에 함께 참여하고, 코드를 설계하기 전에 도메인과 모델을 명확하고 완전하게 이해하면 더 생산적일 것이다.
즉 도메인 모델링과 설계를 밀접하게 관련시켜야한다.
- 개발자들은 모델링 프로세스가 진행되는 동안 함께 참여한다.
- 소프트웨어로 정확하게 표현할 수 있는 모델을 선택하자
- 코드와 기반이 되는 모델을 밀접하게 연관시킴으로서, 코드에 의미가 생기고 모델은 실제적으로 중요한 가치를 지니게 된다.
- 개발자들을 피드백 제공자로 동참시켜라 (모델이 소프트웨어로 구현될 수 있다는 것을 보장할 수 있다.)
모델 주도 설계를 위한 블록
이미지출처 : http://www.infoq.com/minibooks/domain-driven-design-quickly
계층형 아키텍처
일을 빨리 처리하는 가장 쉬운 방법이기 때문이기에, 비즈니스 로직이 UI 의 행위나 데이터베이스 스크립트에 포함되기도 한다.
- 도메인과 관련된 코드가 다른 레이어에 섞여있다면 코드를 읽고 이해하기가 어렵다.
- UI에 가해지는 변화가 비즈니스 로직에 변화를 줄 수 있다.
- 비즈니스 규칙을 변경할때에도 UI/데이터베이스 코드 등 다른 요소까지 일일이 검토해야한다.
이는 응집성 있는 구현이나 모델 기반 객체가 전혀 현실적이지 않게 되고, 자동화된 테스트도 어려워진다. 그렇기에 복잡한 프로그램을 레이어
로 분할해야한다.
- 각 레이어내부에서 설계를 수행하여 응집도 높고 하위 레이어에만 의존해야한다.
- 하나의 레이어에 도메인과 관련된 코드를 집중시켜서, 사용자 인터페이스, 애플리케이션, 인프라 코드로부터 독립시켜야한다.
도메인 객체들은 스스로 정보를 보여주고 저장하고 애플리케이션 작업을 관리하는 등의 부가적인 책임에서 자유롭게 두고 도메인 모델 자체를 표현하는 것에 집중할 수 있도록 한다.
도메인 주도 설계를 위한 공통 아키텍처 수준의 해결안은 다음 4가지의 개념적 레이어를 포함한다.
- 사용자 인터페이스(Presentation): 정보를 보여주고 사용자의 명령을 해석하는 책임을 진다.
- 애플리케이션 레이어: 애플리케이션의 활동을 조율하는 레이어.업무 로직을 포함하지 않는다. 비즈니스 객체의 상태를 보관하지 않지만, 애플리케이션 작업의 처리상태는 보관한다.
- 도메인 레이어: 업무 소프트웨어의 심장, 비즈니스 객체 상태를 포함한다. 비즈니스 객체와 그들의 상태를 영속화하는 책임은 인프라스트럭처 레이어로 위임된다.
- 인프라스트럭처 레이어
도메인 레이어는 핵심 도메인 이슈에만 집중하면 된다.
인프라스트럭처의 행동에 관여하면 안된다. 마찬가지로 UI도 비즈니스 로직이나 인프라스트럭처 레이어에 속하는 작업과 밀접하게 연관되어서는 안 된다.
엔티티
소프트웨어가 여러 상태를 거치는 동안에도 동일한 값을 유지하는 식별자
를 지니는 유형의 객체가 있다. 중요한 것은 속성이 아니라, 시스템의 전 생명주기 동안 또는 그 이상으로 확장될 수 있는 연속성과 식별성의 흐름이다.
이러한 객체를 엔티티
라고 부른다.
- 은행 계좌 시스템-
계좌번호
를 통해 개별 계좌를 식별한다. 주민등록번호
를 통해 사람을 식별한다.
엔티티
를 구현한다는 것은 식별자
를 만들어내는 작업이라해도 과언이 아니다. 서로 다른 식별자를 가진 두 객체를 시스템이 쉽게 구분할 수 있어야 한다는 점은 매우 중요하다.
엔티티는 도메인 모델에서 매우 중요한 객체들이고, 모델링 작업을 시작할 때 부터 깊이 고민해야한다.
더불어 어떤 객체를 엔티티로 봐야할지 여부를 결정하는 작업 또한 매우 중요하다.
값 객체
모든 객체가 엔티티로서 식별자를 가질 필요는 없다.
객체 자체가 아니라 그 객체가 가지는 속성에만 관심이 있는 경우가 있다. 즉, 하나의 객체가 도메인의 어떠한 측면을 표현하는데 사용되지만 식별자가 없는
경우이며, 우리는 이것을 값 객체라고 부른다.
- Point
- 단순히 화면의 좌표를 표현하는 속성 2개 (x, y)로 구성될 것이고, 이 값 객체는 식별자가 필요없다. 단지 좌표만이 중요할 뿐이다.
엔티티 정의에 부합하는 객체만을 선택하고, 나머지는 값 객체로 만들어라 > 설계가 단순화된다.
- 값 객체는 수정할 수 없게 만들어야한다.
- 다른 값을 지닌 값 객체가 필요하면 하나 더 생성하라.
- 수정 불가능하며 식별자가 없는 값 객체는 공유될 수 있다.
값 객체를 공유할 수 있다면 변경 불가능하게 만들어야 한다는 것이 하나의 황금률이다.
서비스
유비쿼터스 언어를 정의할 때 도메인의 핵심 개념이 나타나면 명사를 쉽게 객체로 매핑 가능하다. 또 명사와 연관되어 해당 객체의 행위를 나타내는 동사는
보통 객체의 행위 부분
이 된다. 그러나 도메인의 행위
가운데 어떤 행동이나 일부 동사는 어떤 객체에도 속하지 않는다.
이러한 행위를 어떤 객체에 추가하면 그 객체에 속하지도 않는 기능을 추가하는 셈
> 결과적으로 그 객체를 망칠 수 있다.
그러나 객체지향 언어를 사용할때에는, 우리는 객체를 행위를 포괄하는 용도로 사용해야한다. 행위는 한 객체에 포함되어야한다.
A 계좌 -> B 계좌 송금
- 이러한 기능은 보내는 계좌와 받는 계좌 중 어느쪽에 존재해야하나? 양쪽 어디에 두어도 잘못됨
- 이러한 유형의 행위가 도메인에서 식별되었을때 이러한 행위를
서비스
로 정의한다. 서비스
객체는 내부적인 상태를 가지지 않으면서 단순히 도메인에 기능을 제공하는 목적을 지님
서비스는 객체 자신이 아니라 오페레이션이 수행되는 대상이나, 목적이 되는 객체와 관련이 있다.
즉, 서비스는 많은 객체가 관계를 맺는 지점이 된다.
그렇기에 서비스의 행위들이 도메인 객체에 포함되면 안된다
일반적으로 서비스는 도메인 객체에 속하는 오퍼레이션을 대신하면 안된다. 그러나 오퍼레이션이 도메인에서 중요한 개념을 표현하고 있다면, 그것을 표현할 서비스를 만들어야한다.
서비스의 특징
- 서비스에 의해 수행되는 오퍼레이션은 일반적으로 엔티티 또는 값 객체에 속할 수 없는 도메인의 개념을 나타낸다.
- 수행되는 오퍼레이션은 도메인의 다른 객체를 참조한다.
- 오퍼레이션은 상태를 저장하지 않는다.
서비스를 사용할 때 도메인 레이어를 분리시켜야 한다는 점
은 매우 중요하다.
그러나, 만약 오퍼레이션이 개념적으로 어플리케이션 레이어에 속하는 일을 수행한다면 해당 서비스는 그 레이어에 존재하는 것이 맞다.
만약 오퍼레이션이 도메인 객체에 관한 것이고, 엄밀하게 도메인 레이어에 연관되어있으며 도메인에 필요한것을 제공하면 도메인 레이어
에 포함되어야 한다.
모듈
모듈화
란 관련된 개념과 작업을 조직화하여 복잡도를 감소시키는 기법
어떤 지점에 다다르면 모델 전체를 가지고 이야기하는 것이 힘들어지고 작은 부분들 간의 관계나 상호 작용을 이해하기도 어려워진다.
이러한 이유로 인해, 모델은 모듈
로 나누어 구조화 할 필요가 있다.
- 대규모 모델이더라도 모델에 속해있는 모듈과 이들의 관계를 중심으로 본다면 개요 파악이 쉬워진다.
- 모듈간의 상호작용을 이해하고, 하나하나의 모듈 내부를 파악하면 된다.
- 복잡도를 관리하는데 쉽고도 효율적이다.
모듈을 사용하는 또 다른 이유는 코드의 품질
때문
- 코드는 높은 응집도와 낮은 결합도를 가져야 함
- 응집도를 가능한 최대화하기위해
밀접한 관계를 지닌 클래스들을 하나의 모듈로
정의해야함
모듈은 다른 모듈이 접근할 수 있는 잘 정의된 인터페이스를
가져야함
- 모듈 내부에 있는 3개의 객체를 호출하는 대신 하나의 인터페이스에 접근할 수 있다면 후자가 결합도를 감소시키기 더 좋다.
시스템을 잘 설명할 수 있고, 응집도 높은 개념의 집합으로 구성되도록 모듈을 선정하라.
레퍼지토리
클라이언트가 DB에서 직접 값 객체 혹은 정보등을 조회하게 하지마라
- 데이터베이스를 통하면 대부분 객체들은 직접 정보를 얻을 수 있다. > 즉 엔티티부터의 참조가 불필요하다.
- 빠르고 간단해보이는 해결책이다.
많은 클라이언트가 DB로부터 직접 데이터를 땡겨와 객체를 생성하면, 이 코드들은 도메인 전체에 산재하게 된다.
- 이렇게 되면 도메인 모델은 위태로워진다.
- 이 상태에서 DB를 변경하기로 하면 여기저기 산재 되어 있는 코드 수정량이 클 것이다.
- 바로 DB에 존재하면 집합 내부의 객체를 복원할 수 있다. > 집합에 대한 캡슐화가 깨지는 것이다.
클라이언트는 이미 존재하는 도메인 객체의참조를 얻을 수 있는 실용적인 방법이 필요하다.
- 객체의 참조를 얻는 로직을 캡슐화하기 위해 `레퍼지토리`를 사용하라
- 레퍼지토리를 통해서만 다른 객체를 참조할 수 있게 되며, 모델은 명확해지고 목적에 집중할 수 있다.
직접 접근할 필요가 있는 집합 root에 대해서만 레퍼지토리를 제공한다. 클라이언트는 모델에만 집중하도록 하고 객체의 저장이나 접근과 관련된 내용은 레포지토리에 위임한다.
팩토리와 레퍼지토리는 모두 `도메인 객체의 생명주기`를 관리하는 역할을 한다.
- 팩토리는 객체의 생성에 관여
- 레퍼지토리는 이미 존재하는 객체들을 관리한다.
새로운 객체가 레퍼지토리에 추가되려면, 먼저 팩토리를 사용하여 만들어져야하며, 그 후에 이를 저장할 레퍼지토리에 전달되어야한다.
'DDD' 카테고리의 다른 글
DDD Quickly - 2. 유비쿼터스 언어 (0) | 2021.12.30 |
---|---|
DDD Quickly - 1. 도메인 주도 설계란 무엇인가? (0) | 2021.12.30 |