if(kakao) 2022 컨퍼런스 내용을 듣고 정리한 내용이다. DDD에 대한 간단한 개념 정리를 먼저 읽고 아래 내용을 참고하길 바란다.
DDD란
Domain-Driven Design으로 도메인 주도 설계라고 부른다.
특징
1. 일반적으로 많이 사용하는 데이터 중심의 접근법을 탈피해서 순수한 도메인 모델과 로직에 집중하는 것을 말한다.
2. 보편적인 언어의 사용이다. 도메인 전문가와 소프트웨어 개발자간의 커뮤니케이션 문제를 없애고 상호가 이해할 수 있고 모든 문서와 코드에 이르기까지 동일한 표현과 단어로 구성된 단일화된 언어체계를 구축해나가는 과정을 말한다. 이로서 분석 작업과 설계 그리고 구현에 이르기까지 통일된 방식으로 커뮤니케이션이 가능해진다.
3. 소프트웨어 엔티티와 도메인 컨셉을 가능한 가장 가까이 일치시키는 것이다. 도메인 모델부터 코드까지 항상 함께 움직이는 구조의 모델을 설계하는 것이 핵심 원리이다.
Monolithic Legacy Server의 문제
카카오는 기존에 레거시 서버를 운영하고 있었으며, 다음과 같은 문제점을 인식했다.
1. Monolithic: 하나의 거대한 애플리케이션으로 구성되어 있어 확장성과 유지보수가 어려움.
2. 기술 부채: 오래된 기술이 누적되면서 변경이 어려워지고, 새로운 기술 도입이 제한됨.
3. 유지보수의 어려움: 코드가 복잡하게 얽혀 있어 수정 및 기능 추가 시 리스크가 큼.
4. 기능의 고착화: 시스템이 유연하지 않아 새로운 비즈니스 요구사항 반영이 어려움.
도메인 주도 설계를 하게 된 이유
카카오는 기존의 레거시 시스템을 개선하기 위해 도메인 주도 설계(Domain-Driven Design, DDD)를 도입했다. DDD는 비즈니스 로직과 도메인 모델을 중심으로 설계하는 방식으로, 다음과 같은 특징이 있다.
1. 도메인의 모델과 로직에 집중: 소프트웨어의 핵심 가치를 비즈니스 로직에서 찾음.
2. Ubiquitous Language(보편적 언어) 사용: 개발자와 도메인 전문가가 같은 용어를 사용하여 의사소통을 원활하게 함.
3. Software Entity와 Domain 간 개념 일치: 분석 모델, 설계, 코드가 일관되도록 유지.
Ubiquitous Language
개발팀과 비즈니스 전문가 간의 의사소통을 원활하게 하기 위해 도메인과 관련된 용어를 통일하는 개념
TDD, BDD도 있지만 왜 DDD를?
3. TDD, BDD도 있지만 DDD를 선택한 이유
TDD(Test-Driven Development): 테스트 자동화를 기반으로 반복적인 설계 수정을 진행.
BDD(Behavior-Driven Development): 비즈니스 협업 중심의 테스트 자동화.
✅ DDD(Domain-Driven Design)
• 이미 검증된 비즈니스 로직과 시스템 구조를 기반으로 점진적으로 개선.
• 레거시 시스템과 신규 프로젝트를 함께 운영하며 리소스를 유연하게 활용할 수 있음.

선행 작업
1.Bounded Context(경계 구분)
• 같은 용어라도 하위 도메인마다 의미가 다를 수 있음.
• 하나의 모델로 하위 도메인을 표현하는 것은 올바르지 않으며, 각 하위 도메인별로 별도의 모델을 만들어야 함.
• 특정 문맥에서 의미를 갖는 경계를 Bounded Context라고 정의함.

2.Context Map(문맥 지도)
• 여러 개의 Bounded Context가 있을 때, 서로 간의 관계를 정의하는 구조.
• MSA(Microservices Architecture)에서는 각각의 컨텍스트가 독립적인 서비스로 분리됨.


