일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 네이버
- 릿코드
- Node
- 프로그래머스
- Ai
- 티스토리챌린지
- 카카오페이
- 결제취소
- SQL
- 깃허브
- it #응집도 #결합도 #소프트웨어
- 결제
- 웹훅
- openai
- 데이터베이스 #백엔드 #데이터
- OpenCV
- 포트원
- 코딩테스트
- supabase
- sw
- 오블완
- OCR
- 토스페이
- ETF
- clova
- certbot
- 백준
- 정렬
- 간편결제
- 코딩
- Today
- Total
싱싱미역상태
폴더 구조 본문
도메인형, 계층형
회사 신규 프로젝트를 진행 중에 있어서 폴더 구조의 고민을 했습니다. 어떤 형태로 폴더 구조를 세팅해야 회사에게 맞는 구조인지 찾아보았습니다. 폴더 구조를 세팅할 때 가장 먼저 떠오른 2가지는 계층형과 도메인형입니다. 각 2개의 특징을 알아보겠습니다.
계층형
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ └── demo
│ │ ├── DemoApplication.java
│ │ ├── config
│ │ ├── controller
│ │ ├── dao
│ │ ├── domain
│ │ ├── exception
│ │ └── service
│ └── resources
│ └── application.properties
계층형은 각 계층을 폴더의 상단에 두는 방법이 됩니다. 예를 들어 userController, adminController, teacherController가 있다면, 3개의 컨트롤러가 모두 controller라는 폴더에 들어가는 방식입니다.
장단점
장점으로는 신규 개발자가 입사를 해도 빠르게 계층과 흐름을 파악 할 수 있습니다. 따라서 규모가 작은 프로젝트에 적합하다는 생각을 했습니다.
하지만 단점으로는 규모가 작은 프로젝트여도 지속적인 기능개발이 이루어지면 규모가 커지게 됩니다. 따라서 여러 도메인에 대한 controller, service들이 생성되면서 각 폴더의 부피가 커지게 되는 단점이 있습니다.
또한 개인적인 생각이지만, 만약 서비스 규모가 점차 커지는 경우 api요청이 많은 부분만 따로 분리하는 아키텍처 형식(EX. MSA)으로 마이그레이션이 매우 힘들 것 같습니다. 왜냐하면 모든 컨트롤러를 각 도메인이 맞게 분리를 해야한다고 생각하기 때문입니다.
도메인형
└── 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
계층형의 단점을 보완해서 나온 것이 도메인형 폴더 구조입니다. 도메인형 폴더 구조는 각 도메인 폴더를 기준으로 코드가 작성됩니다. 따라서 폴더에 존재하는 코드들은 폴더끼리 응집해있습니다.
domain
├── domain
│ ├── member
│ │ ├── api
│ │ │ └── MemberApi.java
│ │ ├── application
│ │ │ ├── MemberProfileService.java
│ │ │ ├── MemberSearchService.java
│ │ │ ├── MemberSignUpRestService.java
│ │ │ └── MemberSignUpService.java
│ │ ├── dao
│ │ │ ├── MemberFindDao.java
│ │ │ ├── MemberPredicateExecutor.java
│ │ │ ├── MemberRepository.java
│ │ │ ├── MemberSupportRepository.java
│ │ │ └── MemberSupportRepositoryImpl.java
│ │ ├── domain
│ │ │ ├── Member.java
│ │ │ └── ReferralCode.java
│ │ ├── dto
│ │ │ ├── MemberExistenceType.java
│ │ │ ├── MemberProfileUpdate.java
│ │ │ ├── MemberResponse.java
│ │ │ └── SignUpRequest.java
│ │ └── exception
│ │ ├── EmailDuplicateException.java
│ │ ├── EmailNotFoundException.java
│ │ └── MemberNotFoundException.java
│ └── model
│ ├── Address.java
│ ├── Email.java
│ └── Name.java
model
- Domain Entity 객체들이 공통적으로 사용할 객체
- Embeddable 객체, Enum 객체도 가능
member
- /api : 컨트롤러 클래스 / REST api
- /domain : 도메인 엔티티 / Embeddable 객체, Enum 객체도 가능
- /dto : Request, Response 객체
- /exception : 해당 도메인에서만 발생하는 Exception
- /application : 서비스 클래스 / DB 트랙잭션 처리
- /dao : 레포지토리
global
├── global
│ ├── common
│ │ ├── request
│ │ └── response
│ │ └── Existence.java
│ ├── config
│ │ ├── SwaggerConfig.java
│ │ ├── properties
│ │ ├── resttemplate
│ │ │ ├── RestTemplateClientHttpRequestInterceptor.java
│ │ │ ├── RestTemplateConfig.java
│ │ │ └── RestTemplateErrorHandler.java
│ │ └── security
│ ├── error
│ │ ├── ErrorResponse.java
│ │ ├── GlobalExceptionHandler.java
│ │ └── exception
│ │ ├── BusinessException.java
│ │ ├── EntityNotFoundException.java
│ │ ├── ErrorCode.java
│ │ └── InvalidValueException.java
│ └── util
common
- 공통으로 사용되는 Value 객체들
- 페이징 처리를 위한 Request
- 공통된 응답을 주는 Response 객체들
config
- 스프링 각종 설정
error
- 예외 핸들링을 담당하는 클래스
util
- 유틸성 클래스
infra
└── infra
├── email
└── sms
├── AmazonSmsClient.java
├── KtSmsClient.java
├── SmsClient.java
└── dto
└── SmsRequest.java
infra
- 인프라 스트럭처 관련된 코드들
- 인프라 스트럭처는 대표적으로 Email 알림, SMS 알림 등 외부 서비스에 대한 코드들이 존재(그렇기 때문에 domain, global에 속하지 않음)
- global로 볼 수는 있지만 이 계층도 잘 관리해야 하는 대상이기에 별도의 디렉터리가 필요
장단점
장점으로는 도메인별로 구분을 하기 때문에 나중에 규모가 커지면서 각 도메인을 따로 분리를 하고 싶은 경우, 해당 도메인만 가져다가 서버에 띄우면 됩니다.
하지만 단점으로는 전체적인 프로젝트의 서비스를 이해하기 어렵습니다. 특히 신입 개발자가 입사하는 경우, 전체 적인 아키텍처를 이미지화 하기에 어려운 측면이 존재합니다.
개인적으로는 DDD 구조를 따라가는 방법이 확장성 측면과 유지 보수 측면 그리고 본인이 할당 받은 기능에 초점을 맞추어서 관련된 도메인을 바탕으로 집중할 수 있는 좋은 방법이라고 생각합니다. 물론 서비스 자체를 이해하는 것에 시간이 걸리겠지만, 그래도 개인의 입장보다는 회사의 측면에서는 좋은 방안이라고 생각이 들었습니다.
참고
'SW' 카테고리의 다른 글
SSL 자동 갱신 (0) | 2024.11.21 |
---|---|
깃허브 로그인 인증 방식에서 RSA 인증 방식으로 (0) | 2024.11.18 |
Spring Boot와 Node 비교 (3) | 2024.11.14 |
클라우드 서버와 물리적 서버 사이의 이미지 전송에 대한 고민 (0) | 2024.11.11 |
결제 시스템 흐름 정리 (3) | 2024.11.06 |