Files

140 lines
5.2 KiB
Markdown

# common module 허용 기준
## 목적
`common` 모듈은 공유 편의 때문에 만드는 기본 모듈이 아니다.
기본값은 **만들지 않음** 이다.
이 문서의 목적은:
- “일단 common으로 보내자”를 막고
- 모듈 경계를 흐리는 공유를 줄이고
- 정말 필요한 공용 코드만 예외적으로 허용하는 것이다
## 공식/원전 기준 요약
- 모듈은 외부에 노출하는 API와 내부 구현을 구분해야 한다.
- 다른 모듈은 공개된 API에만 의존해야 하며, 내부 구현 의존은 막아야 한다.
- 헥사고날 아키텍처의 핵심도 경계와 역할 분리다.
- 겉보기 중복만 보고 조기 추상화를 만들면 이후 변경 비용이 커질 수 있다.
## 기본 규칙
### 1. `common`은 기본 금지
새 코드를 추가할 때 기본 선택지는 아래 순서다.
1. owning layer/module 내부에 둔다
2. 경계가 필요하면 해당 module의 API로 노출한다
3. 그래도 어느 곳에도 자연스럽게 속하지 않을 때만 `common`을 검토한다
즉 “어디 둘지 애매하면 common”을 금지한다.
### 2. `common`은 아래 조건을 모두 만족할 때만 허용
다음이 모두 참일 때만 `common` 도입을 검토한다.
- 3개 이상 모듈에서 실제로 재사용된다
- 변화 이유가 같다
- 특정 모듈이 소유한다고 보기 어렵다
- `common`으로 옮겨도 의존 방향이 더 나빠지지 않는다
- 모듈 API를 좁게 노출하는 방식으로 해결하기 어렵다
하나라도 애매하면 기존 owning module에 둔다.
### 3. “중복 존재”만으로는 common 근거가 아니다
코드가 비슷해 보여도 다음이면 `common`으로 보내지 않는다.
- 서로 다른 비즈니스 문맥에서 독립적으로 변할 가능성이 큼
- 지금은 비슷하지만 미래 요구가 갈라질 가능성이 큼
- common으로 모으면 이름과 책임이 모호해짐
즉 진짜 공통 원인(common cause)일 때만 허용한다.
### 4. 레이어 경계를 깨는 공유 금지
`common`이 아래를 섞는 것을 금지한다.
- presentation + domain
- domain + infrastructure
- application + web transport
- persistence 모델 + API 모델
- 외부 API payload + 내부 domain meaning
공유보다 경계 보존이 우선이다.
### 5. `common`에는 business policy를 두지 않는다
다음은 `common`에 두지 않는다.
- 도메인 규칙
- 상태 전이 규칙
- 권한 판정
- 에러 코드 정책
- 외부 연동별 특화 규칙
이런 것은 반드시 owning module 또는 boundary contract가 소유한다.
### 6. `common`에 둘 수 있는 것
예외적으로 허용 가능한 후보:
- 경량 value type
- 순수하고 작은 utility
- 여러 모듈이 같은 이유로 쓰는 매우 안정적인 helper
- 모듈 경계를 깨지 않는 공통 annotation / marker / tiny abstraction
- 명확한 소유자가 없는 순수한 language-level helper
단, 이것도 실제 재사용과 변화 이유가 검증되어야 한다.
### 7. `common`의 utility는 특히 좁게 제한
utility는 아래 조건을 만족할 때만 허용한다.
- side effect 없음
- framework/business/persistence 의존 없음
- 이름만 보고 역할이 분명함
- 단순 문자열/시간/컬렉션 helper라도 owning type 안에 둘 수 없는 이유가 있음
`StringUtils`, `DateUtils`, `CommonUtils`, `AppUtils` 같은 잡동사니 묶음은 금지한다.
### 8. 모듈 API 노출이 common보다 우선
Spring Modulith의 방향처럼, 공용화가 필요해 보일 때 먼저 검토할 것은:
- 해당 모듈의 공개 API로 노출할 수 있는가
- named interface처럼 노출 범위를 좁게 지정할 수 있는가
- explicit dependency로 필요한 부분만 허용할 수 있는가
즉 “common으로 이동”보다 “모듈 API 설계 개선”을 먼저 본다.
### 9. 공용 타입은 더 보수적으로 관리
`common`으로 이동한 타입은 사실상 여러 모듈이 기대는 기반이 된다.
기본:
- 변경에 더 보수적이어야 한다
- naming을 더 명확히 해야 한다
- Javadoc/문서가 더 중요하다
- examples/tests가 함께 있어야 한다
### 10. `common`은 dump zone이 아니다
다음 징후가 보이면 잘못된 `common`이다.
- 이름이 `Common*`, `Util*`, `Base*`, `Helper*` 위주
- business/domain/web/persistence 코드가 섞여 있음
- 모듈 간 순환 의존을 가리기 위해 common을 사용
- “일단 여기 두자”가 반복됨
이 경우 common을 늘리는 대신 다시 소유 모듈로 분해한다.
### 11. common 도입은 문서화한다
새로운 `common` 타입/패키지를 추가할 때는 최소한 아래를 설명한다.
- 왜 owning module에 둘 수 없는가
- 어떤 모듈들이 실제로 재사용하는가
- 같은 이유로 어떻게 함께 바뀌는가
- 어떤 경계를 깨지 않는가
설명할 수 없으면 common으로 보내지 않는다.
## 프로젝트 기준 요약
- `common` 기본 금지
- 재사용만으로는 부족하고 “같은 이유로 함께 변함”이 필요
- 모듈 API 설계 개선이 common보다 우선
- 경계/레이어를 섞는 공용화 금지
- business policy는 common 금지
- utility/common dump zone 금지
- 예외적 허용 시에도 좁고 순수하고 안정적인 타입만