3.Aggregate(집계)
• 데이터 변경의 단위로, 하나의 트랜잭션에서 함께 처리되어야 하는 객체 그룹.
• Aggregate Root(루트 엔티티)를 통해서만 내부 엔티티에 접근할 수 있도록 제한.
• 루트 엔티티가 변경되면, 관련된 모든 엔티티에도 영향을 미침.
Aggregate의 장점
• 개별 객체 간의 상호작용보다 전체적인 관계를 넓은 시야에서 관리 가능.
• 제약사항을 한 곳에서 처리하여 비즈니스 로직에 집중할 수 있음.


DDD의 대표적인 아키텍처 (Layered, Clean, Hexagonal)
1. Layered Architecture
- UI : Application이 연결되는 계층으로 Input,Output 변환등을 담당하는 계층
- Application : 도메인 객체를 직접적으로 사용하면서 어떻게 사용하면 좋을지 정의하는 유즈케이스를 실제로 구현하는 어플리케이션 계층
- Domain : 비즈니스와 관련된 직접적인 기능과 그 객체를 이루는 계층
- InfraStructure :DB, 메세지 전술등과 같은 기술적인 부분을 제공해 주는 계층

2. Clean Architecture
- External Interface : 데이터베이스나 웹 프론트엔드 프레임워크를 기반으로 한 UI
- Interface Adaptor : 데이터 베이스나 파일시스템에 저장하거나 외부에 유스케이스를 위해 양방향으로 데이터 변환을 수행하는 커뮤니케이터 역할을 하는 인터페이스 어댑터
- UseCase : 핵심 비즈니스 로직이나 애플리케이션 로직으로 구성된 유스케이스 계층
- Entity : 엔티티 또는 도메인으로 구성된 내부의 유효성 검사 혹은 모든 도메인에 적용되는 일반 논리를 가진 도메인 계층

3. Hexagonal Architecture
- 클린 아키텍처와 유사하지만 추가적인 포트와 어댑터개념이 존재
XBox, PS와 같은 구조
헥사고날 아키텍처는 xBox, PS처럼 이해하면 편하다.
중간에 위치한 헥사고날 아키텍처가 실제 게임을 플레이 할 때 받아오는 조이스틱 인터페이스에서 받아오는 인풋
사운드나 디스플레이로 나가는 아웃풋이 존재하고 스피커나 모니터, 조이스틱등은 포트에만 맞게 장착할 수 있으면 어느 회사에 것을 사용할 수 있는 것처럼 각 포트에 맞는 어댑터에서 알맞게 구현을 해주면 어떤 유틸리티든 가져다 쓸 수 있는 부분이다.
이 헥사고날 아키텍처의 핵심은 비즈니스 로직이나 표현로직에 의존하지 않도록 하는것이 가장 중요한 목표이다.

선택 과정
1. 비즈니스 로직이 거대해지면서 어플리케이션 레이어가 오염되어서 패스
2. 포트 어댑터가 표현되어있는 확실한 헥사고날 아키텍처를 선택하게 됨
예시
1. 작품 판매에 대한 요청이 Web에서 들어오면 컨트롤러를 통해 서비스포트로 인잇되고 어플리케이션 처리된다.
2. 레포지터리에서 퍼시스턴트에 대한 처리
3. 처리에 대한 항목을 요약해서 알림쪽으로 전송된다.

코드 예시
1. 작품 판매 요청(Web) → 컨트롤러 → 서비스 포트 → 애플리케이션 계층에서 처리
2. 레포지토리를 통해 데이터 저장 (퍼시스턴트 계층)
3. 처리된 결과를 알림 서비스로 전송 (이벤트 발행)
Product라는 도메인이 있다. 도메인 안에는 판매정보와 메타정보, 콘텐츠 파일정보들이 들어있다.
내부에서 작품 판매시 필요한 유효성검사와 판매 날짜에 대해 처리할 수 있는 관련 기능이 들어있고 이를 도메인로직이라고 한다.
public class Product {
.. .
private ProductSalesInfo productSalesInfo;
private ProductMetaInfo productMetaInfo;
private Content content;
...
public void startSale(LocalDateTime startSaleDt){
validateProduct();
productSalesInfo = ProductSalesInfo.startSale(startSaleDt);
}
}
판매 시작 API로 요청 시 API에서는 유스케이스에서 정의 되니 작품 판매를 수행
유스케이스에서 정의된 SlaeProduct는 Service에서 구현이 된다.
@PostMappint(path = "/product/{porductId}")
public void saleProduct(@PathVariable("productId") Long productId){
productUseCase.saleProduct(ProductSaleCommand
.bilder()
.productId(new ProductId(productId))
.build());
}
public interface ProductUseCase {
void slaeProduct(ProductSaleCommand command);
}

