비즈니스 로직 코드를 모델링하고 구현하는 다양한 방법
트랜잭션 스크립트
정의
- 트랜잭션 스크립트 패턴은 프로시저를 기반으로 시스템의 비즈니스 로직을 구성하며 각 프로시저는 퍼블릭 인터페이스를 통해 시스템 사용자가 실행하는 작업을 구현( 약간 파사드 패턴같다.)
- 각 작업은 성공하거나 실패할 수 있지만 유효하지 않은 상태를 만들면 안된다.
트랜잭션 동작 구현 실패
전체를 아우르는 트랜잭션 없이 여러 업데이트를 하는 경우
- Void aaFacade() { 함수1(); 함수2() }
- @Transaction 함수1() {}
분산 트랜잭션에서 통합할 수 없는 여러 개의 저장 장치로 작업(약간 msa에서 트랜잭션을 한번에 할 수 없는 경우)
- 분산 시스템: 데이터 변경 -> 메세지 발행 -> 다른 컴포넌트에 알림
암시적 분산 트랜잭션
- 작업을 멱등성으로 만들기
- 함수 파라미터에 특정 값을 넘겨서 처리하기 (?)
- 낙관적 동시성 제어
- 매개변수로 특정 값을 넘겨서 처음 읽은 값과 동일한 경우에만 카운터 값을 업데이트 (jpa version)
트랜잭션 스크립트를 사용하는 경우
- 일반 모놀로직 같은 느낌(?)
- 간단한 도메인에 효과적
- 단순한 지원 하위 도메인에 적합
액티브 레코드
정의
- 데이터베이스 접근을 캡슐화하고 해당 데이터 도메인 로직을 추가하는 오브젝트
- 약간 무엇을 거쳐서 접근함(프록시?)
액티브 레코드 사용하는 경우
- 단순한 경우 사용
- 복잡한 자료구조에서도 작동 가능
- 액티브 레코드라는 전용 객체를 사용하여 표현
- ORM과 관련이 있음
- 캡슐화 - 유효성 검사 및 데이터 조작을 한다.
- 지원 하위 도메인. 일반 하위 도메인
전술적 도메인 주도 설게 - 애그리게이트, 밸류 오브젝트, 레포지토리 등 도메인 모델 패턴을 구현하는 데 효과적인 도구의 집합
도메인 모델
- 비즈니스 로직을 다루기.
- CRUD 인터페이스 대신 복잡한 상태 전환, 비즈니스 규칙과 불변성 등을 다룬다.
- 본질적으로 복잡 - 복잡성을 추가하면 안됨
- DB, 외부 시스템 호출 구현, 인프라 또는 기술적인 관심사를 피해야한다.
- => 플레인 올드 오브젝트
밸류 오브젝트(VO)
정의
- 값을 가지고 있는 객체, 복합적인(composition) 값에 의해 식별되는 객체
- Color - 색을 식별하기 위한 명시적인 식별 필드가 필요 없음
VO의 구현
- String, integer 등 원시 데이터 타입에 전적으로 의존해서 표시하는 것은 위험하다.
- Class Account { private String password }
- 결국에는 validation 체크를 해야한다.
- 유효성 검사 로직이 중복되기 쉽다.
- VO를 사용해서 코드 작성
- Class Account { private Password password} - 내부에 비밀번호 조건이 들어있음
- 명료성 향상
- 유효성 검사 로직이 VO자체에 있다.
- 다른 예시로는 Height - 특정 도량형에 종속되지 않는다.
- Money - 원, 달러에 종속되지 않는다.
- 좀더 직관적이고 실수가 적은 객체 모델을 사용할 수 있다.
- VO는 불변의 객체로 구현되므로 필드가 바뀌면 다른 객체가 생성됨
- 동일성 검사(equals) 함수를 오버라이드해서 적절히 구현하는 것이 중요
밸류 오브젝트를 사용하는 경우
- 코드의 표현력, 안정성 향상 => 부작용, 동시성 문제가 없다.
- 다른 객체의 속성을 표현하는 도메인 요소에 사용 (Password)
엔티티
정의
- 다른 엔티티 인스턴스와 구별하기 위해 명시적인 식별 필드가 필요하다. => ORM에서 엔티티라고 표현하는 이유가 아닐까?
- Class Person { private String name }
- 같은 이름을 가진 사람이 있을 수 있다.
- 사람을 식별하기 위한 personId 가 필요하다.
- 앤티티의 식별 필드는 인스턴스마다 고유해야한다.
- 앤티티는 불변이 아니라 변할 것으로 생각된다.
- 대신 엔티티의 식별 필드는 불변이여야 한다.
애그리게이트
정의
- 애그리게이트는 엔티티다.
- 식별 필드가 필요하고 인스턴스의 생애주기 동안 상태가 변할 것으로 예상된다.
- 앤티티 그 이상이다.
- 데이터 일관성 보호
일관성 강화
- 변경 요청을 검사해서 비즈니스 규칙에 위배되지 않게 해야한다.
- 비즈니스 로직을 통해서만 애그리게이트의 상태를 변경하게 해야한다.
- 메서드를 실행해야만 상태를 변형
- => 커맨드
- 약간 JPA에 편의 메서드 or Setter 사용하지 않고 메서드 사용하는 예시가 되지 않을까 싶다.
- 동시성 점검
- 트랜잭션이 커밋한 변경을 나중의 트랜잭션이 은연중에 덮어쓰지 않게 해야한다.
트랜잭션 경계
- 자신의 비즈니스 로직을 통해서만 수정될 수 있기 때문에 트랜잭션의 경계 역할을 한다.
- 상태가 수정되면 모든 변경이 커밋되거나 롤백되어야 한다.
- 애그리게이트의 경계가 비즈니스 도메인의 불변성과 규칙을 따르도록 신중히 설계되어야한다.
다른 애그리게이트 참조하기
- 애그리게이트 내의 모든 객체는 같은 트랜잭션 경계를 공유하기 때문에 커지면 성능과 확장에 문제가 생긴다.
- 비즈니스 로직에 따라 강력한 일관성이 필요한 정보만 애그리게이트에 포함돼야한다.
- 외부 애그리게이트를 참조할 때 ID를 이용하는 이유는 경계에 속하지 않음을 명확히 하고 트랜잭션 경계를 갖게 보장하기 위함이다.
- 이부분이 JPA에서 연관관계의 경계를 말하는 것 같다.
- Class Ticket { Message customerId, productId, agentId }
class Ticket { @ManyToOne private Message message; private Long customerId; private Long productId; private Long agentId; }
- 애그리게이트에 속하는지 판단하는 방법
- 일관된 데이터를 다루는 상황에서 시스템의 상태를 손상시킬 수 있는지 여부 판단
- 그 비즈니스 로직이 애그리세이트에 있는지 여부 판단

