Java
Spring Boot 프로젝트의 패키지 구조 전략: Layer-First vs Domain-First
0woong.developer
2025. 6. 25. 10:53
Package 구조 전략
Spring Boot 프로젝트를 시작할 때 가장 고민되는 부분 중 하나가 바로 패키지 구조입니다. 처음에는 단순한 계층형 구조로 시작했다가, 프로젝트가 커지면서 유지보수가 어려워지는 경험을 한 번쯤은 해보셨을 것 같습니다.
오늘은 다양한 패키지 구조 전략과 각각의 특징을 알아보겠습니다.
Package by Layer
전통적인 계층형 구조로, Spring MVC의 기본적인 구조를 따릅니다.
src/main/java/com/example/
├── controller/
├── service/
├── repository/
└── model/
| 장점 | 단점 |
|---|---|
| 구조가 단순하고 직관적 | 기능 수정시 여러 패키지 변경 필요 |
| 계층별 역할이 명확 | 도메인 경계가 불명확 |
| 진입 장벽이 낮음 | 순환 참조 발생 가능성 |
| 새로운 개발자의 빠른 적응 | 패키지가 비대해질 수 있음 |
Package by Feature
기능 또는 도메인 단위로 패키지를 구성하는 방식입니다. 하나의 기능과 관련된 모든 클래스가 하나의 패키지에 모여있습니다.
src/main/java/com/example/
├── user/
│ ├── UserController
│ ├── UserService
│ └── UserRepository
├── order/
│ ├── OrderController
│ ├── OrderService
│ └── OrderRepository
| 장점 | 단점 |
|---|---|
| 높은 응집도 | 계층 구분이 모호 |
| 기능 단위 캡슐화 | 패키지 크기가 커질 수 있음 |
| 명확한 의존성 | 공통 컴포넌트 관리 어려움 |
| 기능 단위 테스트 용이 | 패키지 간 중복 코드 발생 가능 |
Vertical Slice Architecture
기능을 더 작은 단위로 수직 분할하는 구조입니다. 각 기능이 완전히 독립적으로 동작할 수 있도록 설계됩니다.
src/main/java/com/example/
├── users/
│ ├── registration/
│ │ ├── controller/
│ │ ├── service/
│ │ └── dto/
│ └── profile/
│ ├── controller/
│ ├── service/
│ └── dto/
| 장점 | 단점 |
|---|---|
| 기능별 독립성 | 코드 중복 가능성 |
| 변경 영향도 파악 용이 | 복잡한 구조 |
| MSA 전환 용이 | 학습 곡선이 높음 |
| 기능별 독립 배포 가능 | 오버엔지니어링 위험 |
DDD 기반 구조
도메인 주도 설계(Domain-Driven Design) 원칙을 따르는 구조입니다. 비즈니스 도메인을 중심으로 설계됩니다.
src/main/java/com/example/
├── domain/
│ ├── user/
│ │ ├── entity/
│ │ ├── repository/
│ │ └── service/
│ └── order/
│ ├── entity/
│ ├── repository/
│ └── service/
├── application/
│ ├── dto/
│ └── facade/
└── infrastructure/
├── config/
└── external/
| 장점 | 단점 |
|---|---|
| 비즈니스 로직 표현력 | 초기 설계 난이도 높음 |
| 도메인 중심 설계 | 작은 프로젝트엔 과도 |
| 복잡한 비즈니스 처리에 적합 | 도메인 전문가 필요 |
| 확장성이 좋음 | 러닝커브가 높음 |
추천 구조
위 구조들의 장점을 결합한 하이브리드 방식입니다. 도메인 중심이되, 공통 모듈과 외부 연동을 분리합니다.
src/main/java/com/example/
├── common/
│ ├── annotation/
│ ├── aspect/
│ ├── config/
│ └── exception/
│
├── domain/
│ ├── user/
│ │ ├── controller/
│ │ ├── service/
│ │ ├── repository/
│ │ └── dto/
│ └── order/
│ ├── controller/
│ ├── service/
│ ├── repository/
│ └── dto/
│
└── external/
├── payment/
│ ├── controller/
│ ├── service/
│ └── client/
└── notification/
├── controller/
├── service/
└── client/
| 특징 | 설명 |
|---|---|
| 도메인 기반 패키지 분리 | 비즈니스 로직의 응집도를 높이고 의존성을 명확히 함 |
| 공통 모듈 재사용 | 횡단 관심사를 효과적으로 관리 |
| 도메인 독립성 | 각 도메인이 독립적으로 발전 가능 |
| 일관된 구조 | 팀 구성원 간 코드 이해도 향상 |
| MSA 전환 고려 | 필요시 서비스 분리가 용이 |
결론
패키지 구조는 프로젝트의 성격과 팀의 상황에 맞게 선택해야 합니다. 작은 프로젝트는 단순한 계층형 구조로 시작하고, 프로젝트가 커지면서 도메인 중심 구조로 전환하는 것이 일반적입니다.
중요한 것은 선택한 구조가:
- 팀원들이 이해하기 쉽고
- 비즈니스 요구사항을 잘 표현할 수 있으며
- 향후 확장성을 고려했는지 입니다
처음부터 완벽한 구조를 만들려고 하기보다는, 프로젝트의 성장에 따라 점진적으로 개선해 나가는 것을 추천드립니다.