핵심적인 카테고리
Enums
비즈니스 로직과 관련된 상수값들을 정의.
예: 도메인 내 상태 값, 코드 값 등.
Domain
핵심 비즈니스 로직 및 규칙을 포함.
Entity
,Value Object
,Aggregate
,Domain Service
등이 포함될 수 있음.
DTO
외부와 데이터를 교환하기 위한 객체.
요청 및 응답용
RequestDTO
,ResponseDTO
등을 포함.
Service
응용 계층(Application Layer)의 비즈니스 로직을 처리.
Facade
,Application Service
,Domain Service
를 분리하여 명확히 관리 가능.
Repository
도메인 객체의 영속성을 관리.
JpaRepository
또는 커스텀 Repository 인터페이스와 구현체.
Controller
사용자 요청을 받아서 응답하는 입출력 계층.
REST API 혹은 웹 소켓 컨트롤러를 포함.
Configuration
애플리케이션 전반의 설정과 구성.
Bean 등록, 외부 라이브러리 설정.
Utils/Helper
공통적으로 사용되는 유틸리티 함수와 헬퍼 클래스.
비즈니스 로직과 직접적인 관련이 없는 범용 도구들.
추가적으로 고려할 수 있는 카테고리
Adapter
외부 시스템과의 통합을 담당.
예: API 통신, 메시징 시스템(Kafka, RabbitMQ 등)과의 연계.
헥사고날 아키텍처에서는 Port와의 인터페이스를 구현.
Port
애플리케이션이 외부와 통신하는 인터페이스.
Inbound Port
: 사용자의 요청을 받아들임 (예: Service 인터페이스).Outbound Port
: 외부 시스템에 요청을 보냄 (예: Repository 인터페이스).
Exception
커스텀 예외를 정의하여 예외 처리를 중앙 집중화.
예: 비즈니스 예외, 어플리케이션 예외.
Mapper
도메인 객체와 DTO 간 변환 로직을 포함.
MapStruct와 같은 라이브러리를 활용하거나 수동으로 매핑 로직 작성.
Event
도메인 이벤트를 처리하거나 발행.
이벤트 퍼블리싱 또는 핸들링과 관련된 클래스.
Validation
입력 데이터의 검증 로직.
Validator 클래스 또는 애노테이션 기반의 검증.
Scheduler/Batch
정기적으로 실행되는 작업 처리.
스케줄링 또는 배치 작업 관련 클래스.
Interceptor/Filter
요청/응답 처리 파이프라인에 추가되는 처리 로직.
예: 인증, 로깅, 권한 확인.
Integration
외부 서비스와의 연동 테스트 및 모의 구현(Mock).
API, 데이터베이스, 메시지 브로커와의 통합 코드.
Test
단위 테스트(Unit Test), 통합 테스트(Integration Test), E2E 테스트.
테스트 전용 설정 및 Mock 구현.
예시 구조
src ├── adapter ├── application (service, use case) ├── configuration ├── controller ├── domain │ ├── enums │ ├── entity │ ├── valueobject │ └── service ├── dto ├── event ├── exception ├── mapper ├── port │ ├── inbound │ └── outbound ├── repository ├── scheduler ├── utils └── test
특히 중요한 점
헥사고날 아키텍처에서는
Adapter
와Port
의 역할을 명확히 구분하고, 도메인 계층과 의존성을 최소화해야 합니다.공통 기능(
Utils
,Helper
)은 특정 도메인이나 계층에 의존하지 않도록 설계해야 합니다.필요하다면 각 계층을 더 세분화하거나 프로젝트 특성에 맞게 조정할 수 있습니다.
JPA 기반 추가 고려사항
Entity
JPA에서 사용하는 도메인 엔티티 클래스.
애너테이션(@Entity, @Table 등)을 사용하여 데이터베이스와 매핑.
일반적으로
Domain
계층에 포함되지만, 명확한 분리를 원하면 별도로 관리.
Repository
JPA Repository 인터페이스.
Spring Data JPA의 기본 Repository 인터페이스를 확장하거나, 커스텀 메서드 정의.
Specification/Criteria
복잡한 쿼리를 생성하기 위한 JPA의
Criteria API
또는Specification
클래스.데이터 검색 로직을 깔끔하게 분리.
Entity Listener
JPA 엔티티와 관련된 이벤트(@PrePersist, @PostLoad 등)를 처리하는 리스너 클래스.
Mapping Layer
도메인 객체(Entity)와 DTO 간 변환.
MapStruct와 같은 라이브러리 또는 수동 매핑 구현.
명확한 책임 분리를 위해 도메인 계층 외부에 위치.
구조 예시
src ├── adapter │ ├── persistence │ │ ├── repository (JpaRepository 확장) │ │ ├── entity (JPA Entity 클래스) │ │ └── criteria (Specification, Criteria API 관련) │ ├── api │ └── messaging ├── application │ ├── service (Application 서비스) │ └── usecase (유스케이스별 클래스) ├── domain │ ├── entity (도메인 엔티티 - JPA 의존성 제거 가능) │ ├── valueobject │ └── service (도메인 서비스) ├── dto ├── port │ ├── inbound │ └── outbound (Repository 인터페이스 포함) ├── configuration ├── event ├── exception ├── mapper ├── utils └── test
주요 포인트
JPA Entity 분리:
JPA Entity는Domain
에 포함될 수 있지만, 데이터베이스 중심 설계와 도메인 중심 설계를 분리하려면Adapter
의Persistence
디렉터리에 위치시킬 수 있습니다.Repository와 Port 연결:
JPA Repository는Outbound Port
의 구현체로 위치하며, 도메인 서비스에서 Repository 인터페이스만 의존하도록 설계합니다.Entity Listener 및 이벤트:
JPA의@EntityListeners
를 활용하여 영속성 관련 이벤트를 처리할 수 있습니다.Specification 사용:
복잡한 쿼리를 작성해야 하는 경우, JPA의Specification
또는Criteria API
를 별도의 클래스로 구성해 Repository 로직을 깔끔하게 유지합니다.
Feature 기반 분리 시 주요 원칙
Feature 단위로 독립성 유지
각 Feature는 자신의 도메인 모델, 애플리케이션 로직, 데이터 저장소를 독립적으로 관리.
다른 Feature와의 통신은 API나 메시지 큐를 통해 수행.
공통 기능 최소화
각 Feature에서 중복을 줄이기 위해 공통 모듈(
common
또는shared
)을 생성할 수 있지만, 남용하지 않도록 주의.예: 공통 유틸리티, 인증/인가 모듈.
도메인 중심 설계
각 Feature는 자신의 도메인과 유스케이스에 맞는 설계를 유지.
다른 Feature에 의존하지 않도록 설계.
Feature 기반 구조 예시
src ├── feature-a │ ├── adapter │ │ ├── api │ │ ├── persistence │ │ └── messaging │ ├── application │ │ ├── service │ │ └── usecase │ ├── domain │ │ ├── entity │ │ ├── valueobject │ │ └── service │ ├── dto │ ├── port │ │ ├── inbound │ │ └── outbound │ ├── configuration │ ├── event │ ├── exception │ ├── mapper │ ├── utils │ └── test ├── feature-b │ ├── adapter │ ├── application │ ├── domain │ ├── dto │ ├── port │ ├── configuration │ └── test ├── common (공통 모듈) │ ├── security │ ├── messaging │ ├── exception │ ├── utils │ └── test └── shared (공유 리소스) ├── api-clients ├── shared-entity ├── shared-dto └── event
구체적인 분리 전략
Feature 간 통신
동기 통신: REST API 또는 gRPC를 사용.
비동기 통신: Kafka, RabbitMQ와 같은 메시지 브로커를 사용.
Feature 내부 구조
각 Feature는 완전한 헥사고날 아키텍처를 유지.
adapter
,application
,domain
,port
로 구성하여 독립성을 보장.
공통 코드 관리
공통 코드는
common
디렉터리에서 관리.각 Feature가 필요에 따라 가져다 사용.
테스트 분리
단위 테스트는 Feature 내에서 진행.
통합 테스트는 Feature 간의 상호작용을 확인.
데이터베이스 분리
가능한 경우 각 Feature가 별도의 데이터베이스를 관리(MSA의 원칙).
동일한 데이터베이스를 사용해야 한다면, 데이터 접근은
Repository
를 통해 제한.
MSA 최적화를 위한 추가 팁
API Gateway
외부 요청은 API Gateway를 통해 라우팅.
각 Feature는 내부적으로 독립적으로 동작.
Feature별 배포
각 Feature는 독립적으로 빌드 및 배포 가능하도록 설계.
Docker, Kubernetes를 활용.
모니터링과 로깅
각 Feature의 상태를 중앙에서 모니터링.
로그는 통합된 시스템(예: ELK 스택)에서 관리.