본문으로 바로가기

1. 계층형 구조

controller
    ⎿ MemberController
    ⎿ PostController
    ⎿ CommentController

service
    ⎿ MemberService
    ⎿ PostService
    ⎿ CommentService

dao
    ⎿ MemberDao
    ⎿ PostDao
    ⎿ CommentDao
   
domain
    ⎿ Member
    ⎿ Post
    ⎿ Comment
  • 애플리케이션에서 사용하는 계층별로 패키지를 구성하는 방식
  • 장점
    • 프로젝트 전반적인 이해도가 낮아도, 패키지 구조만 보고 전체적인 구조를 파악할 수 있음
      • 애플리케이션의 API를 보고 흐름을 파악하고 싶다면, Controller 패키지 하나만 보고 파악할 수 있음
    • 계층별 응집도가 높아짐
      • 계층별 수정이 일어날 때, 하나의 패키지만 보면 됨
  • 단점
    • 도메인별 응집도가 낮음
      • 하나의 도메인 흐름을 보고 싶을 때, 모든 계층 패키지를 봐야 함
      • 도메인과 관련된 스펙과 기능이 변경되었을 때, 변경 범위가 커짐
    • 규모가 커질 경우, 하나의 패키지에 안에 여러 클래스들이 모여 구분이 어려워지게 됨

 

 

2. 도메인형 구조

Member
    ⎿ controller
    ⎿ service
    ⎿ dao
    ⎿ dto
    
Post
    ⎿ controller
    ⎿ service
    ⎿ dao
    ⎿ dto

Comment
    ⎿ controller
    ⎿ service
    ⎿ dao
    ⎿ dto
  • 도메인을 기준으로 패키지를 나눈 구조
  • 장점
    • 도메인별 응집도가 높아짐
      • 도메인의 흐름을 파악하기 쉬워짐
      • 도메인과 관련된 스펙 및 기능이 변경되었을 대, 해당 도메인 패키지에서만 변경이 일어남
  • 단점
    • 애플리케이션의 전반적인 흐름을 한눈에 파악하기 어려움
    • 개발자의 관점에 따라 도메인을 구분하는 기준이 다를 수 있음

 

 

계층형과 도메인형 중 어느 구조를 선택해야 할까?

패키지 방식에서 정답은 없지만, 최신 기술 동향에 따라 도메인형 구조를 많이 사용하는 추세이다.

 

계층형을 사용하게 될 경우, 너무 많은 클래스들이 밀집하게 된다. 이렇게 되면 프로젝트의 전체적인 구조를 상위 디렉토리 몇 개로 빠르게 파악할 수는 있지만, 오히려 그 이후로는 더 파악하기가 어려워진다.

 

도메인형 패키지 구조의 경우, 스프링 웹 계층이 아닌 도메인에 주목하여 계층형 보다 직관적이고, 각각의 도메인 별로 패키지 분리가 가능하여 관리에 있어 계층형보다 더 직관적이다. 또한, 도메인 주도 개발OOP 관점 그리고 ORM 기술을 사용하는데 핵심이 되는 Entity(엔티티)의 특성을 기반으로 패키징하는 것이 해당 기술들의 관점에서 더 적합하다고 보는 것 같다. 

 

[도메인형 디렉토리 구조]

└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── example
    │   │           └── spring
    │   │               ├── SpringBootApplication.java
    │   │               ├── domain
    │   │               │   ├── member
    │   │               │   │   ├── api
    │   │               │   │   │   └── MemberApi.java
    │   │               │   │   ├── application
    │   │               │   │   │   └── MemberSearchService.java
    │   │               │   │   ├── dao
    │   │               │   │   │   └── MemberFindDao.java
    │   │               │   │   ├── domain
    │   │               │   │   │   └── Member.java
    │   │               │   │   ├── dto
    │   │               │   │   │   └── SignUpRequest.java
    │   │               │   │   └── exception
    │   │               │   │   │   └── MemberNotFoundException.java
    │   │               │   ├── item
    │   │               │   │   ├── api
    │   │               │   │   ├── application
    │   │               │   │   ├── dao
    │   │               │   │   ├── domain
    │   │               │   │   ├── dto
    │   │               │   │   └── exception
    │   │               │   └── model
    │   │               │   │   ├── Address.java
    │   │               │   │   └── Email.java
    │   │               ├── global
    │   │               │   ├── common
    │   │               │   │   ├── request
    │   │               │   │   └── response
    │   │               │   ├── config
    │   │               │   │   ├── SwaggerConfig.java
    │   │               │   │   ├── properties
    │   │               │   │   ├── resttemplate
    │   │               │   │   └── security
    │   │               │   ├── error
    │   │               │   │   ├── ErrorResponse.java
    │   │               │   │   ├── GlobalExceptionHandler.java
    │   │               │   │   └── exception
    │   │               │   └── util
    │   │               └── infra
    │   │                   ├── email
    │   │                   └── sms
    │   │                       ├── AmazonSmsClient.java
    │   │                       ├── SmsClient.java
    │   │                       └── dto
    │   └── resources
    │       ├── application-dev.yml
    │       ├── application-local.yml
    │       ├── application-prod.yml
    │       └── application.yml
  • 최상위 레벨 패키지
    • domain: 도메인을 담당
      • model: Domain Entity 객체들이 공통적으로 사용할 객체들로 구성
    • global: 전체적인 설정 관리(프로젝트 전방위적으로 사용)
    • infra: 외부 인프라 구조 관리
  • domain 하위 패키지
    • api: Controller 클래스 존재. Rest API 서버의 역할을 담당
    • domain: 도메인 Entity 클래스와 와 특정 도메인에만 속하는 Embeddable, Enum 같은 클래스로 구성
    • dto: 주로 Request, Response 객체들로 구성
    • exception: 해당 도메인이 발생시키는 Exception 클래스로 구성
    • application: 도메인 객체와 외부 영역을 연결해주는 역할로, 주로 DB 트랜잭션을 처리하고 주된 비즈니스 로직을 담당함(Service 계층과 유사)
    • dao: repository와 유사, 조회 전용 구현체들로 구성
  • global 하위 패키지
    • auth : 인증, 인가와 관련된 클래스들로 구성
    • common : 공통 클래스 혹은 공통 value 클래스들로 구성
    • config : 각종 스프링 configuration 클래스로 구성
    • error : 공통 exception, error와 관련된 클래스로 구성
    • infra : 외부 모듈, api 등을 사용하는 클래스로 구성
    • util : 공통 util성 클래스들로 구성
  • infra 하위 패키지
    • 대표적으로 이메일 알림, SMS 알림 등 외부 서비스에 대한 코드들이 존재

 

 

 

 

 

 

[참고]

https://cheese10yun.github.io/spring-guide-directory/