일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 추천 검색 기능
- 누적합
- gRPC
- 완전탐색
- 쿠키
- BFS
- 트랜잭샨
- 이분탐색
- ipo 매매자동화
- 레디스 동시성
- spring event
- 카카오
- AWS
- 디버깅
- 몽고 인덱스
- 백준
- 구현
- JPA
- 아키텍쳐 개선
- jwt 표준
- next-stock
- 결제서비스
- piplining
- 검색어 추천
- langgraph
- 크롤링
- docker
- 셀러리
- 프로그래머스
- ai agent
- Today
- Total
코딩관계론
애그리거트 본문
애그리거트 거크트의 목적
애그리거트 거크트(Aggregate Root)는 복잡한 도메인을 이해하고 효율적으로 관리하기 위한 핵심 개념입니다. 이것은 상위 수준에서 도메인을 조망하고, 이를 효율적이고 관리 가능한 단위로 나누기 위한 목적이 있습니다. 또한, 모델의 이해를 돕는 것뿐만 아니라 일관성을 관리하고 도메인의 복잡도를 낮춰 유지보수 시간을 최소화하는 역할을 수행합니다.

애그리거트 특징
애그리거트에 속한 구성 요소는 주로 함께 생성되고 함께 제거되는 특성을 가지고 있습니다. 이는 애그리거트가 단일 논리적 단위로 작동하며, 그 안의 모든 요소가 함께 일관된 상태를 유지할 수 있도록 해줍니다.
애그리거트 설정 방법
애그리거트를 설정할 때 가장 중요한 원칙은 도메인 규칙과 요구사항을 기반으로 하는 것입니다. 예를 들어, 아래의 코드에서 주문 모델을 생성할 때 Product 도메인을 생성하고, 해당 제품 정보를 주문 내역에 포함시키는 것을 확인할 수 있습니다. 이러한 정보들은 주문 시점에 생성되는 정보들로서, 한 애그리거트에 속하게 됩니다.
from typing import List
# 애그리거트 루트 엔터티 - Order
class Order:
def __init__(self, order_id, customer, items):
self.order_id = order_id
self.customer = customer
self.items = items
# 도메인 규칙에 따라 주문 내역 확인
def display_order(self):
print(f"Order ID: {self.order_id}")
print(f"Customer: {self.customer}")
print("Ordered Items:")
for item in self.items:
print(f" - Product: {item['product']}, Quantity: {item['quantity']}")
print("Total Price:", self.calculate_total_price())
# 도메인 규칙에 따라 총 주문 가격 계산
def calculate_total_price(self):
total_price = sum(item['quantity'] * item['product'].price for item in self.items)
return total_price
# 애그리거트의 구성요소 - Product
class Product:
def __init__(self, product_id, product_name, price):
self.product_id = product_id
self.product_name = product_name
self.price = price
# 예시 사용
if __name__ == "__main__":
# 상품 생성
product1 = Product(product_id=1, product_name="Laptop", price=1000)
product2 = Product(product_id=2, product_name="Mouse", price=20)
# 주문 생성
order_items = [
{"product": product1, "quantity": 2},
{"product": product2, "quantity": 1}
]
customer_order = Order(order_id=101, customer="John Doe", items=order_items)
# 주문 내역 출력
customer_order.display_order()
하지만 주의할 점이 있습니다. 특정 요구사항에 따라 A가 B를 가져야 한다면 이를 하나의 애그리거트로 구성할 수 있지만, 반드시 그렇지 않을 수도 있습니다. 예를 들어, 상품과 리뷰가 있는데, 모든 상품에 리뷰가 반드시 존재할 필요는 없으며, 상품 정보의 변경이 리뷰를 수정하는 것을 의미하지 않을 수 있습니다.

애그리거트 루트
역할
애그리거트의 루트 엔터티는 애그리거트에 속한 모든 객체가 일관된 상태를 유지하기 위한 주체입니다. 이 루트 엔터티는 도메인 기능을 제공하여 애그리거트 전체의 일관성을 관리합니다. 따라서, 애그리거트의 상태나 동작을 변경할 때는 주로 이 루트 엔터티를 통해 이루어져야 합니다.
제약사항
애그리거트 외부에서 직접 애그리거트에 속한 객체를 변경하지 않도록 하는 제약사항이 중요합니다. 이는 모델의 일관성을 유지하기 위한 것이며, 일반적으로 다음 두 가지 규칙을 적용합니다.
- 단순한 필드 변경을 set 메서드를 공개 범위로 만들지 않는다.
- 벨류 타입은 불변으로 구현한다.
아래의 코드에서는 Order 클래스와 OrderItem 클래스는 불변(frozen=True)으로 정의되어 있습니다. 따라서, 필드의 값을 변경하는 연산이나 set 메서드를 통한 변경이 불가능하게 되어 있습니다. 주문에 새로운 항목을 추가할 때는 add_item 메서드를 통해 새로운 불변의 OrderItem을 생성하여 추가합니다. 이를 통해 애그리거트 내의 객체를 변경하는 행위를 외부에서 제어하고, 모델의 일관성을 유지할 수 있습니다.
from dataclasses import dataclass
from typing import List
# 애그리거트 루트 엔터티 - Order
@dataclass(frozen=True)
class Order:
order_id: int
customer: str
items: List['OrderItem']
def add_item(self, product, quantity):
new_item = OrderItem(product, quantity)
self.items.append(new_item)
def display_order(self):
print(f"Order ID: {self.order_id}")
print(f"Customer: {self.customer}")
print("Ordered Items:")
for item in self.items:
print(f" - Product: {item.product}, Quantity: {item.quantity}")
print("Total Price:", self.calculate_total_price())
def calculate_total_price(self):
total_price = sum(item.product.price * item.quantity for item in self.items)
return total_price
# 애그리거트의 구성요소 - OrderItem (벨류 타입)
@dataclass(frozen=True)
class OrderItem:
product: str
quantity: int
# 예시 사용
if __name__ == "__main__":
# 주문 생성
order_items = [OrderItem(product="Laptop", quantity=2), OrderItem(product="Mouse", quantity=1)]
customer_order = Order(order_id=101, customer="John Doe", items=order_items)
# 주문 내역 출력
customer_order.display_order()
# 주문 항목 추가
customer_order.add_item(product="Keyboard", quantity=1)
# 주문 내역 갱신 후 출력
customer_order.display_order()
애그리거트의 일관성 유지를 위한 트랜잭션 제약
애그리거트의 일관성을 유지하기 위해서는 트랜잭션 범위도 제약해야 합니다. 애그리거트는 도메인 모델에서 일관성을 유지하고 관리하기 위한 단위이기 때문에, 한 모델에서 다른 모델의 영속성을 관리하는 것은 지양되어야 합니다. 이로 인해 일관성이 해치거나 결합도가 높아질 수 있습니다.
따라서, 특히 트랜잭션 범위를 명시하여 다른 모델에 영향을 미치지 않도록 주의해야 합니다. 즉, 한 애그리거트의 트랜잭션은 해당 애그리거트 내에서 완결되어야 하며, 다른 애그리거트에는 영향을 미치지 않아야 합니다. 이로써 전체 시스템이 안정적으로 동작하고 일관성을 유지할 수 있습니다.
'개발 > Domain Driven Design' 카테고리의 다른 글
아키텍처 개요 (1) | 2024.01.02 |
---|