--- 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: (미작성)