Skip to Content
Blog리팩토링 고민 기록패키지의 구조에 대한 고민

패키지 구조에 대한 고민

프로젝트를 시작할 때마다 습관처럼 controller, service, repository 폴더를 만들었다.
처음 배울때 계층 기반 패키지 구조로 배웠고, 딱히 의심 없이 써왔다.

“이 구조가 나한테 맞는 건가? 더 나은 방식이 있지 않을까?”

그래서 계층 기반 구조를 다시 들여다보고, 도메인 기반 구조와 비교해봤다.
어떤 상황에서 어떤 구조를 선택해야 하는지 고민한 기록을 남긴다.



계층 기반 패키지 구조 (Layer-based)

기술적인 역할, 즉 계층(Layer) 을 기준으로 패키지를 나누는 방식이다.

com.example.project ├── controller │ ├── UserController.java │ └── OrderController.java ├── service │ ├── UserService.java │ └── OrderService.java └── repository ├── UserRepository.java └── OrderRepository.java

장점

  • 구조가 단순하고 직관적이다.
  • 어느 계층에 파일이 있는지 예측하기 쉽다.
  • 소규모 프로젝트에서는 오히려 이 구조가 더 깔끔하게 느껴진다.

단점

  • 프로젝트가 커질수록 한 폴더 안에 파일이 수십 개 쌓인다.
  • User 관련 코드가 controller, service, repository 에 뿔뿔이 흩어진다.
  • User 기능을 파악하려면 4개 폴더를 모두 열어야 한다.
  • 기능 단위로 묶여 있지 않아서 특정 기능을 통째로 삭제하거나 분리하기 어렵다.


도메인 기반 패키지 구조 (Domain-based)

비즈니스 기능(도메인) 을 기준으로 패키지를 나누는 방식이다.

com.example.project ├── user │ ├── UserController.java │ ├── UserService.java │ ├── UserRepository.java │ └── User.java ├── order │ ├── OrderController.java │ ├── OrderService.java │ ├── OrderRepository.java │ └── Order.java └── common ├── exception │ └── GlobalExceptionHandler.java └── config └── SecurityConfig.java

장점

  • user 폴더 하나만 열면 유저 관련 코드가 모두 모여 있다.
  • 기능 추가, 수정, 삭제 시 해당 도메인 패키지만 건드리면 된다.

단점

  • 처음 구조를 잡을 때 도메인 경계를 잘못 나누면 나중에 더 복잡해진다.
  • 경계가 불분명한 경우, 어디에 둬야 할지 고민이 생긴다.


그래서 내가 선택한 구조는?

요즘 도메인 기반 구조가 대세라고 한다.

그럼에도 불구하고, 나는 계층 기반 구조를 선택하기로 했다. 이유는 두 가지다.

첫 번째는 내가 진행하는 웹 개발 프로젝트의 특성상 구조 자체가 복잡하지 않다는 점이다. 도메인이 명확하게 분리될 만큼 규모가 크지 않은 상황에서 굳이 도메인 기반 구조를 도입하는 건 오히려 과한 설계라는 생각이 들었다.

첫 번째는 웹 개발의 특성상 이미 계층 기반으로도 도메인이 충분히 구분된다는 점이다. 웹 애플리케이션은 메뉴(기능) 단위로 설계되고, UserController, OrderController 처럼 네이밍 자체가 자연스럽게 도메인을 구분해준다. 패키지 구조까지 도메인 기반으로 가져가는 건 이미 나뉘어진 것을 한 번 더 나누는 느낌이었다. 굳이 도메인으로 나누지 않아도 충분히 깔끔하다고 판단했다.

두 번째는 도메인 기반 구조는 도메인 경계가 불분명한 기능이 생겼을 때 고민이 깊어진다.

마지막 수정