작품을 판매하기 위해 로드 포트에서 로드프로덕트를 수행된다.
데이터 수정이 이뤄지면 세이브 포트 수행된다.
마지막으로 정리된 내용을 요약해서 알림 서비스 제공을 위한 이벤트 퍼블리쉬가 이뤄지며
로드와 세이브는 모두 별도의 비즈니스인데 CRUD 중 조회를 제외한 나머지는 세이브포트로 가고있고 이는 CQRS 패턴으로 커맨드와 쿼리를 분리하기 위함이다.
이후 EventPublishPoort는 Amazone SQS, RabbitMQ로 조회를 이벤트드리븐 형식으로 변경될 수 있다.
public class SaleService implements ProductUseCase{
private final LoadProductPort loadProductPort;
private final SaveProductPort saveProductPort;
private final EventPublishPort eventPublishPort;
@Override
public void saleProduct(ProductSaleCommand cmd){
Product product=
loadProductPort.loadProduct(cmd.getProductId());
product.startSale(LocalDateTime.now());
saveProductPort.saveProduct(product);
eventPublishPort.publisherEvent(product);
}
}
로드 프로덕트와 세이브프로덕트가 퍼시스턴스어댑터에서 수행이 된다. 로드 프로덕트를 통해 JPA엔티티로 또는 JPA엔티티를 프로덕트 도메인으로 변경이 필요하다.
하나의 어그리게이트는 여러 개의 테이블, 데이터와 연관이 있을 수 있기 때문에 각각의 데이터를 하나의 도메인 집합으로 만들어줄 때 변환하는 로직이 필요하다.
class ProductPersistenceAdapter implements LoadProductPort, SaveProductPort{
...
@Override
public Product loadProduct(PorductId productId){
ProductJpaEntity productJpaEntity = productRepository.findById(productId.getValue())...;
ContentJpaEntity contentJpaEntity = contentRepository.findByProductId(productId.getValue())...;
return mapper.mapToDomainEntity(...);
}
@Override
public void saveProduct(Product product){
productRepository.save(
mapper.mapToJpaEntity(product));
}
}
과연 모든 문제가 해결이 되었을까?
DDD 적용 후 해결되지 않은 문제점
1. MSA의 단점:
• 트랜잭션 관리 및 통합 테스트, 배포 복잡성 증가.
2. 아키텍처 구현 과정에서 발생하는 코드 증가:
• 매퍼 등 추가적인 코드가 필요하여 개발 부담이 증가.
3. 도메인에 대한 높은 이해도 필요:
• DDD를 올바르게 사용하기 위해서는 개발자가 도메인 지식을 충분히 학습해야 함.
DDD 도입 후 장점
설계적인 장점
1. 보편적인 언어 사용으로 빠른 커뮤니케이션 가능.
2. 복잡한 도메인 관계를 Aggregate로 정리 가능.
3. 도메인 분리를 통한 유지보수 및 유연성 증가.
개발적인 장점
4. 캡슐화를 통한 데이터 보호 (루트 엔티티를 통해서만 접근 가능).
5. 의존성 감소로 코드 응집력 향상 (유스케이스 및 포트 활용).
이렇게 알아본 내용으로 DDD를 생각해 봤을 때 내가 맡은 도메인에 대한 높은 이해도와 엄격하게 제한된 각 도메인에 대한 접근, 요청에 대한 데이터 정제 시 사용하는 각 포트를 통한 요청과 생성등이 매우 중요하다고 느껴졌다.
DDD를 통해 도메인 중심으로 시스템을 재설계하면서 유지보수성과 확장성을 개선할 수 있었지만, MSA 및 아키텍처 구현의 복잡성이 증가하는 점도 고려해야 한다. 이를 통해 처음에는 Layered 아키텍처로 구현해 보고 다음에는 헥사고날 아키텍처로 구현하는 방식을 구현해 보며 각각의 장단점과 어떤 상황에 어떤 설계가 더 적합한지에 대해서 경험해보고자 한다.