Orthogonal
Situation
다음과 같은 채팅 시스템을 가정해보겠습니다.
- 각 회사(Company)에는 여러 명의 유저(User)가 소속될 수 있다.
- 각 회사는 여러 개의 보관 정책(Retention Policy)을 가질 수 있다.
- 각 채팅방(Chat Room)은 하나의 회사에 소속된다.
- 각 채팅방은 하나의 보관 정책과 연관된다.
- 각 채팅방에는 여러 명의 유저가 멤버로 참여할 수 있다.
- 각 메시지(Message)는 하나의 채팅방에 속한다.
- 각 메시지는 하나의 작성자(User)를 가진다.
Entity-Based Design
RDBMS와 정규화를 배우고 현실세계의 비즈니스를 마주하면 아래와 같은 논리적 모델을 떠올리게 됩니다.

이 모델은 얼핏 보면 매우 자연스럽습니다.
회사, 유저, 채팅방, 정책, 메시지라는 개념을 각각 독립된 엔터티로 나누고,
서로의 관계를 외래 키나 참조로 연결했기 때문입니다.
이 접근방법이 잘못된 것은 전혀 아니지만, 실제 비즈니스에서 발생할 수 있는 문제점을 살펴보고,
다른 관점을 소개해드리고자 합니다.
다음과 같은 상황을 가정해보겠습니다.
ChatRoom.companyId = A
ChatRoom.policyId = P
RetentionPolicy(P).companyId = B
관계형 데이터베이스의 시각에서는 충분히 입력 가능한 값입니다. 하지만 이 상황을 풀어보면 아래와 같습니다.
A회사 소속 채팅방이 B회사 정책을 사용하고 있다.
즉, 참조 하나하나는 문제되지 않지만 참조의 연계는 출처를 분산시켜 모순을 만드는 것입니다.
이 문제를 “직교 문제” 라고 표현합니다.
유저의 경우는 어떨까요?
ChatRoom.companyId = A
ChatRoom.users = [U]
User(U).companyId = B
역시 동일한 문제는 발생할 수 있습니다.
채팅방의 CompanyId는 A지만, A회사의 소속이 아닌 유저가 들어올 수 있는 것입니다.
직교 문제 직접 하나 찾아보기! (10개 이상 있음)
이러한 직교 문제들은 RDB의 정규화로는 풀 수 없으며, case-by-case로 어플리케이션 로직을 통해 규정해야 합니다.
5개의 테이블로 이루어진 비교적 단순한 케이스에서도 이런 문제가 수없이 발생하고 조금만 확장하더라도 많은 복잡도가 발생합니다.
부서로 또 나뉘어진다면? 메시지 쓰레드를 만들어야 한다면?
또한 엔티티 기반의 모델링은 큰 범위의 트랜잭션을 발생시킵니다.
예를 들면 채팅방 하나를 만들기 위해서는 정책의 존재 여부를 확인해야 하기 때문에 정책의 SELECT문과 채팅방 INSERT문이 트랜잭션으로 묶이게 됩니다.
결론적으로 엔티티 참조 모델링은 사고에는 유리하지만, 관리와 구현에는 많은 어려움이 존재합니다.
값객체
엔티티와 값객체의 차이란?
엔티티가 아닌 값객체를 통해 접근해보겠습니다.

위 그림을 살펴보면 연관관계를 전혀 찾을 수 없습니다.
대신 모든 참조는 사본(스냅샷)이 대체하고 있습니다.
이런 불안이 있을 수 있습니다
만약 채팅방이 생성된 이후에 회사가 이름을 바꾸면 어떡하지?
예를 들어 SK C&C가 채팅방이 생성된 이후에 SK AX로 이름을 바꾼 상황입니다.
하지만 이런 불안과 현실은 다릅니다.
애초에 채팅방에 표시될 회사의 이름이 꼭 최신으로 유지되어야 하는것에 대한 의문을 제기하는 것입니다.
이것이 바로 도메인적 사고의 핵심입니다 - 데이터가 얼마나 실시간적으로 정확해야 하는가?
도메인 판정
참조가 아닌 사본과 값객체로 관계를 정의하기 위해선 도메인 판정이 필요합니다.
채팅방의 생성시점에서 정합성만 확보되더라도 문제가 없는지에 대한 고찰입니다.
의외로 현실세계는 이 값객체를 사용하더라도 무방한 경우가 많습니다.
디스코드의 경우, 사용자가 아이디를 바꿨을 때 즉시 업데이트 되지 않고 유저 프로필 상세보기 했을 때 업데이트 됨
연결참조의 무결성을 의식하여 cascade delete (또는 soft cascade delete) 를 했을 때 모든 정보가 삭제되는것보다,
단순 스냅샷을 통해 관리하는것이 추후 audit 관점에서 유리한 상황 또한 존재할 수 있습니다.
즉 결과적 일관성 (Eventual Consistency)로 충분할 수 있다는 것입니다.
User 도메인을 살펴본다면?
장점
값객체를 통한 관계는 몇가지 장점이 존재합니다.
확장성
관계 대상을 특정 테이블의 외래 키로 고정하지 않기 때문에, 새로운 유형을 추가하기 쉽습니다.
예를 들어 채팅방 멤버를 반드시 User.id 로만 관리한다고 해보겠습니다.
- 지금은 사내 직원만 참여 가능
- 그런데 나중에 외부 협력사 사람도 초대해야 함
- 또 이후에는 이메일 게스트나 봇도 참여해야 함
이 경우 외래 키 중심 모델에서는 고민이 많아집니다.
- 외부인을 User 테이블에 넣을까?
- GuestUser 테이블을 새로 만들까?
- 봇도 User 로 취급할까?
즉, 새로운 요구사항이 생길 때마다 기존 관계 모델을 다시 흔들게 됩니다.
반면 값을 통해 멤버를 표현하면 다음처럼 다룰 수 있습니다.
- user:1001 → 사내 직원
- partner:acme-77 → 협력사 사용자
- guest:alice@gmail.com → 이메일 게스트
- bot:summary-assistant → 시스템 봇
이렇게 Prefix 하면 암묵적인 규칙이라 더 복잡해지는거 아님?
즉, 채팅방 입장에서는 전부 그냥 “참여자”입니다. 누구인지 구분만 되면 같은 구조 안에서 함께 담을 수 있습니다.
마무리
값객체 방식 참조방식보다 항상 우월한 설계는 아닙니다.
기존 참조 관계 방식에 비해 중복이나 실시간성 등 잃는 부분도 존재합니다.
하지만 엔티티 간 참조가 많아질수록 발생하는 결합도나 직교 문제를 해결하는 대안이 될 수 있고,
모델링을 바라보는 다른 관점을 소개하는 의미에서 작성 해 보았습니다.
생각해볼 거리
- 스냅샷은 결국 JSON을 들고다니는 형태이다. 집계는 그러면 어떻게 하는걸까?
- 직렬화나 역직렬화 비용은 감당 가능할까?
댓글남기기