애그리게이트 루트
- 커맨드 중 하나를 실행해서만 수정 가능하다.
- 엔티티 계층 구조를 대표하기 때문에 루트로 지정되어야 한다.
- 이것이 JPA 강의에서 연관관계 주인(?)부분이 아닐까 싶다.
- 그리고 커멘드가 편의 메서드가 되는듯하다.
- 애그리게이트 루트를 통해서만 수정 가능하다.

도메인 이벤트
- 외부에서 애그리게이트와 커뮤니케이션 할 수 있는 다른 메커니즘
- 비즈니스 도메인에서 일어나는 중요한 이벤트를 설명하는 메세지
- 자신의 도메인, 다른 프로세스, 외부 시스템 - MSA일때 이런방식으로 하지 않을까?
도메인 서비스
- 비즈니스 로직을 구현한 상태가 없는 객체다.(stateless object)
- 티켓 애그리게이트 예제
- 제한된 시간 내에 고객에게 솔루션 제시
- 시간은 다양한 출처에서 정보를 필요로 하는 경우에 도메인 서비스 구현한다.
- => 여러 애그리게이트의 데이터를 읽는 것을 도와줌
복잡성 관리
- 시스템 자유도
- 시스템 상태를 설명하는데 필요한 데이터 요소의 개수로 측정
class A {
private int a;
private int b;
private int c;
private int d;
private int e;
}
class B {
private int _a;
private int _b;
public int A {... B, C 사용}
public int B {}
public int C {}
public int D { E 사용}
public int E
}
- classA 상태 설명하는데 얼마나 많은 데이터 요소가 필요한가 -> 5
- classB 상태 설명하는데 얼마나 많은 데이터 요소가 필요한가 -> 2 (A, D) 의 값만 계산하면 나머지 변수는 추론 가능
- classA가 classB보다 더 간단해보이지만 실제로는 복잡하다
- 이것이 애그리게이트와 밸류 오브젝트를 사용하는 이유이다.
결론
도메인 모델을 어떻게 설게하냐에 따라 복잡도가 많이 차이나는것 같다.
'책 > 도메인 주도 설계 첫걸음' 카테고리의 다른 글
| 아키텍처 패턴 (0) | 2023.02.28 |
|---|---|
| 시간 차원의 모델링 (0) | 2023.02.28 |
| 바운디드 컨텍스트 연동 (0) | 2023.02.28 |
| 도메인 복잡성 관리 (1) | 2023.02.28 |
| 비즈니스 도메인 분석하기 (0) | 2023.02.28 |