카카오페이 여신코어 DDD로 구축하기
카테고리
프로그래밍/소프트웨어 개발
서브카테고리
개발 툴, 아키텍처 패턴
대상자
복잡한 도메인 모델을 설계하는 소프트웨어 개발자, 시스템 아키텍트
핵심 요약
- DDD(Domain Driven Design)를 통해 도메인 복잡성을 체계적으로 관리하고 유지보수성을 높였음
- Bounded Context와 Aggregate Root를 중심으로 도메인 모델을 분리하여 기능 중복 방지
- 도메인 모델 내부에서 비즈니스 규칙을 강제하고, Application Layer는 단순한 조합 역할 수행
섹션별 세부 요약
1. DDD 개념 정의
- 도메인(Domain): 문제 해결 영역 (예: 대출, 심사, 승인 등)
- 유비쿼터스 언어: 도메인 전문가와 개발자 간 의사소통 도구
- 바운디드 컨텍스트: 도메인 경계를 명확히 정의하여 모듈 간 의존성 제어
2. 프로젝트 배경 및 설계 선택 이유
- 2021년 금융규제 샌드박스로 인해 여신시스템 내재화 필요성 증가
- DDD 선택 이유: 도메인 복잡성 관리 및 비즈니스 규칙 일관성 유지
- 팀 협업 강화: 도메인 모델, 바운디드 컨텍스트, 에그리거트 정의를 통해 유비쿼터스 언어 공유
3. 도메인 설계 원칙
- 도메인 모델 분할: 최소한의 단위로 분할하여 기능 재사용성 향상
- Aggregate Root 중심 설계: 예: Recovery(납부) 도메인에서 하위 객체 생성 및 관리
- 도메인 내부에서만 데이터 조작: JPA Entity와 분리하여 데이터베이스 의존성 제거
4. 코드 구조 및 예제
- Gradle 모듈 분리: 각 바운디드 컨텍스트는 subproject 단위로 관리 (ex:
gaia-user-domain
,gaia-account-domain
) - Application Layer 구조:
```kotlin
@Service
class RegisterService(
private val userDomainRepository: UserDomainRepository,
private val accountDomainRepository: AccountDomainRepository
) {
@Transactional
fun register(...) {
// 도메인 객체 생성 및 저장
val account = createAccount(...)
accountDomainRepository.save(account)
}
}
```
- Domain Entity 설계:
```kotlin
class Accountinternalconstructor(...) {
companion object {
fun create(command: CreateCommand): Account = Account(...)
}
}
```
- 생성자에 private 접근 제어자 추가하여 factory method로만 생성
5. Application Layer와 Domain Layer의 상호작용
- Application Layer:
- DomainEntity를 통해 명령 전달
- JPA Entity와 직접 연관 X, DomainRepository를 통해 변환
- DomainRepository 예시:
```kotlin
class AccountDomainRepositoryImpl(
private val accountJpaRepository: AccountDomainJpaRepository
) {
@Transactional
override fun save(domainEntity: Account): Result
return runCatching {
accountJpaRepository.findByIdOrNull(domainEntity.externalId)
?.apply(domainEntity)
?: AccountEntity.from(domainEntity)
.let(accountJpaRepository::save)
.toDomainEntity(withWriteOff = true)
}
}
}
```
결론
- DDD를 통해 도메인 복잡성을 체계적으로 관리하고, 유지보수성과 팀 협업 효율성 향상 가능
- PlantUML을 활용한 Business Flow 시각화와 단위테스트 기반 안정성 확보가 핵심
- 도메인 모델 내부에서 비즈니스 규칙 강제, Application Layer는 단순한 조합 역할 수행하여 기술적 분리성 확보