Search
🌍

a0_4.1_1.2_1.1_2. title: Application 레이어는 도메인 모델 중심(DDD) 또는 사용자의 행위 중심(Clean Architecture)으로 도메인 계층을 오케스트레이션한다. 다중 Entity/Aggregate간 협력 위치도 Application 레이어이다. 단순 CRUD인지 복잡한 조율이 필요한지에 따라 파일 이름과 클래스에서 도메인 모델의 힘을 얼마나 담을 것인지 결정한다(Service UseCase).

생성
prev summary
next summary
🚀 next note
♻️ next note
관련 임시노트
9 more properties
애플리케이션 레이어는 도메인 모델을 사용하여 실제 사용자의 목표를 달성시켜주는 역할을 합니다. 즉, 여러 Aggregate와 도메인 서비스를 조율(Orchestration)하여 하나의 완전한 비즈니스 프로세스를 완료하는 계층입니다. 소프트웨어 아키텍처에서 애플리케이션 계층을 구성하는 두 가지 대표적인 패턴이 있습니다. 바로 도메인 주도 설계(DDD)의 애플리케이션 서비스(Application Service)와 클린 아키텍처(Clean Architecture)의 유스케이스(Use Case)입니다. 둘은 비슷한 역할을 수행하지만, 그들을 바라보는 철학과 구조에 약간의 뉘앙스 차이가 존재합니다.
가장 근본적인 차이는 클래스를 구성하는 '중심 관점'에 있습니다. 애플리케이션 서비스(DDD)에서는 도메인 개념을 중심으로 관련 기능들을 묶습니다. 가령 Order 애그리거트와 관련된 기능들은 OrderService에, Member와 관련된 기능들은 MemberService에 모이는 식입니다. 이는 도메인 모델의 구조를 애플리케이션 계층에 반영하는 '모델 중심' 접근법입니다. 유스케이스(Clean Architecture)에서는 사용자의 행동(User Action) 또는 시스템의 단일 응답을 중심으로 클래스를 구성합니다. '주문 생성'이라는 행동은 CreateOrderUseCase 클래스로, '주문 취소'는 CancelOrderUseCase 클래스로 분리됩니다. 이는 사용자의 시나리오를 코드로 표현하는 '행위 중심' 접근법입니다. 이러한 관점의 차이는 클래스의 구조로 이어집니다.
애플리케이션 서비스에서는 하나의 서비스 클래스가 여러 개의 공개 메서드(Public Methods)를 가집니다. 각 메서드가 하나의 유스케이스에 해당합니다.
# 하나의 클래스, 여러 개의 책임 class OrderService: def create_order(...): ... def cancel_order(...): ... def change_shipping_info(...): ...
Python
복사
반면 하나의 유스케이스 클래스는 단 하나의 공개 메서드(보통 execute 또는 handle)만을 가집니다. 클래스 자체가 하나의 유스케이스와 1:1로 매칭됩니다.
# 각 클래스가 단 하나의 책임 class CreateOrderUseCase: def execute(...): ... class CancelOrderUseCase: def execute(...): ...
Python
복사
Application Service 클래스를 작성하는 경우와 달리, 사용자의 행위마다 메서드가 아니라 클래스가 새로 생겨나게 되므로 클래스 수가 늘어나고 보일러플레이트가 생겨나게 됩니다. 아주 간단한 CRUD(Create, Read, Update, Delete) 기능만 필요한 도메인에서도 CreateUserUseCase, UpdateUserUseCase, DeleteUserUseCase, GetUserUseCase처럼 클래스를 일일이 만드는 것은 오버엔지니어링입니다. 차라리 Application Service 클래스를 이용해서 '기능적 응집도' 측면에서는 하나의 도메인과 관련된 책임들을 모으는 편이 나을 수 있죠. 그래서 상대적으로 유즈케이스가 다양해서 하나의 비대한 Application Service 클래스를 작성하는 경우보다 쪼갰을 때 얻는 아래와 같은 장점이 클 때 채택하는 것을 추천합니다.
일단 이렇게 코드를 작성했을 때 얻을 수 있는 가장 큰 장점은 직관적인 이름입니다. CreateOrderUseCase는 '주문 생성 유스케이스'라는 의미를 명확하게 전달합니다. 복잡하고 여러 도메인의 협력이 필요한 핵심 비즈니스 로직일지라도 코드를 읽는 누구나 이 클래스가 어떤 역할을 하는지 즉시 이해할 수 있습니다. 직관적인 이름은 명확한 책임 범위를 의미하기도 합니다. 유즈케이스 클래스 하나는 '주문 생성'같은 단 하나의 책임만 가집니다. 이는 코드의 응집도를 높이고, 관련 없는 기능이 하나의 클래스에 섞이는 것을 방지하여 단일 책임 원칙을 자연스럽게 지키도록 유도합니다.
의미적으로는 클래스나 파일 이름에서 도메인 모델의 힘을 빼게 되면서, 어떤 행위를 하기 위해 여러 도메인 모델의 협력이 필요할 수 있음을 이름만으로도 유추할 수 있다는 장점이 있습니다. 가령 '주문 생성'이라는 비즈니스 프로세스는 단순히 Order Aggregate 하나만으로 끝나지 않습니다. 고객의 주문 가능 상태를 확인(Customer Aggregate)하고, 상품의 재고를 파악(Product Aggregate)하는 등의 작업이 필요할 것이라는 생각이 들게 됩니다. 반면 OrderService와 같이 클래스를 작성하게 이름이 Order이라는 Aggregate 이름에 강하게 종속되어 여러 Aggregate을 조합한다는 느낌이 잘 살지 않습니다.
의외로 마지막 장점을 상당히 크게 느낀 적이 있습니다. 도메인 클래스가 점점 많아지면 이에 맞게 애플리케이션 레이어가 항상 따라오게 되는데, 항상 SomeAggregateNameService와 같은 형식으로 클래스와 파일들이 생겨났습니다. 이렇게 파일과 클래스가 늘어나면 자연스레 도메인 계층과 애플리케이션 계층이 1:1 대응되는 느낌이 들게 됩니다. 사람이 애플리케이션 레이어의 수많은 파일들을 뒤질 때, 도메인 모델의 이름과 동일한 파일이 있으면 그것을 가장 먼저 보게 되니까요. 별 것 아닌 것 같지만 군사번역 프로젝트와 튜닝 프로젝트 등의 프로덕트를 구축할 때 명확하지 않은 애플리케이션 레이어의 역할, 비대해지는 SomeAggregateNameService 클래스, 다중 Aggregate들의 협력이 필요한 로직 배치와 명명 등이 쓸데없이 개발 속도를 늦추곤 했습니다. 가장 사용자와 가까운 계층에서부터 사고 흐름이 흘러가야 할 때에도, 도메인 모델부터 사고가 흘러갔기 때문입니다. 하지만 사용자가 하려는 행위를 기준으로 애플리케이션 레이어를 작성하게 되니 자연스럽게 클래스의 이름에서 Aggregate 이름이 사라지게 되었고, 그 결과 코드를 뒤지는 데 들어가는 시간이 크게 줄어들 수 있었습니다.
애플리케이션 서비스 패턴은 비교적 단순한 CRUD나, 도메인 하나의 책임이 명확한 기능인 경우 실용적입니다. 유스케이스 패턴은 복잡하고, 여러 도메인의 협력이 필수적인 핵심 기능에 적용할 때 투자 대비 최고의 효과를 냅니다. 구조적 명확성을 통해 유지보수성과 확장성을 향상시킬 수 있습니다.
parse me : 언젠가 이 글에 쓰이면 좋을 것 같은 재료을 보관해 두는 영역입니다.
1.
None
from : 과거의 어떤 원자적 생각이 이 생각을 만들었는지 연결하고 설명합니다.
1.
앞의 글은 대형 Entity를 의미하는 Aggregate라는 존재가 무엇인지 설명한다. 애플리케이션 레이어에서 주로 다루게 되는 도메인 레이어의 Entity는 Aggregate root일 가능성이 높다.
supplementary : 어떤 새로운 생각이 이 문서에 작성된 생각을 뒷받침하는지 연결합니다.
1.
None
opposite : 어떤 새로운 생각이 이 문서에 작성된 생각과 대조되는지 연결합니다.
1.
None
to : 이 문서에 작성된 생각이 어떤 생각으로 발전되거나 이어지는지를 작성하는 영역입니다.
1.
None
ref : 생각에 참고한 자료입니다.
1.
None