10 KiB
title, source_type, url, archive_url, status, confidence, tags, related_branches, related_projects, created, last_reviewed
| title | source_type | url | archive_url | status | confidence | tags | related_branches | related_projects | created | last_reviewed | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Martin Fowler — Anemic Domain Model (anti-pattern) | official-doc | https://martinfowler.com/bliki/AnemicDomainModel.html | https://web.archive.org/web/2024/https://martinfowler.com/bliki/AnemicDomainModel.html | raw | high |
|
|
|
2026-05-22 | 2026-05-27 |
Martin Fowler — AnemicDomainModel
Layer:
raw/official-docs/— Martin Fowler bliki "AnemicDomainModel" (2003-11-25) verbatim 발췌. ca-tmpl 의 Rich Domain Model 강제 결정 (invariant in constructor / safe reason enum / domain logger ban) 의 1차 근거.
Parent / 활용 branch (필수)
| Branch | 이 자료가 정당화하는 결정 |
|---|---|
| raw/branch-notes/feature-domain-modeling-guardrails | rich model 강제 — domain class에 invariant 위치, mutation은 aggregate method 호출만, anemic getter/setter 거부 |
| raw/branch-notes/feature-architecture-enforcement-rules | "all logic in *Service" anemic 패턴을 ArchUnit 룰로 차단 (domain method 비어있으면 lint 경고) 근거 |
| raw/branch-notes/feature-skeleton-package-blueprint-contract | feature 패키지 내 domain/ 디렉터리가 단순 DTO 가 아니라 behavior 포함 entity/VO 임을 강제 |
| raw/branch-notes/feature-domain-feature-onboarding-contract | 신규 feature 온보딩 시 anemic 회피 체크리스트 (생성 시 invariant validation / setter 노출 금지) 근거 |
컨텍스트 / 왜 저장했는지
ca-tmpl 결정: "domain logger ban + safe reason enum + invariant in constructor"는 Rich Domain Model을 강제하는 결정. 반대 방향(Anemic Model)은 ca-tmpl이 명시적으로 거부한 안티패턴. Fowler의 글이 가장 자주 인용되는 출처.
출처 / Source
- 원본 URL: https://martinfowler.com/bliki/AnemicDomainModel.html
- 아카이브 URL: https://web.archive.org/web/2024/https://martinfowler.com/bliki/AnemicDomainModel.html
- 보조: Eric Evans "Domain-Driven Design" Ch.5 (entity behavior)
- 보조: "Refactoring" 2nd ed. — primitive obsession / value object 추출
- 저자/조직: Martin Fowler
- 발행일: 2003-11-25
- 마지막 확인일: 2026-05-27
핵심 인용 / Key quotes (verbatim)
[§Opening] "at first blush it looks like the real thing...little more than bags of getters and setters"
[§Critique] "The fundamental horror of this anti-pattern is that it's so contrary to the basic idea of object-oriented design; which is to combine data and process together."
[§Critique] "The anemic domain model is really just a procedural style design, exactly the kind of thing that object bigots like me...have been fighting"
[§Cost] "they incur all of the costs of a domain model, without yielding any of the benefits"
[§Cost] "The primary cost is the awkwardness of mapping to a database, which typically results in a whole layer of O/R mapping"
[§Consequence] "you essentially end up with Transaction Scripts, and thus lose the advantages that the domain model can bring"
[§Domain logic] "The logic that should be in a domain object is domain logic - validations, calculations, business rules"
[§Eric Evans 인용] "the more common mistake is to give up too easily on fitting the behavior into an appropriate object, gradually slipping toward procedural programming."
Claims Extracted / 추출된 주장
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|---|---|---|---|---|---|
| FOWLER-ANEMIC-C1 | Anemic Domain Model 은 OO 의 핵심 원칙 (data + process 결합) 에 반하므로 anti-pattern 으로 분류된다 | [§Critique] "it's so contrary to the basic idea of object-oriented design; which is to combine data and process together" | engineering-blog |
OO 언어 (Java/C#/Smalltalk 류) 도메인 모델 | 모든 getter/setter heavy 클래스가 anemic 이라는 뜻은 아님 — Transaction Script 패턴 자체는 별도 trade-off 결정 |
| FOWLER-ANEMIC-C2 | Anemic model 은 절차적 (procedural) 스타일 설계와 동등하다 | [§Critique] "The anemic domain model is really just a procedural style design" | engineering-blog |
OO 설계 평가 | "절차적이면 항상 나쁘다" 의 증거는 아님 — Fowler 자신이 Transaction Script 도 별도 valid pattern 으로 분류 |
| FOWLER-ANEMIC-C3 | Anemic model 은 domain model 의 비용(O/R 매핑 등)을 모두 지불하면서 이득은 못 얻는 구조 | [§Cost] "they incur all of the costs of a domain model, without yielding any of the benefits" + [§Cost] "The primary cost is the awkwardness of mapping to a database, which typically results in a whole layer of O/R mapping" | engineering-blog |
JPA/Hibernate 등 O/R 매핑 사용하는 프로젝트 | "O/R 매핑이 무조건 비용" 이라는 일반화 아님 — 글 자체가 domain model + O/R 매핑 비교 맥락 |
| FOWLER-ANEMIC-C4 | Anemic 구조의 귀결은 Transaction Scripts 가 되어 domain model 의 장점을 잃는다 | [§Consequence] "you essentially end up with Transaction Scripts, and thus lose the advantages that the domain model can bring" | engineering-blog |
"domain model 을 채택했다고 표방하는" 코드베이스 | Transaction Script 자체가 부적절하다는 뜻은 아님 — Fowler 의 PoEAA 에서 별도 valid pattern |
| FOWLER-ANEMIC-C5 | Domain object 에 위치해야 할 로직 = validations + calculations + business rules | [§Domain logic] "The logic that should be in a domain object is domain logic - validations, calculations, business rules" | engineering-blog |
OO 도메인 모델 책임 분배 | 로깅 / 트랜잭션 경계 / 외부 IO 가 domain 에 와도 된다는 뜻은 아님 (Fowler 가 별도 application/infrastructure layer 분리 권고) |
| FOWLER-ANEMIC-C6 | Eric Evans (DDD) 는 "behavior 를 적절한 객체에 fit 시키는 것을 너무 빨리 포기하고 절차적 프로그래밍으로 점진 회귀하는 것" 을 가장 흔한 실수로 지목 | [§Eric Evans 인용] "the more common mistake is to give up too easily on fitting the behavior into an appropriate object, gradually slipping toward procedural programming." | engineering-blog (Fowler 의 Evans 인용) |
DDD 채택 프로젝트의 회귀 패턴 진단 | Evans 원전 (DDD 책) 의 정확한 페이지/문단을 본 자료가 명시하지 않음 — Evans 원전 직접 확인 별도 필요 |
Usage Boundaries / 적용 경계
- 이 자료가 직접 증명하는 것:
FOWLER-ANEMIC-C1~C5: Fowler 가 "Anemic" 을 anti-pattern 으로 명명하고 그 비용/귀결을 진단한 본인 글의 정확한 wordingFOWLER-ANEMIC-C6: Fowler 가 Evans 의 입장을 어떻게 요약했는지 (Evans 의 원전 자체 아님)
- 이 자료가 증명하지 않는 것:
- Anemic 회피가 "공식 표준 best practice" 라는 정당화 — Fowler bliki 는 본인 의견 글이며 공식 spec/RFC/벤더 doc 아님 (Strength =
engineering-blog) - ca-tmpl 의 구체 결정 (domain logger ban / safe reason enum / package-private constructor) 의 이름과 메커니즘 — 본 글은 anti-pattern 진단까지만, 구체 구현은 Vernon IDDD 등 별도 자료 결합 필요
- JPA + Rich Model 의 ORM-friendly 패턴 (no-arg constructor 가시성 / mapper 위치) — Vernon raw/official-docs/domain-vaughn-vernon-aggregate-root 가 별도 근거
- Anemic 회피가 "공식 표준 best practice" 라는 정당화 — Fowler bliki 는 본인 의견 글이며 공식 spec/RFC/벤더 doc 아님 (Strength =
- 내 프로젝트에 적용하려면 추가 확인이 필요한 것:
- ArchUnit 룰로 "domain method 가 비어있으면 경고" 같은 정량 임계 (몇 줄 이상이면 OK?) — 본 자료 범위 밖
- "logger 금지" 가 본 글에서 직접 도출되는지 — 본 글에서는 "domain logic = validation/calculation/business rule" 만 명시 (transport/logger 언급 없음)
- 한국 백엔드 현장에서 Spring 튜토리얼 default 가 anemic 이라는 관찰 (메모 항목) — 본 글로 증명 불가, 별도 ingest 필요
메모 / Notes (내 프로젝트 해석 — 자료 직접 인용 아님)
- ca-tmpl과의 매핑:
- rich model 측 (ca-tmpl 채택): invariant가 constructor/value object에 위치. mutation은 aggregate root method 호출만. domain exception이 사유를 표현.
- anemic model 측 (ca-tmpl 거부): domain class는 getter/setter만, 모든 logic이
*Service에 위치. ca-tmpl의 "domain logger ban" + "domain exception safe reason"이 anemic을 자연스럽게 거부함 (서비스 측 logger로 다 위임하면 reason enum이 무의미).
- 한국 백엔드 현장 관찰 (memo, ca-tmpl과 직접 무관):
- 우아한형제들 기술블로그 "DDD Aggregate" 시리즈(2020-2022)는 Vernon 라인의 Rich Model 권장.
- Spring 기본 튜토리얼은 종종 anemic 예시 (
@Entity+ setter +@Service). ca-tmpl은 이 default를 거부.
- 트레이드오프:
- rich model은 ORM(JPA)와 마찰: JPA가 reflection으로 객체 생성 → no-arg constructor 필요 → ca-tmpl의 "package-private/protected" 결정으로 해결.
- rich model은 DTO/Response 변환 layer가 반드시 필요. ca-tmpl의 "domain-to-response direct exposure forbidden" 결정과 일치.
- 출처 신뢰도: Fowler bliki는 공식 spec이 아니지만 OO/DDD 영역에서 reference standard로 취급되는 글. Strength =
engineering-blog(개인 블로그/bliki 형식이므로official-vendor-doc으로 격상 금지).
관련 ca-tmpl branch / contract
- 적용 branch-note:
- canonical contract 섹션:
- raw/project-notes/ca-skeleton-operational-contract#19. Domain Application Readiness Contract
- 대안 그룹: Group G-J — Privacy / File / Domain Modeling (domain modeling)
- 본 source의 위치: ca-tmpl reference standard — Fowler "Anemic Domain Model" anti-pattern
Related / 관련
- 같은 주제 다른 official-doc:
- raw/official-docs/domain-vaughn-vernon-aggregate-root (Vernon IDDD / Effective Aggregate Design)
- 인용하는 branch:
- 인용하는 wiki: (미작성)