목차
Package
1️⃣ Spring Boot의 기본 프로젝트 구조

src/main
-
Java 소스 코드가 위치하는 디렉토리입니다.
-
주요 패키지들이 이곳에 생성됩니다.
main/java
- @SpringBootApplication Class(main)가 있습니다.
- 하위 패키지는 자동으로 컴포넌트 스캔이 적용됩니다.
main/resources
- 애플리케이션의 리소스 파일들이 위치하는 디렉토리 입니다.
- static, templates, application.properties등이 있습니다.

src/test
-
테스트 코드를 작성하는 공간입니다.
-
TestApplication이 있습니다.
test/java
- 테스트를 위한 Java 소스 코드가 위치하는 디렉토리입니다.
- 주요 패키지들이 이곳에 생성됩니다.
test/resources
- 테스트를 위한 리소스 파일들이 위치하는 디렉토리입니다.
com.example(com/example): 보통 이 부분에는 회사 또는 개인의 도메인 이름을 역순으로 사용하여 패키지를 생성합니다. 예를 들어, com.example.www
(www.example.com)과 같은 형태입니다.
2️⃣ Spring MVC 패턴에 따른 패키지 구조
보통 패키지는 Controller, Service, Entity(Domain, Model), Repository로 분류되고, 프로젝트에 따라서 계층형 또는 도메인형으로 나뉘게 됩니다.
☝🏻 계층형
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ └── demo
│ │ ├── DemoApplication.java
│ │ ├── config
│ │ ├── controller
│ │ ├── dao
│ │ ├── domain
│ │ ├── exception
│ │ └── service
│ └── resources
│ └── application.properties
특징
계층형 구조는 각 계층을 대표하는 디렉터리를 기준으로 코드들이 구성됩니다.
장점
- 프로젝트 전반적인 이해도가 낮아도, 패키지 구조만 보고 전체적인 구조를 파악할 수 있습니다.
- 애플리케이션의 API를 보고 흐름을 파악하고 싶다면, Controller 패키지 하나만 보고 파악할 수 있습니다.
- 애플리케이션의 비즈니스 로직을 보고 싶다면, Service 패키지 하나만 보고 파악할 수 있습니다.
- 계층별 응집도가 높아집니다.
- 계층별 수정이 일어날 때, 하나의 패키지만 보면 됩니다.
단점
- 도메인별 응집도가 낮습니다. (패키지로 애플리케이션의 기능을 구분짓지 못합니다.)
- 도메인의 흐름을 파악하기 힘듭니다.
- Product 도메인의 흐름을 보고 싶을 때, 모든 계층 패키지를 봐야합니다.
- 하나의 패키지안에 여러 도메인(상품, 장바구니, 사용자)들이 섞여 있습니다.
- 도메인과 관련된 스펙 & 기능이 변경되었을 때, 변경 범위가 큽니다.
- Product에 대한 변경점이 있을 때, 여러 패키지에서 변경이 일어납니다.
- 도메인의 흐름을 파악하기 힘듭니다.
- 유스케이스(사용자의 행위) 표현이 어렵습니다
- 규모가 커지면, 유스케이스별로 클래스를 분리할 때가 있습니다. ex) 상품 등록 유스 케이스 → RegisterProductService
- 하지만, 계층형에서는 계층으로 패키지가 묶이기 떄문에 위와 같이 네이밍해서 분리하기 어렵습니다.
- 규모가 커지면 하나의 패키지 안에 여러 클래스들이 모여서 구분이 어려워집니다.
✌🏻도메인형
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ └── demo
│ │ ├── DemoApplication.java
│ │ ├── coupon
│ │ │ ├── controller
│ │ │ ├── domain
│ │ │ ├── exception
│ │ │ ├── repository
│ │ │ └── service
│ │ ├── member
│ │ │ ├── controller
│ │ │ ├── domain
│ │ │ ├── exception
│ │ │ ├── repository
│ │ │ └── service
│ │ └── order
│ │ ├── controller
│ │ ├── domain
│ │ ├── exception
│ │ ├── repository
│ │ └── service
│ └── resources
│ └── application.properties
특징
도메인 디렉터리 기준으로 코드를 구성합니다.
장점
- 도메인별 응집도가 높아집니다.
- 도메인의 흐름을 파악하기 쉽습니다.
- Product 도메인의 흐름을 보고 싶을 때, Product 패키지 하나만 보면 됩니다.
- 도메인과 관련된 스펙 & 기능이 변경되었을 때, 변경 범위가 작습니다.
- Product에 대한 변경점이 있을 때, Product 패키지만 변경이 일어납니다.
- 도메인의 흐름을 파악하기 쉽습니다.
- 유스케이스별로 세분화해서 표현이 가능하다
- ex) 상품 등록 유스 케이스 → RegisterProductService
- ex) 상품 검색 유스 케이스 → SearchProductService
- 도메인별로 패키지가 나뉘기 떄문에 Product 패키지에서 위와 같은 네이밍으로 분리할 수 있습니다.
- DDD 개념에 직접적으로 대응시킬 수 있습니다.
단점
- 애플리케이션의 전반적인 흐름을 한눈에 파악하기가 어렵습니다.
- 흐름을 파악하기 위해 여러 패키지를 왔다갔다 해야할 가능성이 높습니다.
- 개발자의 관점에 따라 어느 패키지에 둘지 애매한 클래스들이 존재합니다.
- Welcome 페이지를 맵핑하는 컨트롤러일 때, 어느 도메인 패키지에 위치할지 개발자에 따라 다를 수 있습니다.
- 자신이 예상하는 패키지와 다를 때, 해당 클래스를 찾기가 어렵습니다.
❓ 선택 가이드
- 복잡도가 낮고 제공하는 기능이 적어 하나의 계층에 속하는 클래스 수가 적은가?
- 제공하는 기능을 명확한 기준으로 분리하기가 애매한가?
- 추후에 모듈별로 분리하게 될 일이 없을 것 같은 작은 규모의 프로젝트인가?
👉🏻 위에 조건이 충족된다면 계층형 구조를 추천드립니다.
- 복잡도가 높고 제공하는 기능이 많아 하나의 계층에 속하는 클래스 수가 많은가?
- 제공하는 기능을 명확한 기준으로 분리할 수 있는가?
- 추후에 모듈별로 별도 서비스로 쪼개질 가능성이 있는가?
👉🏻 위에 조건이 충족된다면 도메인형 구조를 추천드립니다.
3️⃣ DC의 프로젝트 패키지 구조
☝🏻 구조 선택과 그 이유
DC 프로젝트 패키지의 구조는 도메인형 구조를 선택하였습니다. 도메인형 구조를 선택하는 이유는 다음과 같습니다.
- 너무 많은 클래스
- 계층형 같은 경우 Controller, Service 등에 너무 많은 클래스들이 밀집하게 됩니다.
- 많게는 30 ~ 40개의 클래스들이 xxxController, xxxService 같은 패턴으로 길게 나열되어 프로젝트 전체적인 구조는 상단 디렉터리 몇 개로 빠르게 파악할 수 있지만 그 이후로는 파악하기가 더 힘들어지게 됩니다.
- 관련 코드의 응집
- 관련된 코드들이 응집해 있으면 자연스럽게 연관돼 있는 코드 스타일, 변수, 클래스 이름 등을 참고하게 되고 비슷한 코드 스타일과 패턴으로 개발할 수 있게 될 환경이 자연스럽게 마련된다고 생각합니다.
- 수정시에 계층에 있는 파일뿐만 아니라 다른 controller, service 등등에 있는 계층 패키지 파일들도 함께 변경됩니다.
- 최근 기술 동향
- 도메인 주도 개발(DDD), ORM, 객체지향 프로그래밍 등에서 도메인형 구조가 더 적합하다고 생각합니다.
- 도메인 주도 개발에서 Root Aggrete 같은 표현은 계층형보다 도메인형으로 표현했을 경우 훨씬 더 직관적이며 해당 도메인을 이해하는 것에도 효율적입니다.
✌🏻 DC의 패키지 구조
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── newmakeshop
│ │ └── designcenter
│ │ ├── DesigncenterApplication.java
│ │ ├── PingController.java
│ │ ├── domain
│ │ │ ├── design
│ │ │ │ ├── controller
│ │ │ │ ├── service
│ │ │ │ ├── entity
│ │ │ │ ├── repository
│ │ │ │ └── dto
| | | | ├── request
│ │ │ │ └── response
│ │ │ ├── source
│ │ │ │ ├── controller
│ │ │ │ ├── service
│ │ │ │ ├── entity
│ │ │ │ ├── repository
│ │ │ │ └── dto
| | | | ├── request
│ │ │ │ └── response
│ │ │ └── model : Entity 객체들이 공통적으로 사용할 객체들로 구성(주로 enum)
│ │ │ ├── YorN.java
│ │ │ └── DesignType.java
│ │ ├── global
│ │ │ ├── common
│ │ │ │ ├── request
│ │ │ │ └── response
│ │ │ ├── config
│ │ │ │ ├── SwaggerConfig.java
│ │ │ │ ├── properties
│ │ │ │ ├── resttemplate
│ │ │ │ └── security
│ │ │ ├── error
│ │ │ │ ├── ErrorResponse.java
│ │ │ │ ├── GlobalExceptionHandler.java
│ │ │ │ └── exception
│ │ │ └── util
│ │ └── infra
│ │ ├── email
│ │ └── sms
│ │ └── SmsClient.java
│ └── resources
│ ├── application-local.yml
│ ├── application-prod.yml
│ └── application.yml