애그리거트

이재서·2026년 7월 13일

애그리거트란?

에릭 에반스는 애그리거트를 "데이터 변경의 단위로 취급되는 연관 객체의 묶음"이라고 정의했다.

내가 읽고 있는 『도메인 주도 개발 시작하기』에서는 이를 조금 더 이해하기 쉽게 설명한다.

복잡한 도메인을 이해하고 관리하기 쉬운 단위로 만들기 위해 상위 수준에서 조망할 수 있는 모델

결국 애그리거트는 관련 있는 객체들을 적절한 경계 안으로 묶어서 복잡도를 낮추는 역할을 한다.

덕분에 도메인을 바라보기가 쉬워지고, 기능을 수정하거나 확장할 때도 영향 범위를 예측하기가 훨씬 수월해진다.

애그리거트의 특징을 정리해 보면 다음과 같다.

  • 복잡한 도메인을 단순한 구조로 만든다.
  • 하나의 애그리거트에 속한 객체들은 비슷하거나 동일한 라이프사이클을 가진다.
  • 하나의 객체는 하나의 애그리거트에만 속한다.

애그리거트의 경계는 어떻게 나눌까?

애그리거트의 경계를 정하는 기준은 객체 간의 연관관계가 아니라 도메인 규칙과 요구사항이다.

경계를 정하는 과정에서 자주 당하는 함정이 있다.

"A가 B를 가진다"는 사실만으로 A와 B가 같은 애그리거트인 것은 아니다.

처음에는 포함 관계가 있으면 같은 애그리거트라고 생각하기 쉬운데, 실제 기준은 함께 생성되고 함께 변경되는지 여부다.

즉,

  • 항상 함께 생성되는가?
  • 변경되는 시점도 대부분 같은가?
  • 하나의 규칙 안에서 함께 관리되어야 하는가?

이런 질문에 "그렇다"라고 답할 수 있다면 같은 애그리거트일 가능성이 높다.


애그리거트 루트(Aggregate Root)

애그리거트 안에는 여러 객체가 존재한다.

하지만 이 객체들이 마음대로 상태를 변경하면 애그리거트의 일관성은 쉽게 깨질 수 있다.

그래서 애그리거트에는 모든 변경을 책임지는 대표 객체, 즉 애그리거트 루트(Aggregate Root)가 존재한다.

애그리거트 루트의 가장 중요한 역할은 단 하나다.

애그리거트의 일관성을 지키는 것

이를 위해 루트는 애그리거트가 제공해야 하는 모든 도메인 기능을 구현한다.

그래서 DDD에서는 몇 가지 원칙을 강조한다.

  • 애그리거트 외부에서 내부 객체를 직접 수정하지 않는다.
  • setXXX()처럼 상태를 무분별하게 변경하는 public Setter를 만들지 않는다.
  • Value Object는 가능하면 불변 객체로 구현한다.
  • 내부 객체들을 조합해서 필요한 기능을 완성한다.

결국 상태 변경은 항상 애그리거트 루트를 통해서만 이루어져야 한다.


트랜잭션도 애그리거트 단위로 생각한다

DDD에서 가장 많이 강조되는 원칙 중 하나가 있다.

한 트랜잭션에서는 하나의 애그리거트만 수정한다.

여러 애그리거트를 동시에 수정하기 시작하면 결합도가 높아지고, 일관성을 유지하기 어려워진다.

만약 두 개 이상의 애그리거트를 함께 수정해야 한다면,

애그리거트가 서로를 직접 수정하는 것이 아니라 응용 서비스(Application Service)가 각각의 애그리거트를 호출해서 변경하도록 구현하는 것이 권장된다.


리포지터리도 애그리거트 단위다

리포지터리 역시 엔티티 하나가 아니라 애그리거트 단위로 존재한다.

즉,

  • 리포지터리는 애그리거트 전체를 저장한다.
  • 조회할 때도 완전한 애그리거트를 반환한다.
  • 변경 사항 역시 하나의 원자적인 작업으로 저장한다.

결국 리포지터리는 애그리거트의 생명주기를 관리하는 역할이라고 이해하면 될 것 같다.


다른 애그리거트는 ID로 참조한다

애그리거트도 다른 애그리거트와 관계를 맺는다.

하지만 DDD에서는 객체 자체를 참조하기보다 ID를 통해 참조하는 방식을 권장한다.

처음에는 조금 불편해 보였지만 이유를 알고 나니 충분히 납득이 갔다.

객체를 직접 참조하면 여러 문제가 생길 수 있다.

1. 다른 애그리거트를 쉽게 수정하게 된다.

객체가 바로 연결되어 있으면 의도하지 않게 다른 애그리거트의 상태를 변경하기 쉬워진다.

결국 애그리거트의 경계가 무너지게 된다.

2. 조회 전략을 계속 고민해야 한다.

직접 참조하면 Lazy Loading과 Eager Loading을 상황마다 고민해야 한다.

ID만 가지고 있다면 필요한 시점에만 조회하면 되므로 이런 고민이 줄어든다.

3. 시스템 확장에 유리하다.

서비스가 커지면 도메인별로 DB를 분리하거나 마이크로서비스로 나누는 경우가 생긴다.

이때 객체 참조에 의존하면 구현이 어려워질 수 있지만, ID만 사용한다면 저장소나 기술이 달라져도 비교적 유연하게 대응할 수 있다.

그래서 DDD에서는 애그리거트 간에는 ID를 이용해 참조하는 방식을 권장한다.


마무리

애그리거트는 단순히 객체를 묶는 기술이 아니라는 것이다.

오히려 도메인의 경계를 명확하게 만들고, 변경의 범위를 통제하기 위한 설계 방법에 더 가깝다.

애그리거트 루트를 통해 상태를 변경하고, 트랜잭션과 리포지터리 역시 애그리거트 단위로 관리한다.

아직은 작은 프로젝트에서는 필요성을 크게 체감하지 못할 수도 있지만, 도메인이 복잡해질수록 왜 DDD에서 애그리거트를 중요한 개념으로 다루는지 조금씩 이해하게 되는 것 같다.

profile
아무거나 쓰는 중

0개의 댓글