오브젝트 실전 강의 교재¶
부록 C — 동적인 협력, 정적인 코드¶
원서: 조영호 『오브젝트』 대상: Java/Spring 백엔드 입문~중급 수강생 형식: 개념 → 비유 → 예시 → 핵심 교훈 → 함정 → 체크리스트 → 퀴즈(정답 분리)
0. 이 장을 시작하기 전에¶
0.1 학습 목표¶
- 동적 모델 (런타임 객체 협력) vs 정적 코드 (클래스·메서드) 의 차이.
- "행동이 코드를 결정 " — 협력을 먼저 그리고 코드는 그것을 표현.
- 도메인 모델·분석 모델·설계 모델·구현 모델 의 4 모델 관계.
- 오브젝트 책 전체의 마지막 통찰.
0.2 큰 그림 — 4 모델의 관계¶
[ 도메인 (실세계) ]
↓
[ 분석 모델 ] 도메인 전문가의 개념 + 비즈니스 규칙
↓
[ 설계 모델 ] 개발자의 해석 → 클래스·인터페이스·협력
↓
[ 구현 모델 ] 실제 코드
↓
[ 동적 협력 ] 런타임 객체 메시지 흐름
비유 — "건축"
새 도시를 짓는다고 해 봅시다. 건축가는 먼저 도시 전체를 살펴보고 스케치를 그리고, 그 스케치를 설계도로 다듬은 뒤, 설계도를 따라 건물을 시공합니다. 시공이 끝나면 그 안에서 사람들이 오가는 동선이 생깁니다. 그런데 동선은 시공이 끝난 다음에 저절로 정해지는 것이 아닙니다. 사람들이 어떻게 움직일지를 먼저 정하고, 그 동선이 거꾸로 설계와 시공을 이끕니다.
객체지향도 같은 순서입니다. 실세계 도메인이 도시에, 분석 모델이 건축가의 스케치에, 설계 모델이 설계도에, 구현 모델이 시공에, 런타임의 동적 협력이 사람들의 동선에 해당합니다. 코드를 다 짜야 협력이 생기는 것이 아니라, 객체들이 주고받을 협력을 먼저 정하고 그 협력이 코드를 이끌어야 합니다.
0.3 현업에서 왜 중요한가¶
- 오브젝트 책 전체 (1~15장) 의 마지막 통찰 — 코드 정적 구조가 본질 X, 동적 협력이 본질.
- DDD 의 Ubiquitous Language 와 직결 — 4 모델이 한 언어 공유.
- "왜 도메인 모델이 코드와 어긋나는가" 의 진단.
1. 동적 모델과 정적 모델¶
1.1 행동이 코드를 결정한다¶
객체 협력 (동적) 이 먼저, 클래스·메서드 (정적) 는 그것을 표현.
거꾸로 사고하는 함정¶
사례 — 영화 예매¶
[ 잘못된 사고 ] [ 올바른 사고 ]
"Movie 가 있어야" "예매 시나리오:"
"Movie.title·fee·..." " 사용자 → Screening.reserve()"
"Movie.getFee()" " Screening → Movie.calculateFee()"
"Service 가 호출" " Movie → DiscountPolicy.calculate()"
↓
"이 협력에 필요한 객체 + 메시지가 도출"
↓
"Movie·Screening·DiscountPolicy + calculateFee/reserve"
→ 4·5장 책임 주도 설계의 핵심.
1.2 변경을 고려하라¶
코드의 정적 구조 = 시간이 지나며 진화. 동적 협력이 안정적 이면 정적 코드 변경 자유.
안정적 동적 협력의 특징¶
- 메시지 흐름이 도메인 본질을 반영.
- 객체 책임이 변경 이유와 일치 (SRP).
- 협력 인터페이스가 추상 (구체 변경 자유).
→ 코드는 변해도 협력은 안정.
불안정 협력의 신호¶
- 새 기능 추가 시 협력 흐름 자체가 바뀜.
- 객체 책임이 자주 재할당.
- 메시지 시그니처가 자주 변경.
→ 도메인 분석 부족 또는 설계 미숙 신호.
2. 도메인 모델과 구현¶
2.1 도메인 모델에 관하여¶
도메인 모델 = 비즈니스 문제 영역의 개념을 객체로 표현. 코드 이전의 사고 모델.
도메인 모델의 요소: - 도메인 객체 (Customer·Order·Product). - 객체 협력 (Order 가 Customer 에게 결제 요청). - 비즈니스 규칙 (재고 부족 시 주문 거부). - 불변식 (잔액은 음수 X).
2.2 몬스터 설계하기 — 책 사례¶
게임의 몬스터를 어떻게 설계할까?
잘못된 시작 — 데이터 중심¶
올바른 시작 — 행동 중심¶
1. 협력 시나리오:
- "플레이어가 몬스터 공격 → 몬스터가 데미지 받음"
- "몬스터가 hp 0 → 몬스터 죽음 → 아이템 드롭"
- "몬스터가 플레이어 공격 → 플레이어가 데미지 받음"
2. 책임 식별:
- Monster.takeDamage(amount)
- Monster.attack(target)
- Monster.isDead()
- Monster.drop() // 죽으면 아이템
3. 필요 데이터 (행동에 필요한 것만):
- hp (takeDamage·isDead 에 필요)
- attackPower (attack 에 필요)
- dropTable (drop 에 필요)
→ 데이터 (필드) 가 행동의 결과로 도출.
2.3 행동과 변경을 고려한 도메인 모델¶
새 몬스터 종류 추가¶
- 데이터 중심: Monster 의
type필드 + switch 분기 → 산탄총 수술. - 책임 중심:
Monster추상 +Dragon·Goblin·Slime자식 → 다형성, OCP.
새 행동 추가 (예: 도망)¶
- 데이터 중심: 모든 Monster 자식에
flee()추가 → 부담. - 책임 중심:
FleeingBehavior정책 객체 + 합성 → 새 정책 1개.
→ 변경을 견디는 도메인 모델 = 책임 주도 + 합성 + 다형성의 종합.
2.4 분석 모델·설계 모델·구현 모델¶
4 모델의 차이¶
| 모델 | 누가 만드는가 | 언어 | 도구 |
|---|---|---|---|
| 도메인 | 도메인 전문가 | 비즈니스 용어 | 인터뷰·문서 |
| 분석 모델 | 도메인 전문가 + 분석가 | 비즈니스 개념 + 관계 | UML·다이어그램 |
| 설계 모델 | 개발자 | 클래스·인터페이스·협력 | UML 클래스 다이어그램 |
| 구현 모델 | 개발자 | 코드 | IDE |
일관성의 중요성¶
4 모델이 같은 개념·같은 이름·같은 협력 을 공유해야:
- 도메인 전문가가 "주문 (Order) 의 결제 (pay) 가 실패하면" 이라고 말함.
- 분석 모델에 Order.pay() 가 있음.
- 설계 모델에 Order.pay() 메서드.
- 구현 모델 코드에 order.pay() 메서드.
→ 같은 이름이 4 모델 모두에 흐름 = DDD 의 Ubiquitous Language (편재 언어).
일관성 깨질 때¶
→ 도메인 전문가가 코드 못 읽고, 개발자가 도메인 용어 못 씀. 번역 비용 폭증 + 버그 단골.
2.5 도메인 모델 표현 사례 — DDD Aggregate¶
// 도메인 전문가 언어 그대로
public class Order {
private OrderId id;
private List<OrderItem> items;
private OrderStatus status;
public void pay(Payment payment) { // ← 도메인 용어
if (status != PENDING) throw new IllegalStateException();
// 비즈니스 규칙
status = PAID;
registerEvent(new OrderPaidEvent(id));
}
public void cancel() { ... } // ← 도메인 용어
public void ship(Carrier carrier) { ... }
}
→ 도메인 전문가가 코드 (메서드 이름만이라도) 를 읽을 수 있음. DDD 의 Ubiquitous Language.
3. 책 전체의 마치며¶
핵심 메시지 정리 (1~15장 + 부록)¶
- 객체지향의 본질 = 객체 협력 (1·2·7·12장).
- 메시지가 객체를 결정 — 협력 → 책임 → 객체 (3·5·6장).
- 데이터 중심 X → 책임 중심 (4·5장).
- 추상에 의존 — OCP·DIP (8·9장).
- 합성 > 상속 — Stack·핸드폰 과금 (10·11장).
- 다형성 + LSP = 진짜 다형성 (12·13장).
- 일관된 협력 → 디자인 패턴 → 프레임워크 (14·15장).
- 계약 (사전·사후·불변) 이 LSP 의 기반 (부록 A).
- 타입 계층 표현 = 인터페이스 + 추상 클래스 + 합성 + sealed (부록 B).
- 동적 협력 먼저, 정적 코드 나중 + 4 모델 일관성 (부록 C).
다른 4권과의 연결¶
- Effective Java (Bloch) — Java 매일의 권고 90개. 오브젝트 원칙의 메서드·필드 단위.
- 리팩터링 (Fowler) — 이미 짠 코드를 오브젝트 원칙으로 개선.
- Clean Code (Martin) — 줄·이름·함수 단위 가독성.
- TDD (Beck) — 테스트가 오브젝트 원칙을 끌어내는 도구.
→ 5권이 자연스럽게 한 세트. → entity-object 안 5권 오각형 비교.
다음 깊이¶
- Domain-Driven Design (Evans) — 도메인 모델링 + Ubiquitous Language + Aggregate.
- Implementing Domain-Driven Design (Vernon) — DDD 실전 가이드.
- Patterns of Enterprise Application Architecture (Fowler) — 큰 시스템 패턴.
→ 오브젝트 가 OO 설계의 기반, DDD 가 엔터프라이즈 도메인 모델의 다음 단계.
핵심 교훈¶
- 동적 협력 먼저, 정적 코드 나중 — 코드 그리기 전에 협력 시나리오.
- 행동이 코드를 결정 — 데이터·필드는 행동의 결과.
- 변경에 강한 도메인 모델 = 책임 주도 + 합성 + 다형성.
- 4 모델 일관성 — 도메인·분석·설계·구현이 같은 언어 (Ubiquitous Language).
- 불일치는 번역 비용 + 버그 — 도메인 전문가가 코드 못 읽으면 위험 신호.
함정 / 주의¶
- 코드 먼저 그리고 협력 발견 = 빈혈 도메인 모델로 직행.
- 분석/설계/구현 모델 분리 가 도그마가 되면 문서 폭증 + 코드 동기화 비용.
- Ubiquitous Language 도그마 — 너무 엄격하면 도메인 변화에 코드 못 따라감.
- 거대 도메인 모델 = 모든 도메인을 한 모델에 — Bounded Context 분리 검토 (DDD).
체크리스트¶
- 새 기능 설계 시 협력 시나리오 먼저 그리는가
- 도메인 메서드 이름이 도메인 전문가 용어와 일치하는가
- 도메인 객체가 행동을 가졌는가 (빈혈 모델 X)
- 4 모델 (도메인·분석·설계·구현) 이 같은 언어 사용하는가
- 큰 도메인이면 Bounded Context 분리 검토
퀴즈¶
- 동적 모델과 정적 모델 의 차이는?
- "행동이 코드를 결정" 의 실천적 의미?
- 4 모델 일관성 이 왜 중요한가?
- Ubiquitous Language 가 깨질 때 무엇이 어려워지는가?
- 오브젝트 책 전체의 한 줄 메시지를 부록 C 관점에서?
정답·해설¶
- 동적 모델 = 런타임 객체 메시지 흐름 (협력). 정적 모델 = 클래스·메서드 (코드 구조). 동적이 본질 — 객체지향의 행동 측면. 정적은 그것을 표현하는 도구.
- 클래스·필드부터 그리지 말고 협력 시나리오부터 그려라. 협력에 필요한 책임 → 그 책임 가진 객체 → 책임에 필요한 데이터. 데이터는 행동의 결과 (4·5장 RDD).
- 번역 비용 + 버그 감소. 도메인 전문가·분석가·개발자가 같은 언어를 쓰면 요구사항 → 코드 흐름이 매끄러움. 다른 언어면 매번 번역 + 오해 + 실수.
- 도메인 전문가가 코드 못 읽음 + 개발자가 도메인 용어 못 씀 → 매번 통역 필요, 요구사항 변경 시 어디를 어떻게 바꿀지 추적 어려움, 버그 단골.
- 객체지향은 정적 클래스 묶음이 아니라 동적 객체 협력이다. 그 협력이 도메인 본질을 반영하고, 4 모델이 일관 언어를 공유할 때 비로소 살아있는 도메인 모델. 책 전체가 이를 다양한 도구 (책임 주도·합성·다형성·패턴) 로 가리킴.
책 전체 완결¶
부록 C 가 오브젝트 의 마지막. 1~15장 + 부록 A·B·C 의 모든 통찰이 한 문장으로 모임:
객체지향의 본질은 클래스가 아니라 객체 협력이다.
이 협력을 잘하기 위한 도구 (책임 주도·추상 의존·합성·다형성·LSP·패턴·계약·일관성) 가 책 전체. 다른 4권 (Effective Java·리팩터링·Clean Code·TDD) 이 같은 원칙을 다른 단위 (메서드·1단계·줄·사이클) 로 보완.
→ entity-object / src-object-lecture / entity-effective-java / entity-refactoring / entity-clean-code / entity-tdd.