5.3 KiB
5.3 KiB
title, source_type, status, related_branches, related_projects, tags, created, status_label, target_audience, inspiration_url, archive_url
| title | source_type | status | related_branches | related_projects | tags | created | status_label | target_audience | inspiration_url | archive_url | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| blog-topic / domain-modeling-guardrails-as-archunit-fitness-functions-2026-06-05 | blog-topic | raw |
|
|
|
2026-06-05 | ready-for-canonical | backend-engineer |
blog-topic: domain-modeling-guardrails-as-archunit-fitness-functions-2026-06-05
Layer:
raw/blog-topics/— 작업·트러블슈팅에서 나온 글감 원석. canonical 정제 전 raw.
Parent
한 줄 글감
"DDD 전술 패턴을 README 권고가 아니라 빌드 깨짐으로 강제하기 — stereotype 애너테이션 + ArchUnit fitness function."
본문 뼈대 (초안)
- 문제: rich domain model / 값 객체 불변식 / transport-free 도메인 이벤트는 보통 "문서 권고"로 남고 시간이 지나면 침식된다(anemic 회귀, public setter, 도메인에 Kafka 타입 누출).
- 접근: 의미를 드러내는 마커 애너테이션을 도메인 코어에 둔다 —
@ValueObject/@AggregateRoot/@DomainEvent(java.lang.annotation 만 의존, 프레임워크 0). - 강제: ArchUnit 규칙이 마커를 키로 평가
value_objects_have_no_public_no_arg_constructor— 빈 생성자 = 불변식 우회 백도어 차단. record(컴포넌트 보유)는 자동 충족.aggregate_root_setters_are_not_public—set*비공개 강제(Vernon Option A: ORM 외부 매핑 가시성).domain_events_are_records+domain_events_are_transport_free— immutable record + Kafka/HTTP/JAX-RS 패키지 의존 금지.domain_has_no_logger— 도메인은 로그 대신 안전한 명사형 reason enum 예외로 위반을 표현.
- owner 경계 교훈: "도메인 순수성" 규칙(다른 branch 소유)에 logger 금지를 끼워넣지 않고 별도 규칙으로 분리한 이유 — 규칙 소유권/위반 메시지 명확성.
- 정직성 교훈: logger 금지는 공식 표준이 아니라 프로젝트 자체 규약. 사실 등급을 격상하지 않는다.
- 비공허(non-vacuous) 증명: 규칙마다 의도적 위반 fixture + 격리 코퍼스로 "실제로 잡는다"를 테스트(violations-as-data). transport glob 은 broker별 격리 증명.
- 함정:
testCompileOnly타입을 record component 로 쓰면 JUnit discovery 가 죽는다 → method body.class참조로 회피(raw/errors/archunit-testcompileonly-class-loading-2026-06-02). - 불변식 검증의 깊이: 예시 테스트 대신 jqwik property-based test 로 값 객체 입력 공간 전체를 무작위 검증.
- 이벤트 경계 PoC:
WorkLogReserved(domain) →WorkLogReservedIntegrationEvent(application mapper) — 도메인은 wire 를 모른다.
Cross-links
- raw/blog-topics/archunit-testcompileonly-fixture-annotation-pattern-2026-06-02
- raw/blog-topics/archunit-violations-as-data-pattern-2026-05-28
- raw/interviews/domain-modeling-guardrails-archunit-2026-06-05
트리거 / Trigger
- 트리거 유형:
branch-work - 트리거 날짜: 2026-06-05
- 트리거 연결 노트: raw/branch-notes/feature-domain-modeling-guardrails
글감 / Topic seed
- 한 문장 요지: DDD tactical pattern을 README 권고가 아니라 marker annotation + ArchUnit fitness function으로 빌드 단계에서 강제한다.
- 예상 제목 후보:
- DDD guardrail을 ArchUnit fitness function으로 만들기
- Value Object와 Domain Event 규칙을 빌드에서 검증하기
핵심 주장 후보 / Claim candidates
- 사실 후보:
@ValueObject,@AggregateRoot,@DomainEvent같은 marker를 ArchUnit rule의 평가 key로 쓴다.
- 의견/해석 후보:
- domain modeling 규칙은 공식 표준이 아니라 project-local guardrail이므로 사실 등급을 조심해야 한다.
Outline seed
- tactical DDD rule이 문서 권고로만 남을 때 침식되는 경로를 설명한다.
- framework-free marker annotation과 ArchUnit rule의 역할을 나눈다.
- violations-as-data와 jqwik property test로 guardrail이 실제로 bite하는지 확인한다.
Canonical 전환 후보 / Canonical extraction candidates
wiki/projects/ca-tmpl/clean-architecture-package-layout.md후보:- domain modeling guardrail / ArchUnit fitness function 글감.
- 필요한 추가 검증:
- 현재 marker annotation, ArchUnit rule, jqwik test 존재 여부.
Sources / 근거 후보
- raw/branch-notes/feature-domain-modeling-guardrails
- raw/blog-topics/archunit-violations-as-data-pattern-2026-05-28
- raw/errors/archunit-testcompileonly-class-loading-2026-06-02
미해결 / Unknown
- 아직 확인해야 할 사실: domain guardrail 구현과 property-based test의 현재 상태.
- 과장하면 안 되는 부분: logger ban이나 marker taxonomy를 DDD 공식 표준처럼 쓰지 않는다.
Decision / 처리 결정
- 액션:
promote-to-canonical - 이유:
wiki/projects/ca-tmpl/clean-architecture-package-layout.md에 domain modeling guardrail 글감으로 반영한다. - 다음 단계: blogify 전 project-local rule과 구현 증거를 분리한다.