결정-0050: 컨텍스트 내부를 피쳐 단위로 나눈다
상태
Accepted
맥락
컨텍스트 내부의 application 을 명령과 조회 두 형제 패키지로 나눈 구성을 운영하면 두 가지가 나타납니다.
기능이 흩어집니다. 하나의 요구사항이 명령과 조회 양쪽에 걸쳐, 함께 변경되는 코드가 물리적으로 떨어집니다. 요구사항 하나를 고치는 작업이 두 폴더 이상을 오가는 일이 됩니다.
구조가 비대칭입니다. 화면 조회에는 분리할 조율 로직이 없어 단위 테스트 대상에도 해당하지 않습니다. 쓰기 경로에만 유효한 분리를 읽기 경로에도 패키지 수준으로 강제하면 형식만 남습니다.
컨트롤러를 별도 패키지에 두는 구성도 같은 문제를 만듭니다. 컨트롤러가 쓰기와 조회 어느 쪽에도 완전히 속하지 않는다는 것이 분리의 근거였는데, 두 요소가 한 패키지에 모이면 그 근거가 사라집니다.
결정
컨텍스트 내부의 1차 분류는 계층이 아니라 피쳐입니다. 컨트롤러 · 서비스 · DTO · 포트가 한 패키지에 모입니다.
| 항목 | 결정 내용 |
|---|---|
| 패키지 단위 | application/<피쳐> 를 씁니다. 명령과 조회를 형제 패키지로 나누지 않습니다 |
| 피쳐 내부 구성 | 제약을 두지 않습니다. 평면 구성, DTO만 분리, 같은 종류가 둘 이상일 때만 하위 패키지를 모두 허용합니다 |
| 경로 분리 | 원칙으로 유지하되 패키지가 아니라 클래스 역할로 구분합니다 |
| 컨트롤러 배치 | 해당 피쳐 패키지에 둡니다. 여러 피쳐를 참조하면 의존도가 가장 높은 곳에 둡니다 |
| 계층 식별 | 폴더가 아니라 어노테이션과 접미사로 합니다 |
검토한 대안
계층을 1차 분류로 유지한다
| 구분 | 내용 |
|---|---|
| 장점 | 폴더명만으로 계층을 알 수 있습니다. 새로 합류한 사람이 구조를 즉시 파악합니다 |
| 단점 | 요구사항 하나를 고칠 때 네 폴더를 오갑니다. 함께 변경되는 코드가 가장 멀리 떨어집니다 |
| 기각 사유 | 화면 요구가 빈번하게 바뀌는 환경에서는 변경 빈도가 높은 축을 1차로 두는 편이 낫습니다 |
결과
요구사항 하나를 고칠 때 패키지 하나만 엽니다. 조회 경로에 형식적 분리를 강제하지 않게 됩니다.
감수하는 것은 폴더명으로 계층을 알 수 없다는 점입니다. 그래서 계층 식별을 이름 규약에 위임하고, 그 규약을 사람이 아니라 ArchUnit이 검사하게 했습니다. 규약이 깨지면 검사도 함께 무력해지므로 접미사 변경은 규칙 변경으로 취급합니다.