Files
llm-wiki/raw/official-docs/domain-fowler-anemic-vs-rich-model.md
T

115 lines
10 KiB
Markdown

---
title: Martin Fowler — Anemic Domain Model (anti-pattern)
source_type: official-doc
url: https://martinfowler.com/bliki/AnemicDomainModel.html
archive_url: https://web.archive.org/web/2024/https://martinfowler.com/bliki/AnemicDomainModel.html
status: raw
confidence: high
tags: [domain, ddd, anemic-model, rich-model, fowler, ca-skeleton]
related_branches: [feature-domain-modeling-guardrails, feature-architecture-enforcement-rules, feature-skeleton-package-blueprint-contract, feature-domain-feature-onboarding-contract]
related_projects: [ca-skeleton-operational-contract]
created: 2026-05-22
last_reviewed: 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 으로 명명하고 그 비용/귀결을 진단한 본인 글의 정확한 wording
- `FOWLER-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]] 가 별도 근거
- **내 프로젝트에 적용하려면 추가 확인이 필요한 것**:
- 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:
- [[raw/branch-notes/feature-domain-modeling-guardrails]]
- 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:
- [[raw/branch-notes/feature-domain-modeling-guardrails]]
- [[raw/branch-notes/feature-architecture-enforcement-rules]]
- 인용하는 wiki: (미작성)