아래 설명되는 코드는 해당링크의 Git 에 있다.
현재 스프링부트 개발자들이 사용하는 패키지 구조는 크게 레이어 계층형 구조와 도메인형 2가지의 유형이 존재한다고 생각한다. 각 유형에 대한 나의 개인적인 BP를 얘기하려고한다.
계층형
나는 이전까지의 모든 프로젝트에서 계층형 구조의 패키지관리를 시행해 왔었다.
└── src
├── main
│ ├── java
│ │ └── learn
│ │ └── jwt
│ │ └── andsocket
│ │ ├── AndSocketApplication.java
│ │ ├── config
│ │ ├── controller
│ │ ├── exception
│ │ ├── filter
│ │ ├── handler
│ │ ├── model
│ │ ├── principal
│ │ ├── repository
│ │ └── service
│ └── resources
│ ├── application.yml
│ └── application-jwt.yml
이렇게 계층형 구조를 사용한 경우 각 계층을 대표하는 디렉터리 네이밍을 지어 클래스들을 관리한다.
계층형 구조로 프로젝트를 진행할 경우에 장점으로는 개발자가 유지 보수하는 입장에서 편하다.
좀 더 쉽게 풀어서 설명하자면 내가 진행중이던 프로젝트를 다른 개발자가 보더라도 직관적이라 구조를 빠르게 파악할 수 있다. 단점은 디렉터리에 너무 많은 클래스가 모이게된다.
위에 구조를 예시로 Config 패키지는 프로젝트의 설정관련 파일이 전부 모이는 파일이다. Redis에 관한 설정파일이던 Jwt에 관할 설정파일이던 모든 클래스파일이 모이게된다.
개인적으로 계층형 구조로 패키지를 관리할 경우 프로젝트가 수정 추가됨에 따라 규모가 커지면 커질수록 파일을 찾기가 어렵다. 그래서 여태까지 써왔던 구조이지만 지금부터는 지양하려고한다.
그럼 도메인형 구조는?
도메인형 구조는 다음과 같다.
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ └── customexception
│ │ ├── DemoApplication.java
│ │ ├── domain
│ │ │ ├── api
│ │ │ ├── application
│ │ │ │ └── impl
│ │ │ ├── dto
│ │ │ ├── entity
│ │ │ ├── exception
│ │ │ └── repository
│ │ └── global
│ │ ├── application
│ │ ├── config
│ │ ├── entity
│ │ ├── exception
│ │ ├── filter
│ │ ├── handler
│ │ ├── principal
│ │ └── filter
│ └── resources
│ └── application.yml
도메인 디렉터리는 네이밍에서도 느껴지지만 도메인별로 패키지화하여 해당 도메인에 필요한 패키지를 하위 디렉터리로 나두어 사용하게되어 개발자가 클래스 관리가 편해진다. 관련 코드들끼리 응집이 되어있으니 찾기 편해지는 것이다.
단점으로는 프로젝트에 이해도가 낮을 경우 계층형 구조와 반대로 전체적인 구조의 이해도가 낮아지게된다.
개인적인 생각
여태까지의 모든 프로젝트에서 계층형 구조를 사용해왔지만 지금부터는 지양하려고 한다.
계층형 구조를 사용할때 가장 불편해던 점은 프로젝트의 규모가 작으면 괜찮지만 구조가 커짐에 따라 개발자인 내가 관리하기가 힘들다는 점에서 계층형 구조를 비추한다.
단, 프로젝트의 규모가 작은 경우 계층형 구조를 사용하는 것도 나쁘지 않지만 도메인 구조를 사용하는것이 직관적인 느낌이 강해 규모 여부에 상관없이 사용하는 것을 개인적으로 추천한다.
계층형을 추천안하는 이유?
계층형을 사용할 경우 대부분의 경우 Entity하나당 따라오는 클래스가 Controller,Service,Repository,DTO 등 많게는 Config와 Filter까지 추가하여 상상도 할수없이 많이 나온다. 대략 50여개의 클래스들이 XXXXController, XXXXService 패턴으로 나열될경우 직관적이지도 못할 뿐더러 한패키지에 전부몰려있어 미관상의 이유와 효율적이지 못한 이유 둘다 존재한다.
그럼 계층형 방식의 네이밍을 사용하되 그 안에서 도메인 별로 분류하는것은?
사실 이러한 방식도 나쁘지는 않다고 생각은 하되 개인적으로는 계층형의 반복이라고 생각한다.
예를 들어 도메인 구조의 경우 도메인 별로 디렉터리화 되어있기 때문에 직관적이라는 장점이 있다. 내가 현재 회원관련 디렉터리의 서비스 코드를 건드려야한다고 가정하였을 때 Service -> Member -> Service로 패키지가 중복되면서 명확하지 못한다. 위의 구조에서 최상위 디렉터리만 없애면 도메인 형식의 구조인데 굳이?라는 의문도 든다.
그럼 도메인형을 추천하는 이유?
우선 관련된 코드들끼리 뭉쳐있게 된다. 이럴 경우의 장점은 변수명을 헷갈리거나 하는 이슈를 줄일 수 있고 클래스,서비스로직을 비슷한 디자인 패턴으로 개발할 수 있다. 즉 코드에 일관성이 높아진다. 또한 최근 "도메인 주도 개발" 이 추세이고 스프링 프레임워크가 결국 객체지향적 구조를 사용하기 때문에 도메인형 구조가 적합하다고 생각한다.
참고했던 Best Practice 구조
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── spring
│ │ └── guide
│ │ ├── ApiApp.java
│ │ ├── SampleApi.java
│ │ ├── domain
│ │ │ ├── coupon
│ │ │ │ ├── api
│ │ │ │ ├── application
│ │ │ │ ├── dao
│ │ │ │ ├── domain
│ │ │ │ ├── dto
│ │ │ │ └── exception
│ │ │ ├── member
│ │ │ │ ├── api
│ │ │ │ ├── application
│ │ │ │ ├── dao
│ │ │ │ ├── domain
│ │ │ │ ├── dto
│ │ │ │ └── exception
│ │ │ └── model
│ │ │ ├── Address.java
│ │ │ ├── Email.java
│ │ │ └── Name.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
* 참고링크 https://cheese10yun.github.io/spring-guide-directory/
이 구조는 크게 domain,global,Infra로 나누어 사용되며 domain에는 dbEntity와 관련된 클래스, global에는 filter나 config같은 전체 설정 클래스, infra에는 서버 관련 클래스를 나누어 관리한다.
결론
물론 사람의 취향차이이지만 프로젝트가 커질 수록 결국 도메인형의 구조를 선택할 수 밖에 없다고 생각한다.
또한 디렉터리의 네이밍과 위치 만으로도 다른 개발자에게 해당 디렉터리 하위 클래스들이 무슨 역할을 하는지 한번에 전달하는 것이 중요하기에 네이밍도 중요하다고 생각한다.
'Spring-boot' 카테고리의 다른 글
N+1 이슈 (0) | 2022.12.06 |
---|---|
@Getter와 @Setter는 왜 지양되어야 하는가? (0) | 2022.11.29 |
[JPA] 비즈니스 로직 디자인 패턴에 관한 정리 (0) | 2022.08.27 |
Web-Socket 공부 흔적(2) STOMP를 사용하는 채팅방[SpringBoot] (0) | 2022.07.09 |
[JWT-Token] 스프링 시큐리티 JWT 토큰을 이용한 스프링부트 프로젝트 만들기 -(1) (0) | 2022.06.28 |