SlideShare a Scribd company logo
DOMAIN MODEL 패턴과 JPA의 조화
객체지향적인 도메인 레이어 구축하기
조영호
Eternity’s Chit-Chat(http://aeternum.egloos.com)
2. 임피던스 불일치Impedance Mismatch
목차
3. JPAJava Persistence API
1. 온라인 영화 예매 시스템 도메인
4. 결롞
1. 온라인 영화 예매 시스템 도메인
4 / 객체지향적인 도메인 레이어 구축하기
Domain Concept - 영화
Movie
5 / 객체지향적인 도메인 레이어 구축하기
2011-10-18 09:30 조조
2011-10-21 20:30 5회
2011-12-01 14:20 4회
Domain Concept - 상영
Showing
6 / 객체지향적인 도메인 레이어 구축하기
Domain Concept – 할인 정책
Amount Discount
Percent Discount
8,000 - 800 = 7,200
8,000 – (8,000 * 0.1) = 7,200
Discount
7 / 객체지향적인 도메인 레이어 구축하기
Domain Concept – 할인 규칙
Sequence Rule
Time Rule
조조 상영인 경우
월요일 10:00 ~ 12:00 상영인 경우
화요일 18:00 ~ 21:00 상영인 경우
10회 상영인 경우
Rule
8 / 객체지향적인 도메인 레이어 구축하기
Domain Concept –할인 정책 + 할인 규칙
Movie Discount Rule
1 0..1 1 1..*
10회 상영인 경우
도가니
8000원
Amount DC
800원
조조 상영인 경우
월요일 10:00 ~ 12:00 상영인 경우
화요일 18:00 ~ 21:00 상영인 경우
9 / 객체지향적인 도메인 레이어 구축하기
Domain Concept –예매
도가니
2011년 10월 18일 (목)
7회 6:00(오후) – 8:00(오후)
2명
16,000원
14,400원
제 목
상영 정보
인 원
정 가
결재 금액
Reservation
10 / 객체지향적인 도메인 레이어 구축하기
Domain Model
Movie Discount Rule
1 0..1 1 1..*
1
0..*
1 0..*
Showing Reservation
11 / 객체지향적인 도메인 레이어 구축하기
영화 예매 책임 수행을 위한 협력의 설계
 후보 객체Candidate, 책임Responsibility, 협력Collaboration 식별
Showing
상영 정보를 알고 있다
예매 정보를 생성한다
Movie
Movie
영화 정보를 알고 있다
가격을 계산한다
Discount
Strategy
DiscountStrategy
할인율 정책을 알고 있다
할인된 가격을 계산한다
Rule
Rule
할인 정책을 알고 있다
할인 여부를 판단한다
Showing
12 / 객체지향적인 도메인 레이어 구축하기
도메인 레이어 객체 구현
Customer
Showing
reserve(customer, count):Reservation
{abstract}
Rule
isStatisfiedBy(showing):boolean
Reservation
Amount
Strategy
Percent
Strategy
NonDiscount
Strategy
Sequence
Rule
TimeOfDay
Rule
{abstract}
DiscountStrategy
calculateFee(showing):Money
Movie
calculateFee(showing):Money
<<create>>
User Interface
Service
Domain
Infrastructure
13 / 객체지향적인 도메인 레이어 구축하기
Domain Model
Movie Discount Rule
1 0..1 1 1..*
1
0..*
1 0..*
Showing Reservation
14 / 객체지향적인 도메인 레이어 구축하기
Movie Discount Rule
1 0..1 1 1..*
1
0..*
1 0..*
Showing Reservation
Domain Layer Design & Domain Model
Customer
Showing
reserve(customer, count):Reservation
{abstract}
Rule
isStatisfiedBy(showing):boolean
Reservation
Amount
Strategy
Percent
Strategy
NonDiscount
Strategy
Sequence
Rule
TimeOfDay
Rule
{abstract}
DiscountStrategy
calculateFee(showing):Money
Movie
calculateFee(showing):Money
<<create>>
15 / 객체지향적인 도메인 레이어 구축하기
아키텍처 패턴
Domain Model
User Interface
Service
Domain
Infrastructure
2. 임피던스 불일치Impedance Mismatch
17 / 객체지향적인 도메인 레이어 구축하기
임피던스 불일치Impedance Mismatch
18 / 객체지향적인 도메인 레이어 구축하기
객체-관계 임피던스 불일치
 객체 모델과 DB 스키마 간의 불일치
 객체 패러다임Object Paradigm과 관계 패러다임Relational Paradigm 간의 불일치
RULE
ID
DISCOUNT_ID(FK)
POSITION
RULE_TYPE
DAY_OF_WEEK
START_TIME
END_TUME
SEQUENCE
DISCOUNT
MOVIE_ID(FK)
DISCOUNT_TYPE
FEE_AMOUNT
FEE_CURRENCY
PERCENT
Rule
Amount
Strategy
Percent
Strategy
NonDiscount
Strategy
Sequence
Rule
TimeOfDay
Rule
DiscountStrategy
19 / 객체지향적인 도메인 레이어 구축하기
캡슐화 경계Encapsulation Boundary의 불일치
식별자Identity의 불일치
다형성Polymorphism의 불일치
연관 관계Association와 외래키Foreign Key의 불일치
구성 요소 크기Granularity의 불일치
임피던스 불일치 유형
20 / 객체지향적인 도메인 레이어 구축하기
캡슐화 경계Encapsulation Boundary의 불일치
식별자Identity의 불일치
다형성Polymorphism의 불일치
연관 관계Association와 외래키Foreign Key의 불일치
구성 요소 크기Granularity의 불일치
임피던스 불일치 유형
21 / 객체지향적인 도메인 레이어 구축하기
구성 요소 크기Granularity의 불일치Mismatch
8,000원
요금
135분
시간
하나와 앨리스
제목
Movie
MOVIE
ID(PK)
TITLE
RUNNING_TIME
FEE_AMOUNT
FEE_CURRENCY
<<value object>>
Duration
quantity
<<value object>>
Money
amount
currency
<<entity>>
Movie
title
calculateFee(showing):Money
running
Time
fee
22 / 객체지향적인 도메인 레이어 구축하기
Value Object
Entity <<value object>>
Duration
quantity
<<value object>>
Money
amount
currency
<<entity>>
Movie
title
calculateFee(showing):Money
running
Time
fee
Identity Value
Entity & Value Object
23 / 객체지향적인 도메인 레이어 구축하기
Movie
영화 정보를 알고 있다
가격을 계산한다
Money
금액과 환율을 알고 있다
금액을 +,-,*,/한다
Duration
기간을 알고 있다.
기간의 합, 차를 계산한다
책임의 재사용
24 / 객체지향적인 도메인 레이어 구축하기
코드 중복Code DuplicationProblem
Movie
id
title
runningTime
fee
feeCurrency
calculateFee()
Reservation
id
customerId
showingId
amount
acmointCurrency
audienceCount
getFee()
MOVIE
ID(PK)
TITLE
RUNNING_TIME
FEE_AMOUNT
FEE_CURRENCY
RESERVATION
ID(PK)
CUSTOMER_ID(FK)
SHOWING_ID(FK)
FEE_AMOUNT
FEE_CURRENCY
AUDIENCE_COUNT
class Movie {
long plus(long fee, Currency currency) {
if (this.feeCurrency.equals(currency) {
return this.fee + fee;
}
throw new IllegalArgumentException();
}
}
class Reservation {
long add(long amount, Currency currency) {
if (this.amountCurrency.equals(currency) {
return this.amount + fee;
}
throw new IllegalArgumentException();
}
}
25 / 객체지향적인 도메인 레이어 구축하기
캡슐화 경계Encapsulation Boundary의 불일치
식별자Identity의 불일치
다형성Polymorphism의 불일치
연관 관계Association와 외래키Foreign Key의 불일치
구성 요소 크기Granularity의 불일치
임피던스 불일치 유형
26 / 객체지향적인 도메인 레이어 구축하기
데이터베이스 식별자Database IdentityMismatch
TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY
MOVIE
시간을 달리는 소녀 95 8,000 KRW
시간을 달리는 소녀 95 8,000 KRW
ID
1
2
 테이블 주키Primary Key
8,000원
요금
95분
시간
시간을
달리는 소녀
제목
8,000원
요금
95분
시간
시간을
달리는 소녀
제목
27 / 객체지향적인 도메인 레이어 구축하기
객체 식별자Object Identity
8,000원
요금
95분
시간
시간을
달리는 소녀
제목
8,000원
요금
95분
시간
시간을
달리는 소녀
제목
movie1 : Movie
title = ‚시간을 달리는 소녀‛
runningTime = 95
Fee = 8000
address 1
movie2 : Movie
title = ‚시간을 달리는 소녀‛
runningTime = 95
Fee = 8000
address 2
 Java == 연산자
28 / 객체지향적인 도메인 레이어 구축하기
데이터베이스-객체 식별자 불일치Identity Mismatch
TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY
MOVIE
시간을 달리는 소녀 95 8,000 KRW
시간을 달리는 소녀 95 8,000 KRW
ID
1
2
movie1 : Movie
title = ‚시간을 달리는 소녀‛
runningTime = 95
Fee = 8000
movie2 : Movie
title = ‚시간을 달리는 소녀‛
runningTime = 95
Fee = 8000
Problem
29 / 객체지향적인 도메인 레이어 구축하기
캡슐화 경계Encapsulation Boundary의 불일치
식별자Identity의 불일치
다형성Polymorphism의 불일치
연관 관계Association와 외래키Foreign Key의 불일치
구성 요소 크기Granularity의 불일치
임피던스 불일치 유형
30 / 객체지향적인 도메인 레이어 구축하기
다형성PolymorphismMismatch
Movie
Amount Discount 800원
Percent Discount 10%
No Discount 0원(%)
Discount
Movie
calculateFee(showing)
{abstract}
DiscountStrategy
registerDate
calculateFee(showing)
Percent
DiscountStrategy
percent
Amount
DiscountStrategy
discountAmount
Non
DiscountStrategy
public class Movie {
private DiscountStrategy discountStrategy;
public Money calculateFee(Showing showing) {
return discountStrategy.calculateFee(showing);
}
}
31 / 객체지향적인 도메인 레이어 구축하기
젃차적인 조건 분기Conditional BranchProblem
public class Movie {
private DiscountStrategy discountStrategy;
public Money calculateFee(Showing showing) {
return discountStrategy.calculateFee(showing);
}
}
public class ReservationService {
public Money calculateFee(Movie movie,
DiscountStrategy discountStrategy) {
if (discountStrategy.isAmountType()) {
...
} else if (discountStrategy.isPercentType()) {
...
} else {
...
}
...
}
}
Movie
Amount Discount 800원
Percent Discount 10%
No Discount 0원(%)
Discount
Movie
id
title
runningTime
fee
feeCurrency
calculateFee()
DiscountStrategy
movieId
discountType
amount
percent
registerDate
calculateFee()
32 / 객체지향적인 도메인 레이어 구축하기
캡슐화 경계Encapsulation Boundary의 불일치
식별자Identity의 불일치
다형성Polymorphism의 불일치
연관 관계Association와 외래키Foreign Key의 불일치
구성 요소 크기Granularity의 불일치
임피던스 불일치 유형
33 / 객체지향적인 도메인 레이어 구축하기
데이터베이스 외래키Foreign KeyMismatch
Movie Showing
1회 10/18 10:00
2회 10/18 12:30
3회 10/18 15:00
4회 10/18 17:30
MOVIE SHOWING
ID(PK)
SEQUENCE
SHOWING_TIME
ID(PK)
TITLE
RUNNING_TIME
FEE_AMOUNT
FEE_CURRENCY
MOVIE_ID(FK)
TITLE
하나와 앨리스
MOVIE
ID SEQUENCE SHOWING_TIME
1 7 2010-12-23 18:00
SHOWING
ID
1
MOVIE_ID
1
34 / 객체지향적인 도메인 레이어 구축하기
테이블 외래키Foreign Key - 양방향BiDirectional
MOVIE SHOWING
ID(PK)
MOVIE_ID(FK)
SEQUENCE
SHOWING_TIME
ID(PK)
TITLE
RUNNING_TIME
FEE_AMOUNT
FEE_CURRENCY
SELECT *
FROM MOVIE as m LEFT JOIN SHOWING as s
ON m.ID = s.MOVIE_ID
35 / 객체지향적인 도메인 레이어 구축하기
객체 연관관계Association – 단방향UniDirectional
Showing
reserve(customer, count)
Movie
calculateFee(showing) *1
Showing
reserve(customer, count)
Movie
calculateFee(showing) *1
Showing
reserve(customer, count)
Movie
calculateFee(showing) *1
showing.getMovie();
movie.getShowings();
movie.getShowings();
showing.getMovie();
MOVIE SHOWING
ID(PK)
MOVIE_ID(FK)
SEQUENCE
SHOWING_TIME
ID(PK)
TITLE
RUNNING_TIME
FEE_AMOUNT
FEE_CURRENCY
36 / 객체지향적인 도메인 레이어 구축하기
Showing
상영 정보를 알고 있다
예매 정보를 생성한다
Movie
Movie
영화 정보를 알고 있다
가격을 계산한다
Discount
Strategy
DiscountStrategy
할인율 정책을 알고 있다
할인된 가격을 계산한다
Rule
Showing
reserve()
Movie
calculateFee()
*
1
DiscountStrategy
calculateFee()
1
0..1
public class Showing {
private Movie movie;
public Money calculateFee() {
return movie.calculateFee(this);
}
...
}
public class Movie {
private DiscountStrategy discountStrategy;
public Money calculateFee(Showing showing) {
return discountStrategy.calculateFee(showing);
}
...
}
 연관 관계는 책임 분배와 협력을 위한 핵심 메커니즘
객체 협력Collaboration을 통한 구현
37 / 객체지향적인 도메인 레이어 구축하기
Data + Process = 젃차적인Procedural 프로그래밍Problem
public class Showing {
private Movie movie;
public Money calculateFee() {
return movie.calculateFee(this);
}
...
}
MOVIE SHOWING
ID(PK)
MOVIE_ID(FK)
SEQUENCE
SHOWING_TIME
ID(PK)
TITLE
RUNNING_TIME
FEE_AMOUNT
FEE_CURRENCY
Movie
id
title
runningTime
fee
feeCurrency
Showing
id
movieId
title
sequence
showingTime
public class ReservationService {
public Reservation reserveShowing(int customerId, int showingId, int audienceCount) {
Showing showing = showingDAO.selectShowing(showingId);
Movie movie = movieDAO.selectMovie(showing.getMovieId());
long amount = calculateFee(movie.getFee(), showing, audienceCount);
...
}
private long calculateFee(long movieFee, Showing showing, int audientCount) {
...
}
}
Data
Process
ReservationService
reserveShowing()
38 / 객체지향적인 도메인 레이어 구축하기
캡슐화 경계Encapsulation Boundary의 불일치
식별자Identity의 불일치
다형성Polymorphism의 불일치
연관 관계Association와 외래키Foreign Key의 불일치
구성 요소 크기Granularity의 불일치
임피던스 불일치 유형
39 / 객체지향적인 도메인 레이어 구축하기
캡슐화EncapsulationMismatch
{abstract}
Rule
isStatisfiedBy(showing)
Sequence
Rule
TimeOfDay
Rule
Amount
Strategy
Percent
Strategy
NonDiscount
Strategy
{abstract}
DiscountStrategy
calculateFee(showing):Money
Showing
reserve(customer, count)
Movie
calculateFee(showing):Money
Hierarchical
Flat
40 / 객체지향적인 도메인 레이어 구축하기
할인 규칙 등록
Movie
calculateFee(showing)
Showing
reserve(customer, count) *1
{abstract}
DiscountStrategy
calculateFee(showing)1 0..1
{abstract}
Rule
calculateFee(showing)0..*1
제 목 무지개여싞
상영 시간 116분 요 금
할인 정책
AMOUNT
DISCOUNT 할인 금액
할인 규칙 SEQUENCE RULE
5회 7회할인 대상
8,000원
9,000원
1회 1회
41 / 객체지향적인 도메인 레이어 구축하기
할인 규칙 등록
Movie
calculateFee(showing)
Showing
reserve(customer, count) *1
{abstract}
DiscountStrategy
calculateFee(showing)1 0..1
{abstract}
Rule
calculateFee(showing)0..*1
제 목 무지개여싞
상영 시간 116분 요 금
할인 정책
AMOUNT
DISCOUNT 할인 금액
할인 규칙 SEQUENCE RULE
5회 7회할인 대상
8,000원
9,000원
1회 1회
Movie
Discount
Rule
캡슐화 경계Boundary
42 / 객체지향적인 도메인 레이어 구축하기
캡슐화 저해Problem
Flat
movie.setFee(8000);
movieDAO.save(movie);
DiscountStrategy strategy =
new AmountDiscountStrategy(9000);
discountStrategyDAO.save(strategy);
DiscountRule rule = new SequenceRule(1);
discountRuleDAO.save(rule);
불변식 위반Invariant Violation
DiscountRule rule = new SequenceRule(1);
discountRuleDAO.save(rule);
43 / 객체지향적인 도메인 레이어 구축하기
임피던스 불일치의 결과
public class Movie {
private Long id;
private String title;
public Long getId() {
return id;
}
public String getTitle() {
return title;
}
public class ReservationService {
public Money calculateFee(Movie movie,
DiscountStrategy strategy) {
if (strategy.isAmountType()) {
...
} else if (strategy.isPercentType()) {
...
} else {
...
}
...
}
public class ReservationService {
public Reservation reserveShowing(int customerId,
int showingId, int audienceCount) {
Showing showing = showingDAO.selectShowing(showingId);
Movie movie = movieDAO.selectMovie(showing.getMovieId());
long amount = calculateFee(movie.getFee(), showing, audienceCount);
 Anemic Domain Model & Fat Service Layer
Conclusion
44 / 객체지향적인 도메인 레이어 구축하기
Transaction Script
아키텍처 패턴
User Interface
Service
Domain
Infrastructure
3. JPAJava Persistence API
46 / 객체지향적인 도메인 레이어 구축하기
DATA MAPPER
 객체 모델과 DB 스키마 간의 독립성 유지
 도메인 객체는 DB에 대해 독립적
 ORMObject-Relational Mapper
RULE
ID
DISCOUNT_ID(FK)
POSITION
RULE_TYPE
DAY_OF_WEEK
START_TIME
END_TUME
SEQUENCE
Rule
SequenceRule TimeOfDayRule
RuleMapper
insert
update
delete
47 / 객체지향적인 도메인 레이어 구축하기
JPAJava Persistence API
RULE
ID
DISCOUNT_ID(FK)
POSITION
RULE_TYPE
DAY_OF_WEEK
START_TIME
END_TUME
SEQUENCE
Rule
SequenceRule TimeOfDayRule
Hibernate
EclipseLink
JPA
 Java ORM 표준 명세
 Annotation과 XML을 이용한 META DATA MAPPING 기능 제공
 Hibernate, EclipseLink
48 / 객체지향적인 도메인 레이어 구축하기
캡슐화 경계Encapsulation Boundary의 불일치
식별자Identity의 불일치
다형성Polymorphism의 불일치
연관 관계Association와 외래키Foreign Key의 불일치
구성 요소 크기Granularity의 불일치
임피던스 불일치 유형
49 / 객체지향적인 도메인 레이어 구축하기
구성 요소 크기Granularity의 불일치Mismatch
8,000원
요금
135분
시간
하나와 앨리스
제목
Movie
MOVIE
ID(PK)
TITLE
RUNNING_TIME
FEE_AMOUNT
FEE_CURRENCY
Value Object
Entity <<value object>>
Duration
quantity
<<value object>>
Money
amount
currency
<<entity>>
Movie
title
calculateFee(showing):Money
running
Time
fee
50 / 객체지향적인 도메인 레이어 구축하기
Solution @Embeddable
Value Object
Entity <<value object>>
Duration
quantity
<<value object>>
Money
amount
currency
<<entity>>
Movie
title
calculateFee(showing):Money
running
Time
fee
@Entity
@Table(name="MOVIE")
public class Movie {
private Duration runningTime;
private Money fee;
@Embeddable
public class Duration {
@Column(name="RUNNING_TIME", nullable=true)
private long quantity;
@Embeddable
public class Money {
@Column(name="FEE_AMOUNT", nullable=true)
private BigDecimal amount;
@Column(name="FEE_CURRENCY", nullable=true)
private Currency currency;
MOVIE
ID(PK)
TITLE
RUNNING_TIME
FEE_AMOUNT
FEE_CURRENCY
51 / 객체지향적인 도메인 레이어 구축하기
캡슐화 경계Encapsulation Boundary의 불일치
식별자Identity의 불일치
다형성Polymorphism의 불일치
연관 관계Association와 외래키Foreign Key의 불일치
구성 요소 크기Granularity의 불일치
임피던스 불일치 유형
52 / 객체지향적인 도메인 레이어 구축하기
식별자 불일치Identity MismatchMismatch
TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY
MOVIE
시간을 달리는 소녀 95 8,000 KRW
시간을 달리는 소녀 95 8,000 KRW
ID
1
2
movie1 : Movie
title = ‚시간을 달리는 소녀‛
runningTime = 95
Fee = 8000
movie2 : Movie
title = ‚시간을 달리는 소녀‛
runningTime = 95
Fee = 8000
53 / 객체지향적인 도메인 레이어 구축하기
영속 컨텍스트Persistence ContextSolution
UNIT OF WORK
User Interface
Service
Domain
Infrastructure
Begin
TX
Commit/
Rollback
IDENTITY
MAP
54 / 객체지향적인 도메인 레이어 구축하기
영화 엔티티Entity 조회
TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY
MOVIE
시간을 달리는 소녀 95 8,000 KRW
시간을 달리는 소녀 95 8,000 KRW
ID
1
2
movie1 : Movie
title = ‚시간을 달리는 소녀‛
runningTime = 95
Fee = 8000
movie2 : Movie
title = ‚시간을 달리는 소녀‛
runningTime = 95
Fee = 8000
55 / 객체지향적인 도메인 레이어 구축하기
영속 컨텍스트Persistence Context
UNIT OF WORK
User Interface
Service
Domain
Infrastructure
IDENTITY
MAP
Begin
TX
Commit/
Rollback
ID 1
movie1 : Movie
title = ‚시간을 달리는 소녀‛
runningTime = 95
Fee = 8000
ID 2
movie2 : Movie
title = ‚시간을 달리는 소녀‛
runningTime = 95
Fee = 8000
56 / 객체지향적인 도메인 레이어 구축하기
첫 번째 영화 엔티티 다시 조회
TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY
MOVIE
ID
시간을 달리는 소녀 95 8,000 KRW1
movie1 : Movie
title = ‚시간을 달리는 소녀‛
runningTime = 95
Fee = 8000
movie2 : Movie
title = ‚시간을 달리는 소녀‛
runningTime = 95
Fee = 8000
시간을 달리는 소녀 95 8,000 KRW2
57 / 객체지향적인 도메인 레이어 구축하기
영속 컨텍스트Persistence Context
UNIT OF WORK
User Interface
Service
Domain
Infrastructure
IDENTITY
MAP
Begin
TX
Commit/
Rollback
ID 1
movie1 : Movie
title = ‚시간을 달리는 소녀‛
runningTime = 95
Fee = 8000
ID 2
movie2 : Movie
title = ‚시간을 달리는 소녀‛
runningTime = 95
Fee = 8000
58 / 객체지향적인 도메인 레이어 구축하기
식별자 일관성 보장
TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY
MOVIE
ID
시간을 달리는 소녀 95 8,000 KRW1
movie1 : Movie
title = ‚시간을 달리는 소녀‛
runningTime = 95
Fee = 8000
movie2 : Movie
title = ‚시간을 달리는 소녀‛
runningTime = 95
Fee = 8000
시간을 달리는 소녀 95 8,000 KRW2
 데이터베이스 주키Primary Key와 객체 식별자Identity 간 일관성 유지
59 / 객체지향적인 도메인 레이어 구축하기
식별자 일관성 보장
movie1 = entityManager.load(Movie.class, 1);
movie2 = entityManager.load(Movie.class, 1);
assertSame(movie1, movie2);
60 / 객체지향적인 도메인 레이어 구축하기
캡슐화 경계Encapsulation Boundary의 불일치
식별자Identity의 불일치
다형성Polymorphism의 불일치
연관 관계Association와 외래키Foreign Key의 불일치
구성 요소 크기Granularity의 불일치
임피던스 불일치 유형
61 / 객체지향적인 도메인 레이어 구축하기
다형성PolymorphismMismatch
public class ReservationService {
public Money calculateFee(Movie movie,
DiscountStrategy discountStrategy) {
if (discountStrategy.isAmountType()) {
...
} else if (discountStrategy.isPercentType()) {
...
} else {
...
}
...
}
}
Movie
Amount Discount 800원
Percent Discount 10%
No Discount 0원(%)
Discount
Movie
calculateFee(showing)
{abstract}
DiscountStrategy
registerDate
calculateFee(showing)
Percent
DiscountStrategy
percent
Amount
DiscountStrategy
discountAmount
Non
DiscountStrategy
Movie
id
title
runningTime
fee
feeCurrency
calculateFee()
DiscountStrategy
movieId
discountType
amount
percent
registerDate
calculateFee()
62 / 객체지향적인 도메인 레이어 구축하기
상속 매핑Inheritance MappingSolution
{abstract}
DiscountStrategy
registerDate
calculateFee(showing)
Percent
DiscountStrategy
percent
Amount
DiscountStrategy
discountAmount
DISCOUNT
MOVIE_ID(FK)
DISCOUNT_TYPE
FEE_AMOUNT
FEE_CURRENCY
PERCENT
REGISTER_DATE
Single Table
Inheritance
AMOUNT_DISCOUNT
MOVIE_ID(FK)
FEE_AMOUNT
FEE_CURRENCY
REGISTER_DATE
PERCENT_DISCOUNT
MOVIE_ID(FK)
PERCENT
REGISTER_DATE
Concrete Class
Inheritance
Class Table
Inheritance
DISCOUNT
AMOUNT_DISCOUN
T
DISCOUNT_ID(FK)
FEE_AMOUNT
FEE_CURRENCY
PERCENT_DISCOUN
T
DISCOUNT_ID(FK)
PERCENT
MOVIE_ID(FK)
REGISTER_DATE
63 / 객체지향적인 도메인 레이어 구축하기
다형성을 통한 조건 분기 제거Solution
Movie
Amount Discount 800원
Percent Discount 10%
No Discount 0원(%)
Discount
Movie
calculateFee(showing)
{abstract}
DiscountStrategy
registerDate
calculateFee(showing)
Percent
DiscountStrategy
percent
Amount
DiscountStrategy
discountAmount
Non
DiscountStrategy
public class Movie {
private DiscountStrategy discountStrategy;
public Money calculateFee(Showing showing) {
return discountStrategy.calculateFee(showing);
}
}
64 / 객체지향적인 도메인 레이어 구축하기
캡슐화 경계Encapsulation Boundary의 불일치
식별자Identity의 불일치
다형성Polymorphism의 불일치
연관 관계Association와 외래키Foreign Key의 불일치
구성 요소 크기Granularity의 불일치
임피던스 불일치 유형
65 / 객체지향적인 도메인 레이어 구축하기
연관관계Association와 외래키Foreign KeyMismatch
Showing
reserve(customer, count)
Movie
calculateFee(showing) *1
Showing
reserve(customer, count)
Movie
calculateFee(showing) *1
Showing
reserve(customer, count)
Movie
calculateFee(showing) *1
showing.getMovie();
movie.getShowings();
movie.getShowings();
showing.getMovie();
MOVIE SHOWING
ID(PK)
MOVIE_ID(FK)
SEQUENCE
SHOWING_TIME
ID(PK)
TITLE
RUNNING_TIME
FEE_AMOUNT
FEE_CURRENCY
66 / 객체지향적인 도메인 레이어 구축하기
외래키 맵핑Foreign Key MappingSolution
MOVIE SHOWING
ID(PK)
MOVIE_ID(FK)
SEQUENCE
SHOWING_TIME
ID(PK)
TITLE
RUNNING_TIME
FEE_AMOUNT
FEE_CURRENCY
Showing
reserve(customer, count)
Movie
calculateFee(showing) *1
Foreign Key
Association
public class Showing {
@ManyToOne(optional=false)
@JoinColumn(name="MOVIE_ID")
private Movie movie;
}
public Money calculateFee() {
return movie.calculateFee(this);
}
67 / 객체지향적인 도메인 레이어 구축하기
캡슐화 경계Encapsulation Boundary의 불일치
식별자Identity의 불일치
다형성Polymorphism의 불일치
연관 관계Association와 외래키Foreign Key의 불일치
구성 요소 크기Granularity의 불일치
임피던스 불일치 유형
68 / 객체지향적인 도메인 레이어 구축하기
캡슐화EncapsulationMismatch
Flat
movie.setFee(8000);
movieDAO.save(movie);
DiscountStrategy strategy =
new AmountDiscountStrategy(9000);
discountStrategyDAO.save(strategy);
DiscountRule rule = new SequenceRule(1);
discountRuleDAO.save(rule);
불변식 위반Invariant Violation
DiscountRule rule = new SequenceRule(1);
discountRuleDAO.save(rule);
{abstract}
Rule
isStatisfiedBy(sho
wing)
Sequence
Rule
TimeOf
Day
Rule
Amount
Strategy
Percent
Strategy
NonDiscoun
t
Strategy
{abstract}
DiscountStrategy
calculateFee(showing):Mon
ey
Showing
reserve(customer, count)
Movie
calculateFee(showing):Money
Hierarchical
69 / 객체지향적인 도메인 레이어 구축하기
페치 젂략Fetch StrategySolution
 지연 페치Lazy Fetch
public class Movie {
@OneToOne(cascade=CascadeType.ALL, optional=true, fetch=FetchType.LAZY)
private DiscountStrategy discountStrategy;
public class DiscountStrategy {
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
@JoinColumn(name="DISCOUNTID")
private Set<Rule> rules = new HashSet<Rule>();
Showing
reserve(customer, count)
1
{abstract}
Rule
calculateFee(showing)0..*1
Movie
calculateFee(showing)*
{abstract}
DiscountStrategy
calculateFee(showing)1 0..1
70 / 객체지향적인 도메인 레이어 구축하기
페치 젂략Fetch StrategySolution
 선행 페치Eager Fetch
public class Movie {
@OneToOne(cascade=CascadeType.ALL, optional=true, fetch=FetchType.EAGER)
private DiscountStrategy discountStrategy;
public class DiscountStrategy {
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name="DISCOUNTID")
private Set<Rule> rules = new HashSet<Rule>();
Showing
reserve(customer, count)
Movie
calculateFee(showing)*1
{abstract}
DiscountStrategy
calculateFee(showing)1 0..1
{abstract}
Rule
calculateFee(showing)0..*1
71 / 객체지향적인 도메인 레이어 구축하기
 예기치 못한 변경으로부터 보호
 객체 그룹의 불변성 보장
{abstract}
Rule
isStatisfiedBy(showing)
Sequence
Rule
TimeOfDay
Rule
Amount
Strategy
Percent
Strategy
NonDiscount
Strategy
{abstract}
DiscountStrategy
calculateFee(showing):Money
Showing
reserve(customer, count)
Movie
calculateFee(showing):Money
Aggregate
Aggregate = 캡슐화 경계Encapsulation Boundary
Eager Fetch
Lazy Fetch
Solution
4. 결롞
73 / 객체지향적인 도메인 레이어 구축하기
DOMAIN MODEL PATTERN
 도메인을 구성하는 개념들을 따르는 도메인 레이어
 적젃한 책임의 분배와 협력을 통한 객체 지향적인 도메인 레이어
74 / 객체지향적인 도메인 레이어 구축하기
임피던스 불일치
 맹목적으로 테이블의 구조를 따르는 객체 구조
 젃차적인 TRANSACTION SCRIPT로 향하는 한 가지 이유
75 / 객체지향적인 도메인 레이어 구축하기
JPAJavaPersistece API
 임피던스 불일치를 해결할 수 있는 실용적인 솔루션
 풍부한 도메인 레이어Rich Domain Layer의 기반
76 / 객체지향적인 도메인 레이어 구축하기
Movie Discount Rule
1 0..1 1 1..*
1
0..*
1 0..*
Showing Reservation
Domain Model에 초점을 맞춰라
Customer
Showing
reserve(customer, count):Reservation
{abstract}
Rule
isStatisfiedBy(showing):boolean
Reservation
Amount
Strategy
Percent
Strategy
NonDiscount
Strategy
Sequence
Rule
TimeOfDay
Rule
{abstract}
DiscountStrategy
calculateFee(showing):Money
Movie
calculateFee(showing):Money
<<create>>
77 / 객체지향적인 도메인 레이어 구축하기
Data Model이 더 중요
78 / 객체지향적인 도메인 레이어 구축하기
Be Pragmatic
타협하라
데이터베이스가 하나의 객체 저장소로 보여진다면 매핑 도구의 기능과는 상관없이 데이터
모델과 객체 모델이 서로 갈라지게 해서는 안 된다. 일부 객체 관계의 풍부함을 희생해서
관계 모델에 밀접하게 한다. 객체 매핑을 단순화하는데 도움이 된다면 정규화와 같은 정형
화된 관계 표준을 젃충한다.
- Eric Evans
79 / 객체지향적인 도메인 레이어 구축하기
Thank you.
80 / 객체지향적인 도메인 레이어 구축하기
Question?
81 / 객체지향적인 도메인 레이어 구축하기
참고자료
- Christian Bauer, Gavin King, Java Persistence with Hibernate, Manning, 2006.
- Michael Keith, Merrick Schincario, Pro JPA2 : Mastering the Java(TM) Persistence API, Apress, 2009.
- Chris Richardson, POJOs in Action : Developing Enterprise Applications with Lightweight Frameworks, Manning,
2006.
- Martin Fowler, Patterns of Enterprise Application Architecture, Addison-Wesley, 2002.
- Eric Evans, Domain-Driven Design, Addison-Wesley, 2003.
- Kent Beck and Ward Cunningham, ‚A Laboratory for Teaching Object Oriented Thinking,‛ OOPSLA ‘89 Conference
Proceedings, SIGPLAN Notices, 24(10), pp. 1-6, New Orleans, Louisiana, October 1989.
- Rebecca Wirfs-Brock and Brian Wilkerson, ‚Object-Oriented Design: A Responsibility-Driven Approach,‛ OOPSLA ‘89
Conference Proceedings, SIGPLAN Notices, 24(10), pp.71-76, New Orleans, Louisiana, October, 1989.
- Rebecca Wirfs-Brock, Alan McKean, Object Design : Roles, Responsibilities, and Collaborations ,
Addison- Wesley, 2002.
Appendix A.
CRC Card
83 / 객체지향적인 도메인 레이어 구축하기
예매 생성 책임
 예매 생성에 필요한 정보의 EXPERT에게 할당Creator
Showing
상영 정보를 알고 있다
예매 정보를 생성한다
84 / 객체지향적인 도메인 레이어 구축하기
가격 계산 책임
 영화 가격 정보를 알고 있는 EXPERT에 할당Information Expert
Showing
상영 정보를 알고 있다
예매 정보를 생성한다
Movie
Movie
영화 정보를 알고 있다
가격을 계산한다
85 / 객체지향적인 도메인 레이어 구축하기
할인율 계산 책임
 할인율을 적용할 STRATEGY 객체 추가
Showing
상영 정보를 알고 있다
예매 정보를 생성한다
Movie
Movie
영화 정보를 알고 있다
가격을 계산한다
Discount
Strategy
DiscountStrategy
할인율 정책을 알고 있다
할인된 가격을 계산한다
86 / 객체지향적인 도메인 레이어 구축하기
할인 여부를 판단할 책임
 할인 정책을 판단하기 위한 SPECIFICATION 객체 추가
Showing
상영 정보를 알고 있다
예매 정보를 생성한다
Movie
Movie
영화 정보를 알고 있다
가격을 계산한다
Discount
Strategy
DiscountStrategy
할인율 정책을 알고 있다
할인된 가격을 계산한다
Rule
Rule
할인 정책을 알고 있다
할인 여부를 판단한다
Showing
Appendix B.
Domain Model Pattern Implementation
88 / 객체지향적인 도메인 레이어 구축하기
public class Showing {
public Reservation reserve(Customer customer, int audienceCount) {
return new Reservation(customer, this, audienceCount);
}
}
public class Reservation {
public Reservation(Customer customer, Showing showing, int audienceCount) {
this.customer = customer;
this.showing = showing;
this.fee = showing.calculateFee().times(audienceCount);
this.audienceCount = audienceCount;
}
} public class Showing {
public Money calculateFee() {
return movie.calculateFee(this);
}
}
public class Movie {
public Money calculateFee(Showing showing) {
return discountStrategy.calculateFee(showing);
}
}
Domain Layer Collaboration
89 / 객체지향적인 도메인 레이어 구축하기
public abstract class DiscountStrategy {
public Money calculateFee(Showing showing) {
for(Rule each : rules) {
if (each.isStatisfiedBy(showing)) {
return getDiscountedFee(showing);
}
}
return showing.getFixedFee();
}
abstract protected Money getDiscountedFee(Showing showing);
public abstract class Rule {
abstract public boolean isStatisfiedBy(Showing showing);
}
public class SequenceRule extends Rule {
public boolean isStatisfiedBy(Showing showing) {
return showing.isSequence(sequence);
}
}
public class TimeOfDayRule extends Rule {
public boolean isStatisfiedBy(Showing showing) {
return showing.isPlayingOn(dayOfWeek) &&
Interval.closed(startTime, endTime)
.includes(showing.getPlayngInterval());
}
}
Domain Layer Collaboration
90 / 객체지향적인 도메인 레이어 구축하기
public abstract class DiscountStrategy {
public Money calculateFee(Showing showing) {
for(Rule each : rules) {
if (each.isStatisfiedBy(showing)) {
return getDiscountedFee(showing);
}
}
return showing.getFixedFee();
}
abstract protected Money getDiscountedFee(Showing showing);
public class AmountDiscountStrategy extends DiscountStrategy {
protected Money getDiscountedFee(Showing showing) {
return showing.getFixedFee().minus(discountAmount);
}
}
public class NonDiscountStrategy extends DiscountStrategy {
protected Money getDiscountedFee(Showing showing) {
return showing.getFixedFee();
}
}
public class PercentDiscountStrategy extends DiscountStrategy {
protected Money getDiscountedFee(Showing showing) {
return showing.getFixedFee().minus(showing.getFixedFee().times(percent));
}
}
Domain Layer Collaboration
91 / 객체지향적인 도메인 레이어 구축하기
Domain Layer Collaboration
:Reservation :Movie
reserve()
new
:Showing
calculateFee()
calculateFee()
:DiscountStrategy :Rule
calculateFee()
isStatisfied()
*
92 / 객체지향적인 도메인 레이어 구축하기
Data Model
MOVIE
ID
TITLE
RUNNING_TIME
FEE_AMOUNT
FEE_CURRENCY
RESERVATION
ID
CUSTOMER_ID(FK)
SHOWING_ID(FK)
FEE_AMOUNT
FEE_CURRENCY
AUDIENCE_COUNT
RULE
ID
DISCOUNT_ID(FK)
POSITION
RULE_TYPE
DAY_OF_WEEK
START_TIME
END_TUME
SEQUENCE
DISCOUNT
MOVIE_ID(FK)
DISCOUNT_TYPE
FEE_AMOUNT
FEE_CURRENCY
PERCENT
REGISTER_DATE
SHOWING
ID
MOVIE_ID(FK)
SEQUENCE
SHOWING_TIME
CUSTOMER
ID
CUSTOMER_ID
NAME
Appendix C.
Impedance Mismatch Summary
94 / 객체지향적인 도메인 레이어 구축하기
Duration
quantity
Money
amount
currency
running
Time
fee
Movie
title
MOVIE
ID(PK)
TITLE
RUNNING_TIME
FEE_AMOUNT
FEE_CURRENCY
Movie
*1
Showing
Movie
*1
Showing
Movie
*1
Showing
MOVIE SHOWING
ID(PK)
MOVIE_ID(FK)
SEQUENCE
SHOWING_TIME
{abstract}
DiscountStrategy
registerDate
Percent
Discount
Strategy
percent
Amount
Discount
Strategy
discountAmount
Non
Discount
Strategy
DISCOUNT
MOVIE_ID(FK)
DISCOUNT_TYPE
FEE_AMOUNT
FEE_CURRENCY
PERCENT
REGISTER_DATE
AMOUNT_
DISCOUNT
MOVIE_ID(FK)
FEE_AMOUNT
FEE_CURRENCY
REGISTER_DATE
PERCENT_
DISCOUNT
MOVIE_ID(FK)
PERCENT
REGISTER_DATE
DISCOUNT
MOVIE_ID(FK)
REGISTER_DATE
AMOUNT_
DISCOUNT
DISCOUNT_ID(FK)
FEE_AMOUNT
FEE_CURRENCY
PERCENT_
DISCOUNT
DISCOUNT_ID(FK)
PERCENT
ID(PK)
TITLE
RUNNING_TIME
FEE_AMOUNT
FEE_CURRENCY
임피던스 불일치Impedance Mismatch

More Related Content

What's hot

[JWAP-2] DI & Spring
[JWAP-2] DI & Spring[JWAP-2] DI & Spring
[JWAP-2] DI & Spring
Young-Ho Cho
 
DDD로 복잡함 다루기
DDD로 복잡함 다루기DDD로 복잡함 다루기
DDD로 복잡함 다루기
beom kyun choi
 
우아한 객체지향
우아한 객체지향우아한 객체지향
우아한 객체지향
Young-Ho Cho
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven Design
Young-Ho Cho
 
DDD와 이벤트소싱
DDD와 이벤트소싱DDD와 이벤트소싱
DDD와 이벤트소싱
Suhyeon Jo
 
DDD 준비 서문래
DDD 준비 서문래DDD 준비 서문래
DDD 준비 서문래
beom kyun choi
 
도메인구현 KSUG 20151128
도메인구현 KSUG 20151128도메인구현 KSUG 20151128
도메인구현 KSUG 20151128
beom kyun choi
 
Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄
현 수
 
Event source 학습 내용 공유
Event source 학습 내용 공유Event source 학습 내용 공유
Event source 학습 내용 공유
beom kyun choi
 
Ksug2015 - JPA3, JPA 내부구조
Ksug2015 - JPA3, JPA 내부구조Ksug2015 - JPA3, JPA 내부구조
Ksug2015 - JPA3, JPA 내부구조
Younghan Kim
 
자바 서버 애플리케이션 아키텍처 안티 패턴
자바 서버 애플리케이션 아키텍처 안티 패턴자바 서버 애플리케이션 아키텍처 안티 패턴
자바 서버 애플리케이션 아키텍처 안티 패턴
Sungchul Park
 
Domain driven design 8장
Domain driven design 8장Domain driven design 8장
Domain driven design 8장
kukuman
 
Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄
Suhyeon Jo
 
[2019] DDD Lite@Spring
[2019] DDD Lite@Spring[2019] DDD Lite@Spring
[2019] DDD Lite@Spring
NHN FORWARD
 
Jpa 잘 (하는 척) 하기
Jpa 잘 (하는 척) 하기Jpa 잘 (하는 척) 하기
Jpa 잘 (하는 척) 하기
경원 이
 
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다
Arawn Park
 
객체지향 개념 (쫌 아는체 하기)
객체지향 개념 (쫌 아는체 하기)객체지향 개념 (쫌 아는체 하기)
객체지향 개념 (쫌 아는체 하기)
Seung-June Lee
 
Web Components
Web ComponentsWeb Components
Web Components
Nikolaus Graf
 
What is Material UI?
What is Material UI?What is Material UI?
What is Material UI?
Flatlogic
 
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
VMware Tanzu Korea
 

What's hot (20)

[JWAP-2] DI & Spring
[JWAP-2] DI & Spring[JWAP-2] DI & Spring
[JWAP-2] DI & Spring
 
DDD로 복잡함 다루기
DDD로 복잡함 다루기DDD로 복잡함 다루기
DDD로 복잡함 다루기
 
우아한 객체지향
우아한 객체지향우아한 객체지향
우아한 객체지향
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven Design
 
DDD와 이벤트소싱
DDD와 이벤트소싱DDD와 이벤트소싱
DDD와 이벤트소싱
 
DDD 준비 서문래
DDD 준비 서문래DDD 준비 서문래
DDD 준비 서문래
 
도메인구현 KSUG 20151128
도메인구현 KSUG 20151128도메인구현 KSUG 20151128
도메인구현 KSUG 20151128
 
Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄
 
Event source 학습 내용 공유
Event source 학습 내용 공유Event source 학습 내용 공유
Event source 학습 내용 공유
 
Ksug2015 - JPA3, JPA 내부구조
Ksug2015 - JPA3, JPA 내부구조Ksug2015 - JPA3, JPA 내부구조
Ksug2015 - JPA3, JPA 내부구조
 
자바 서버 애플리케이션 아키텍처 안티 패턴
자바 서버 애플리케이션 아키텍처 안티 패턴자바 서버 애플리케이션 아키텍처 안티 패턴
자바 서버 애플리케이션 아키텍처 안티 패턴
 
Domain driven design 8장
Domain driven design 8장Domain driven design 8장
Domain driven design 8장
 
Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄
 
[2019] DDD Lite@Spring
[2019] DDD Lite@Spring[2019] DDD Lite@Spring
[2019] DDD Lite@Spring
 
Jpa 잘 (하는 척) 하기
Jpa 잘 (하는 척) 하기Jpa 잘 (하는 척) 하기
Jpa 잘 (하는 척) 하기
 
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다
 
객체지향 개념 (쫌 아는체 하기)
객체지향 개념 (쫌 아는체 하기)객체지향 개념 (쫌 아는체 하기)
객체지향 개념 (쫌 아는체 하기)
 
Web Components
Web ComponentsWeb Components
Web Components
 
What is Material UI?
What is Material UI?What is Material UI?
What is Material UI?
 
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
 

Similar to 객체지향적인 도메인 레이어 구축하기

A6 객체지향적인 도메인 레이어 구축하기
A6 객체지향적인 도메인 레이어 구축하기A6 객체지향적인 도메인 레이어 구축하기
A6 객체지향적인 도메인 레이어 구축하기
NAVER D2
 
What's new in IE11
What's new in IE11What's new in IE11
What's new in IE11
Jae Sung Park
 
파크히어 Realm 사용 사례
파크히어 Realm 사용 사례파크히어 Realm 사용 사례
파크히어 Realm 사용 사례
선협 이
 
꿀밋업2탄_도메인 모델에 따른 데이터 분리 저장과 API 연결
꿀밋업2탄_도메인 모델에 따른 데이터 분리 저장과 API 연결꿀밋업2탄_도메인 모델에 따른 데이터 분리 저장과 API 연결
꿀밋업2탄_도메인 모델에 따른 데이터 분리 저장과 API 연결
VMware Tanzu Korea
 
Amazon Game Services - GameLift, GameSparks (김병수 솔루션즈 아키텍트, AWS) :: Gaming on...
Amazon Game Services - GameLift, GameSparks (김병수 솔루션즈 아키텍트, AWS) :: Gaming on...Amazon Game Services - GameLift, GameSparks (김병수 솔루션즈 아키텍트, AWS) :: Gaming on...
Amazon Game Services - GameLift, GameSparks (김병수 솔루션즈 아키텍트, AWS) :: Gaming on...
Amazon Web Services Korea
 
Rainbow Movie
Rainbow MovieRainbow Movie
Rainbow Movie
Hee Tae Kim
 
Amazon EC2 Deep Dive - 이창수 (AWS 솔루션 아키텍트) : 8월 온라인 세미나
Amazon EC2 Deep Dive - 이창수 (AWS 솔루션 아키텍트) : 8월 온라인 세미나Amazon EC2 Deep Dive - 이창수 (AWS 솔루션 아키텍트) : 8월 온라인 세미나
Amazon EC2 Deep Dive - 이창수 (AWS 솔루션 아키텍트) : 8월 온라인 세미나
Amazon Web Services Korea
 

Similar to 객체지향적인 도메인 레이어 구축하기 (7)

A6 객체지향적인 도메인 레이어 구축하기
A6 객체지향적인 도메인 레이어 구축하기A6 객체지향적인 도메인 레이어 구축하기
A6 객체지향적인 도메인 레이어 구축하기
 
What's new in IE11
What's new in IE11What's new in IE11
What's new in IE11
 
파크히어 Realm 사용 사례
파크히어 Realm 사용 사례파크히어 Realm 사용 사례
파크히어 Realm 사용 사례
 
꿀밋업2탄_도메인 모델에 따른 데이터 분리 저장과 API 연결
꿀밋업2탄_도메인 모델에 따른 데이터 분리 저장과 API 연결꿀밋업2탄_도메인 모델에 따른 데이터 분리 저장과 API 연결
꿀밋업2탄_도메인 모델에 따른 데이터 분리 저장과 API 연결
 
Amazon Game Services - GameLift, GameSparks (김병수 솔루션즈 아키텍트, AWS) :: Gaming on...
Amazon Game Services - GameLift, GameSparks (김병수 솔루션즈 아키텍트, AWS) :: Gaming on...Amazon Game Services - GameLift, GameSparks (김병수 솔루션즈 아키텍트, AWS) :: Gaming on...
Amazon Game Services - GameLift, GameSparks (김병수 솔루션즈 아키텍트, AWS) :: Gaming on...
 
Rainbow Movie
Rainbow MovieRainbow Movie
Rainbow Movie
 
Amazon EC2 Deep Dive - 이창수 (AWS 솔루션 아키텍트) : 8월 온라인 세미나
Amazon EC2 Deep Dive - 이창수 (AWS 솔루션 아키텍트) : 8월 온라인 세미나Amazon EC2 Deep Dive - 이창수 (AWS 솔루션 아키텍트) : 8월 온라인 세미나
Amazon EC2 Deep Dive - 이창수 (AWS 솔루션 아키텍트) : 8월 온라인 세미나
 

More from Young-Ho Cho

[NHN NEXT] Java 강의 - Week4
[NHN NEXT] Java 강의 - Week4[NHN NEXT] Java 강의 - Week4
[NHN NEXT] Java 강의 - Week4
Young-Ho Cho
 
[NEXT 프연 Week3] C# Data Type
[NEXT 프연 Week3] C# Data Type[NEXT 프연 Week3] C# Data Type
[NEXT 프연 Week3] C# Data Type
Young-Ho Cho
 
[NEXT 프연 Week2] UNIX 명령어 간단하게 살펴보기
[NEXT 프연 Week2] UNIX 명령어 간단하게 살펴보기[NEXT 프연 Week2] UNIX 명령어 간단하게 살펴보기
[NEXT 프연 Week2] UNIX 명령어 간단하게 살펴보기
Young-Ho Cho
 
[NHN NEXT] Java 강의- Week3
[NHN NEXT] Java 강의- Week3[NHN NEXT] Java 강의- Week3
[NHN NEXT] Java 강의- Week3
Young-Ho Cho
 
[NHN NEXT] Java 강의 - Week2
[NHN NEXT] Java 강의 - Week2[NHN NEXT] Java 강의 - Week2
[NHN NEXT] Java 강의 - Week2
Young-Ho Cho
 
[NHN NEXT] Java 강의 - Week1
[NHN NEXT] Java 강의 - Week1[NHN NEXT] Java 강의 - Week1
[NHN NEXT] Java 강의 - Week1
Young-Ho Cho
 
[NEXT 프연 Week1] Git 시작하기
[NEXT 프연 Week1] Git 시작하기[NEXT 프연 Week1] Git 시작하기
[NEXT 프연 Week1] Git 시작하기
Young-Ho Cho
 
[NHN NEXT] 2014 NHN NEXT 창의체험
[NHN NEXT] 2014 NHN NEXT 창의체험[NHN NEXT] 2014 NHN NEXT 창의체험
[NHN NEXT] 2014 NHN NEXT 창의체험
Young-Ho Cho
 
[PreSchool-1] 프로그래밍 '개념' 맛보기
[PreSchool-1] 프로그래밍 '개념' 맛보기[PreSchool-1] 프로그래밍 '개념' 맛보기
[PreSchool-1] 프로그래밍 '개념' 맛보기
Young-Ho Cho
 

More from Young-Ho Cho (9)

[NHN NEXT] Java 강의 - Week4
[NHN NEXT] Java 강의 - Week4[NHN NEXT] Java 강의 - Week4
[NHN NEXT] Java 강의 - Week4
 
[NEXT 프연 Week3] C# Data Type
[NEXT 프연 Week3] C# Data Type[NEXT 프연 Week3] C# Data Type
[NEXT 프연 Week3] C# Data Type
 
[NEXT 프연 Week2] UNIX 명령어 간단하게 살펴보기
[NEXT 프연 Week2] UNIX 명령어 간단하게 살펴보기[NEXT 프연 Week2] UNIX 명령어 간단하게 살펴보기
[NEXT 프연 Week2] UNIX 명령어 간단하게 살펴보기
 
[NHN NEXT] Java 강의- Week3
[NHN NEXT] Java 강의- Week3[NHN NEXT] Java 강의- Week3
[NHN NEXT] Java 강의- Week3
 
[NHN NEXT] Java 강의 - Week2
[NHN NEXT] Java 강의 - Week2[NHN NEXT] Java 강의 - Week2
[NHN NEXT] Java 강의 - Week2
 
[NHN NEXT] Java 강의 - Week1
[NHN NEXT] Java 강의 - Week1[NHN NEXT] Java 강의 - Week1
[NHN NEXT] Java 강의 - Week1
 
[NEXT 프연 Week1] Git 시작하기
[NEXT 프연 Week1] Git 시작하기[NEXT 프연 Week1] Git 시작하기
[NEXT 프연 Week1] Git 시작하기
 
[NHN NEXT] 2014 NHN NEXT 창의체험
[NHN NEXT] 2014 NHN NEXT 창의체험[NHN NEXT] 2014 NHN NEXT 창의체험
[NHN NEXT] 2014 NHN NEXT 창의체험
 
[PreSchool-1] 프로그래밍 '개념' 맛보기
[PreSchool-1] 프로그래밍 '개념' 맛보기[PreSchool-1] 프로그래밍 '개념' 맛보기
[PreSchool-1] 프로그래밍 '개념' 맛보기
 

객체지향적인 도메인 레이어 구축하기

  • 1. DOMAIN MODEL 패턴과 JPA의 조화 객체지향적인 도메인 레이어 구축하기 조영호 Eternity’s Chit-Chat(http://aeternum.egloos.com)
  • 2. 2. 임피던스 불일치Impedance Mismatch 목차 3. JPAJava Persistence API 1. 온라인 영화 예매 시스템 도메인 4. 결롞
  • 3. 1. 온라인 영화 예매 시스템 도메인
  • 4. 4 / 객체지향적인 도메인 레이어 구축하기 Domain Concept - 영화 Movie
  • 5. 5 / 객체지향적인 도메인 레이어 구축하기 2011-10-18 09:30 조조 2011-10-21 20:30 5회 2011-12-01 14:20 4회 Domain Concept - 상영 Showing
  • 6. 6 / 객체지향적인 도메인 레이어 구축하기 Domain Concept – 할인 정책 Amount Discount Percent Discount 8,000 - 800 = 7,200 8,000 – (8,000 * 0.1) = 7,200 Discount
  • 7. 7 / 객체지향적인 도메인 레이어 구축하기 Domain Concept – 할인 규칙 Sequence Rule Time Rule 조조 상영인 경우 월요일 10:00 ~ 12:00 상영인 경우 화요일 18:00 ~ 21:00 상영인 경우 10회 상영인 경우 Rule
  • 8. 8 / 객체지향적인 도메인 레이어 구축하기 Domain Concept –할인 정책 + 할인 규칙 Movie Discount Rule 1 0..1 1 1..* 10회 상영인 경우 도가니 8000원 Amount DC 800원 조조 상영인 경우 월요일 10:00 ~ 12:00 상영인 경우 화요일 18:00 ~ 21:00 상영인 경우
  • 9. 9 / 객체지향적인 도메인 레이어 구축하기 Domain Concept –예매 도가니 2011년 10월 18일 (목) 7회 6:00(오후) – 8:00(오후) 2명 16,000원 14,400원 제 목 상영 정보 인 원 정 가 결재 금액 Reservation
  • 10. 10 / 객체지향적인 도메인 레이어 구축하기 Domain Model Movie Discount Rule 1 0..1 1 1..* 1 0..* 1 0..* Showing Reservation
  • 11. 11 / 객체지향적인 도메인 레이어 구축하기 영화 예매 책임 수행을 위한 협력의 설계  후보 객체Candidate, 책임Responsibility, 협력Collaboration 식별 Showing 상영 정보를 알고 있다 예매 정보를 생성한다 Movie Movie 영화 정보를 알고 있다 가격을 계산한다 Discount Strategy DiscountStrategy 할인율 정책을 알고 있다 할인된 가격을 계산한다 Rule Rule 할인 정책을 알고 있다 할인 여부를 판단한다 Showing
  • 12. 12 / 객체지향적인 도메인 레이어 구축하기 도메인 레이어 객체 구현 Customer Showing reserve(customer, count):Reservation {abstract} Rule isStatisfiedBy(showing):boolean Reservation Amount Strategy Percent Strategy NonDiscount Strategy Sequence Rule TimeOfDay Rule {abstract} DiscountStrategy calculateFee(showing):Money Movie calculateFee(showing):Money <<create>> User Interface Service Domain Infrastructure
  • 13. 13 / 객체지향적인 도메인 레이어 구축하기 Domain Model Movie Discount Rule 1 0..1 1 1..* 1 0..* 1 0..* Showing Reservation
  • 14. 14 / 객체지향적인 도메인 레이어 구축하기 Movie Discount Rule 1 0..1 1 1..* 1 0..* 1 0..* Showing Reservation Domain Layer Design & Domain Model Customer Showing reserve(customer, count):Reservation {abstract} Rule isStatisfiedBy(showing):boolean Reservation Amount Strategy Percent Strategy NonDiscount Strategy Sequence Rule TimeOfDay Rule {abstract} DiscountStrategy calculateFee(showing):Money Movie calculateFee(showing):Money <<create>>
  • 15. 15 / 객체지향적인 도메인 레이어 구축하기 아키텍처 패턴 Domain Model User Interface Service Domain Infrastructure
  • 17. 17 / 객체지향적인 도메인 레이어 구축하기 임피던스 불일치Impedance Mismatch
  • 18. 18 / 객체지향적인 도메인 레이어 구축하기 객체-관계 임피던스 불일치  객체 모델과 DB 스키마 간의 불일치  객체 패러다임Object Paradigm과 관계 패러다임Relational Paradigm 간의 불일치 RULE ID DISCOUNT_ID(FK) POSITION RULE_TYPE DAY_OF_WEEK START_TIME END_TUME SEQUENCE DISCOUNT MOVIE_ID(FK) DISCOUNT_TYPE FEE_AMOUNT FEE_CURRENCY PERCENT Rule Amount Strategy Percent Strategy NonDiscount Strategy Sequence Rule TimeOfDay Rule DiscountStrategy
  • 19. 19 / 객체지향적인 도메인 레이어 구축하기 캡슐화 경계Encapsulation Boundary의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 구성 요소 크기Granularity의 불일치 임피던스 불일치 유형
  • 20. 20 / 객체지향적인 도메인 레이어 구축하기 캡슐화 경계Encapsulation Boundary의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 구성 요소 크기Granularity의 불일치 임피던스 불일치 유형
  • 21. 21 / 객체지향적인 도메인 레이어 구축하기 구성 요소 크기Granularity의 불일치Mismatch 8,000원 요금 135분 시간 하나와 앨리스 제목 Movie MOVIE ID(PK) TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY <<value object>> Duration quantity <<value object>> Money amount currency <<entity>> Movie title calculateFee(showing):Money running Time fee
  • 22. 22 / 객체지향적인 도메인 레이어 구축하기 Value Object Entity <<value object>> Duration quantity <<value object>> Money amount currency <<entity>> Movie title calculateFee(showing):Money running Time fee Identity Value Entity & Value Object
  • 23. 23 / 객체지향적인 도메인 레이어 구축하기 Movie 영화 정보를 알고 있다 가격을 계산한다 Money 금액과 환율을 알고 있다 금액을 +,-,*,/한다 Duration 기간을 알고 있다. 기간의 합, 차를 계산한다 책임의 재사용
  • 24. 24 / 객체지향적인 도메인 레이어 구축하기 코드 중복Code DuplicationProblem Movie id title runningTime fee feeCurrency calculateFee() Reservation id customerId showingId amount acmointCurrency audienceCount getFee() MOVIE ID(PK) TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY RESERVATION ID(PK) CUSTOMER_ID(FK) SHOWING_ID(FK) FEE_AMOUNT FEE_CURRENCY AUDIENCE_COUNT class Movie { long plus(long fee, Currency currency) { if (this.feeCurrency.equals(currency) { return this.fee + fee; } throw new IllegalArgumentException(); } } class Reservation { long add(long amount, Currency currency) { if (this.amountCurrency.equals(currency) { return this.amount + fee; } throw new IllegalArgumentException(); } }
  • 25. 25 / 객체지향적인 도메인 레이어 구축하기 캡슐화 경계Encapsulation Boundary의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 구성 요소 크기Granularity의 불일치 임피던스 불일치 유형
  • 26. 26 / 객체지향적인 도메인 레이어 구축하기 데이터베이스 식별자Database IdentityMismatch TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY MOVIE 시간을 달리는 소녀 95 8,000 KRW 시간을 달리는 소녀 95 8,000 KRW ID 1 2  테이블 주키Primary Key 8,000원 요금 95분 시간 시간을 달리는 소녀 제목 8,000원 요금 95분 시간 시간을 달리는 소녀 제목
  • 27. 27 / 객체지향적인 도메인 레이어 구축하기 객체 식별자Object Identity 8,000원 요금 95분 시간 시간을 달리는 소녀 제목 8,000원 요금 95분 시간 시간을 달리는 소녀 제목 movie1 : Movie title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000 address 1 movie2 : Movie title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000 address 2  Java == 연산자
  • 28. 28 / 객체지향적인 도메인 레이어 구축하기 데이터베이스-객체 식별자 불일치Identity Mismatch TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY MOVIE 시간을 달리는 소녀 95 8,000 KRW 시간을 달리는 소녀 95 8,000 KRW ID 1 2 movie1 : Movie title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000 movie2 : Movie title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000 Problem
  • 29. 29 / 객체지향적인 도메인 레이어 구축하기 캡슐화 경계Encapsulation Boundary의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 구성 요소 크기Granularity의 불일치 임피던스 불일치 유형
  • 30. 30 / 객체지향적인 도메인 레이어 구축하기 다형성PolymorphismMismatch Movie Amount Discount 800원 Percent Discount 10% No Discount 0원(%) Discount Movie calculateFee(showing) {abstract} DiscountStrategy registerDate calculateFee(showing) Percent DiscountStrategy percent Amount DiscountStrategy discountAmount Non DiscountStrategy public class Movie { private DiscountStrategy discountStrategy; public Money calculateFee(Showing showing) { return discountStrategy.calculateFee(showing); } }
  • 31. 31 / 객체지향적인 도메인 레이어 구축하기 젃차적인 조건 분기Conditional BranchProblem public class Movie { private DiscountStrategy discountStrategy; public Money calculateFee(Showing showing) { return discountStrategy.calculateFee(showing); } } public class ReservationService { public Money calculateFee(Movie movie, DiscountStrategy discountStrategy) { if (discountStrategy.isAmountType()) { ... } else if (discountStrategy.isPercentType()) { ... } else { ... } ... } } Movie Amount Discount 800원 Percent Discount 10% No Discount 0원(%) Discount Movie id title runningTime fee feeCurrency calculateFee() DiscountStrategy movieId discountType amount percent registerDate calculateFee()
  • 32. 32 / 객체지향적인 도메인 레이어 구축하기 캡슐화 경계Encapsulation Boundary의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 구성 요소 크기Granularity의 불일치 임피던스 불일치 유형
  • 33. 33 / 객체지향적인 도메인 레이어 구축하기 데이터베이스 외래키Foreign KeyMismatch Movie Showing 1회 10/18 10:00 2회 10/18 12:30 3회 10/18 15:00 4회 10/18 17:30 MOVIE SHOWING ID(PK) SEQUENCE SHOWING_TIME ID(PK) TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY MOVIE_ID(FK) TITLE 하나와 앨리스 MOVIE ID SEQUENCE SHOWING_TIME 1 7 2010-12-23 18:00 SHOWING ID 1 MOVIE_ID 1
  • 34. 34 / 객체지향적인 도메인 레이어 구축하기 테이블 외래키Foreign Key - 양방향BiDirectional MOVIE SHOWING ID(PK) MOVIE_ID(FK) SEQUENCE SHOWING_TIME ID(PK) TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY SELECT * FROM MOVIE as m LEFT JOIN SHOWING as s ON m.ID = s.MOVIE_ID
  • 35. 35 / 객체지향적인 도메인 레이어 구축하기 객체 연관관계Association – 단방향UniDirectional Showing reserve(customer, count) Movie calculateFee(showing) *1 Showing reserve(customer, count) Movie calculateFee(showing) *1 Showing reserve(customer, count) Movie calculateFee(showing) *1 showing.getMovie(); movie.getShowings(); movie.getShowings(); showing.getMovie(); MOVIE SHOWING ID(PK) MOVIE_ID(FK) SEQUENCE SHOWING_TIME ID(PK) TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY
  • 36. 36 / 객체지향적인 도메인 레이어 구축하기 Showing 상영 정보를 알고 있다 예매 정보를 생성한다 Movie Movie 영화 정보를 알고 있다 가격을 계산한다 Discount Strategy DiscountStrategy 할인율 정책을 알고 있다 할인된 가격을 계산한다 Rule Showing reserve() Movie calculateFee() * 1 DiscountStrategy calculateFee() 1 0..1 public class Showing { private Movie movie; public Money calculateFee() { return movie.calculateFee(this); } ... } public class Movie { private DiscountStrategy discountStrategy; public Money calculateFee(Showing showing) { return discountStrategy.calculateFee(showing); } ... }  연관 관계는 책임 분배와 협력을 위한 핵심 메커니즘 객체 협력Collaboration을 통한 구현
  • 37. 37 / 객체지향적인 도메인 레이어 구축하기 Data + Process = 젃차적인Procedural 프로그래밍Problem public class Showing { private Movie movie; public Money calculateFee() { return movie.calculateFee(this); } ... } MOVIE SHOWING ID(PK) MOVIE_ID(FK) SEQUENCE SHOWING_TIME ID(PK) TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY Movie id title runningTime fee feeCurrency Showing id movieId title sequence showingTime public class ReservationService { public Reservation reserveShowing(int customerId, int showingId, int audienceCount) { Showing showing = showingDAO.selectShowing(showingId); Movie movie = movieDAO.selectMovie(showing.getMovieId()); long amount = calculateFee(movie.getFee(), showing, audienceCount); ... } private long calculateFee(long movieFee, Showing showing, int audientCount) { ... } } Data Process ReservationService reserveShowing()
  • 38. 38 / 객체지향적인 도메인 레이어 구축하기 캡슐화 경계Encapsulation Boundary의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 구성 요소 크기Granularity의 불일치 임피던스 불일치 유형
  • 39. 39 / 객체지향적인 도메인 레이어 구축하기 캡슐화EncapsulationMismatch {abstract} Rule isStatisfiedBy(showing) Sequence Rule TimeOfDay Rule Amount Strategy Percent Strategy NonDiscount Strategy {abstract} DiscountStrategy calculateFee(showing):Money Showing reserve(customer, count) Movie calculateFee(showing):Money Hierarchical Flat
  • 40. 40 / 객체지향적인 도메인 레이어 구축하기 할인 규칙 등록 Movie calculateFee(showing) Showing reserve(customer, count) *1 {abstract} DiscountStrategy calculateFee(showing)1 0..1 {abstract} Rule calculateFee(showing)0..*1 제 목 무지개여싞 상영 시간 116분 요 금 할인 정책 AMOUNT DISCOUNT 할인 금액 할인 규칙 SEQUENCE RULE 5회 7회할인 대상 8,000원 9,000원 1회 1회
  • 41. 41 / 객체지향적인 도메인 레이어 구축하기 할인 규칙 등록 Movie calculateFee(showing) Showing reserve(customer, count) *1 {abstract} DiscountStrategy calculateFee(showing)1 0..1 {abstract} Rule calculateFee(showing)0..*1 제 목 무지개여싞 상영 시간 116분 요 금 할인 정책 AMOUNT DISCOUNT 할인 금액 할인 규칙 SEQUENCE RULE 5회 7회할인 대상 8,000원 9,000원 1회 1회 Movie Discount Rule 캡슐화 경계Boundary
  • 42. 42 / 객체지향적인 도메인 레이어 구축하기 캡슐화 저해Problem Flat movie.setFee(8000); movieDAO.save(movie); DiscountStrategy strategy = new AmountDiscountStrategy(9000); discountStrategyDAO.save(strategy); DiscountRule rule = new SequenceRule(1); discountRuleDAO.save(rule); 불변식 위반Invariant Violation DiscountRule rule = new SequenceRule(1); discountRuleDAO.save(rule);
  • 43. 43 / 객체지향적인 도메인 레이어 구축하기 임피던스 불일치의 결과 public class Movie { private Long id; private String title; public Long getId() { return id; } public String getTitle() { return title; } public class ReservationService { public Money calculateFee(Movie movie, DiscountStrategy strategy) { if (strategy.isAmountType()) { ... } else if (strategy.isPercentType()) { ... } else { ... } ... } public class ReservationService { public Reservation reserveShowing(int customerId, int showingId, int audienceCount) { Showing showing = showingDAO.selectShowing(showingId); Movie movie = movieDAO.selectMovie(showing.getMovieId()); long amount = calculateFee(movie.getFee(), showing, audienceCount);  Anemic Domain Model & Fat Service Layer Conclusion
  • 44. 44 / 객체지향적인 도메인 레이어 구축하기 Transaction Script 아키텍처 패턴 User Interface Service Domain Infrastructure
  • 46. 46 / 객체지향적인 도메인 레이어 구축하기 DATA MAPPER  객체 모델과 DB 스키마 간의 독립성 유지  도메인 객체는 DB에 대해 독립적  ORMObject-Relational Mapper RULE ID DISCOUNT_ID(FK) POSITION RULE_TYPE DAY_OF_WEEK START_TIME END_TUME SEQUENCE Rule SequenceRule TimeOfDayRule RuleMapper insert update delete
  • 47. 47 / 객체지향적인 도메인 레이어 구축하기 JPAJava Persistence API RULE ID DISCOUNT_ID(FK) POSITION RULE_TYPE DAY_OF_WEEK START_TIME END_TUME SEQUENCE Rule SequenceRule TimeOfDayRule Hibernate EclipseLink JPA  Java ORM 표준 명세  Annotation과 XML을 이용한 META DATA MAPPING 기능 제공  Hibernate, EclipseLink
  • 48. 48 / 객체지향적인 도메인 레이어 구축하기 캡슐화 경계Encapsulation Boundary의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 구성 요소 크기Granularity의 불일치 임피던스 불일치 유형
  • 49. 49 / 객체지향적인 도메인 레이어 구축하기 구성 요소 크기Granularity의 불일치Mismatch 8,000원 요금 135분 시간 하나와 앨리스 제목 Movie MOVIE ID(PK) TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY Value Object Entity <<value object>> Duration quantity <<value object>> Money amount currency <<entity>> Movie title calculateFee(showing):Money running Time fee
  • 50. 50 / 객체지향적인 도메인 레이어 구축하기 Solution @Embeddable Value Object Entity <<value object>> Duration quantity <<value object>> Money amount currency <<entity>> Movie title calculateFee(showing):Money running Time fee @Entity @Table(name="MOVIE") public class Movie { private Duration runningTime; private Money fee; @Embeddable public class Duration { @Column(name="RUNNING_TIME", nullable=true) private long quantity; @Embeddable public class Money { @Column(name="FEE_AMOUNT", nullable=true) private BigDecimal amount; @Column(name="FEE_CURRENCY", nullable=true) private Currency currency; MOVIE ID(PK) TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY
  • 51. 51 / 객체지향적인 도메인 레이어 구축하기 캡슐화 경계Encapsulation Boundary의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 구성 요소 크기Granularity의 불일치 임피던스 불일치 유형
  • 52. 52 / 객체지향적인 도메인 레이어 구축하기 식별자 불일치Identity MismatchMismatch TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY MOVIE 시간을 달리는 소녀 95 8,000 KRW 시간을 달리는 소녀 95 8,000 KRW ID 1 2 movie1 : Movie title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000 movie2 : Movie title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000
  • 53. 53 / 객체지향적인 도메인 레이어 구축하기 영속 컨텍스트Persistence ContextSolution UNIT OF WORK User Interface Service Domain Infrastructure Begin TX Commit/ Rollback IDENTITY MAP
  • 54. 54 / 객체지향적인 도메인 레이어 구축하기 영화 엔티티Entity 조회 TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY MOVIE 시간을 달리는 소녀 95 8,000 KRW 시간을 달리는 소녀 95 8,000 KRW ID 1 2 movie1 : Movie title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000 movie2 : Movie title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000
  • 55. 55 / 객체지향적인 도메인 레이어 구축하기 영속 컨텍스트Persistence Context UNIT OF WORK User Interface Service Domain Infrastructure IDENTITY MAP Begin TX Commit/ Rollback ID 1 movie1 : Movie title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000 ID 2 movie2 : Movie title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000
  • 56. 56 / 객체지향적인 도메인 레이어 구축하기 첫 번째 영화 엔티티 다시 조회 TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY MOVIE ID 시간을 달리는 소녀 95 8,000 KRW1 movie1 : Movie title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000 movie2 : Movie title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000 시간을 달리는 소녀 95 8,000 KRW2
  • 57. 57 / 객체지향적인 도메인 레이어 구축하기 영속 컨텍스트Persistence Context UNIT OF WORK User Interface Service Domain Infrastructure IDENTITY MAP Begin TX Commit/ Rollback ID 1 movie1 : Movie title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000 ID 2 movie2 : Movie title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000
  • 58. 58 / 객체지향적인 도메인 레이어 구축하기 식별자 일관성 보장 TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY MOVIE ID 시간을 달리는 소녀 95 8,000 KRW1 movie1 : Movie title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000 movie2 : Movie title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000 시간을 달리는 소녀 95 8,000 KRW2  데이터베이스 주키Primary Key와 객체 식별자Identity 간 일관성 유지
  • 59. 59 / 객체지향적인 도메인 레이어 구축하기 식별자 일관성 보장 movie1 = entityManager.load(Movie.class, 1); movie2 = entityManager.load(Movie.class, 1); assertSame(movie1, movie2);
  • 60. 60 / 객체지향적인 도메인 레이어 구축하기 캡슐화 경계Encapsulation Boundary의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 구성 요소 크기Granularity의 불일치 임피던스 불일치 유형
  • 61. 61 / 객체지향적인 도메인 레이어 구축하기 다형성PolymorphismMismatch public class ReservationService { public Money calculateFee(Movie movie, DiscountStrategy discountStrategy) { if (discountStrategy.isAmountType()) { ... } else if (discountStrategy.isPercentType()) { ... } else { ... } ... } } Movie Amount Discount 800원 Percent Discount 10% No Discount 0원(%) Discount Movie calculateFee(showing) {abstract} DiscountStrategy registerDate calculateFee(showing) Percent DiscountStrategy percent Amount DiscountStrategy discountAmount Non DiscountStrategy Movie id title runningTime fee feeCurrency calculateFee() DiscountStrategy movieId discountType amount percent registerDate calculateFee()
  • 62. 62 / 객체지향적인 도메인 레이어 구축하기 상속 매핑Inheritance MappingSolution {abstract} DiscountStrategy registerDate calculateFee(showing) Percent DiscountStrategy percent Amount DiscountStrategy discountAmount DISCOUNT MOVIE_ID(FK) DISCOUNT_TYPE FEE_AMOUNT FEE_CURRENCY PERCENT REGISTER_DATE Single Table Inheritance AMOUNT_DISCOUNT MOVIE_ID(FK) FEE_AMOUNT FEE_CURRENCY REGISTER_DATE PERCENT_DISCOUNT MOVIE_ID(FK) PERCENT REGISTER_DATE Concrete Class Inheritance Class Table Inheritance DISCOUNT AMOUNT_DISCOUN T DISCOUNT_ID(FK) FEE_AMOUNT FEE_CURRENCY PERCENT_DISCOUN T DISCOUNT_ID(FK) PERCENT MOVIE_ID(FK) REGISTER_DATE
  • 63. 63 / 객체지향적인 도메인 레이어 구축하기 다형성을 통한 조건 분기 제거Solution Movie Amount Discount 800원 Percent Discount 10% No Discount 0원(%) Discount Movie calculateFee(showing) {abstract} DiscountStrategy registerDate calculateFee(showing) Percent DiscountStrategy percent Amount DiscountStrategy discountAmount Non DiscountStrategy public class Movie { private DiscountStrategy discountStrategy; public Money calculateFee(Showing showing) { return discountStrategy.calculateFee(showing); } }
  • 64. 64 / 객체지향적인 도메인 레이어 구축하기 캡슐화 경계Encapsulation Boundary의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 구성 요소 크기Granularity의 불일치 임피던스 불일치 유형
  • 65. 65 / 객체지향적인 도메인 레이어 구축하기 연관관계Association와 외래키Foreign KeyMismatch Showing reserve(customer, count) Movie calculateFee(showing) *1 Showing reserve(customer, count) Movie calculateFee(showing) *1 Showing reserve(customer, count) Movie calculateFee(showing) *1 showing.getMovie(); movie.getShowings(); movie.getShowings(); showing.getMovie(); MOVIE SHOWING ID(PK) MOVIE_ID(FK) SEQUENCE SHOWING_TIME ID(PK) TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY
  • 66. 66 / 객체지향적인 도메인 레이어 구축하기 외래키 맵핑Foreign Key MappingSolution MOVIE SHOWING ID(PK) MOVIE_ID(FK) SEQUENCE SHOWING_TIME ID(PK) TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY Showing reserve(customer, count) Movie calculateFee(showing) *1 Foreign Key Association public class Showing { @ManyToOne(optional=false) @JoinColumn(name="MOVIE_ID") private Movie movie; } public Money calculateFee() { return movie.calculateFee(this); }
  • 67. 67 / 객체지향적인 도메인 레이어 구축하기 캡슐화 경계Encapsulation Boundary의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 구성 요소 크기Granularity의 불일치 임피던스 불일치 유형
  • 68. 68 / 객체지향적인 도메인 레이어 구축하기 캡슐화EncapsulationMismatch Flat movie.setFee(8000); movieDAO.save(movie); DiscountStrategy strategy = new AmountDiscountStrategy(9000); discountStrategyDAO.save(strategy); DiscountRule rule = new SequenceRule(1); discountRuleDAO.save(rule); 불변식 위반Invariant Violation DiscountRule rule = new SequenceRule(1); discountRuleDAO.save(rule); {abstract} Rule isStatisfiedBy(sho wing) Sequence Rule TimeOf Day Rule Amount Strategy Percent Strategy NonDiscoun t Strategy {abstract} DiscountStrategy calculateFee(showing):Mon ey Showing reserve(customer, count) Movie calculateFee(showing):Money Hierarchical
  • 69. 69 / 객체지향적인 도메인 레이어 구축하기 페치 젂략Fetch StrategySolution  지연 페치Lazy Fetch public class Movie { @OneToOne(cascade=CascadeType.ALL, optional=true, fetch=FetchType.LAZY) private DiscountStrategy discountStrategy; public class DiscountStrategy { @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY) @JoinColumn(name="DISCOUNTID") private Set<Rule> rules = new HashSet<Rule>(); Showing reserve(customer, count) 1 {abstract} Rule calculateFee(showing)0..*1 Movie calculateFee(showing)* {abstract} DiscountStrategy calculateFee(showing)1 0..1
  • 70. 70 / 객체지향적인 도메인 레이어 구축하기 페치 젂략Fetch StrategySolution  선행 페치Eager Fetch public class Movie { @OneToOne(cascade=CascadeType.ALL, optional=true, fetch=FetchType.EAGER) private DiscountStrategy discountStrategy; public class DiscountStrategy { @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER) @JoinColumn(name="DISCOUNTID") private Set<Rule> rules = new HashSet<Rule>(); Showing reserve(customer, count) Movie calculateFee(showing)*1 {abstract} DiscountStrategy calculateFee(showing)1 0..1 {abstract} Rule calculateFee(showing)0..*1
  • 71. 71 / 객체지향적인 도메인 레이어 구축하기  예기치 못한 변경으로부터 보호  객체 그룹의 불변성 보장 {abstract} Rule isStatisfiedBy(showing) Sequence Rule TimeOfDay Rule Amount Strategy Percent Strategy NonDiscount Strategy {abstract} DiscountStrategy calculateFee(showing):Money Showing reserve(customer, count) Movie calculateFee(showing):Money Aggregate Aggregate = 캡슐화 경계Encapsulation Boundary Eager Fetch Lazy Fetch Solution
  • 73. 73 / 객체지향적인 도메인 레이어 구축하기 DOMAIN MODEL PATTERN  도메인을 구성하는 개념들을 따르는 도메인 레이어  적젃한 책임의 분배와 협력을 통한 객체 지향적인 도메인 레이어
  • 74. 74 / 객체지향적인 도메인 레이어 구축하기 임피던스 불일치  맹목적으로 테이블의 구조를 따르는 객체 구조  젃차적인 TRANSACTION SCRIPT로 향하는 한 가지 이유
  • 75. 75 / 객체지향적인 도메인 레이어 구축하기 JPAJavaPersistece API  임피던스 불일치를 해결할 수 있는 실용적인 솔루션  풍부한 도메인 레이어Rich Domain Layer의 기반
  • 76. 76 / 객체지향적인 도메인 레이어 구축하기 Movie Discount Rule 1 0..1 1 1..* 1 0..* 1 0..* Showing Reservation Domain Model에 초점을 맞춰라 Customer Showing reserve(customer, count):Reservation {abstract} Rule isStatisfiedBy(showing):boolean Reservation Amount Strategy Percent Strategy NonDiscount Strategy Sequence Rule TimeOfDay Rule {abstract} DiscountStrategy calculateFee(showing):Money Movie calculateFee(showing):Money <<create>>
  • 77. 77 / 객체지향적인 도메인 레이어 구축하기 Data Model이 더 중요
  • 78. 78 / 객체지향적인 도메인 레이어 구축하기 Be Pragmatic 타협하라 데이터베이스가 하나의 객체 저장소로 보여진다면 매핑 도구의 기능과는 상관없이 데이터 모델과 객체 모델이 서로 갈라지게 해서는 안 된다. 일부 객체 관계의 풍부함을 희생해서 관계 모델에 밀접하게 한다. 객체 매핑을 단순화하는데 도움이 된다면 정규화와 같은 정형 화된 관계 표준을 젃충한다. - Eric Evans
  • 79. 79 / 객체지향적인 도메인 레이어 구축하기 Thank you.
  • 80. 80 / 객체지향적인 도메인 레이어 구축하기 Question?
  • 81. 81 / 객체지향적인 도메인 레이어 구축하기 참고자료 - Christian Bauer, Gavin King, Java Persistence with Hibernate, Manning, 2006. - Michael Keith, Merrick Schincario, Pro JPA2 : Mastering the Java(TM) Persistence API, Apress, 2009. - Chris Richardson, POJOs in Action : Developing Enterprise Applications with Lightweight Frameworks, Manning, 2006. - Martin Fowler, Patterns of Enterprise Application Architecture, Addison-Wesley, 2002. - Eric Evans, Domain-Driven Design, Addison-Wesley, 2003. - Kent Beck and Ward Cunningham, ‚A Laboratory for Teaching Object Oriented Thinking,‛ OOPSLA ‘89 Conference Proceedings, SIGPLAN Notices, 24(10), pp. 1-6, New Orleans, Louisiana, October 1989. - Rebecca Wirfs-Brock and Brian Wilkerson, ‚Object-Oriented Design: A Responsibility-Driven Approach,‛ OOPSLA ‘89 Conference Proceedings, SIGPLAN Notices, 24(10), pp.71-76, New Orleans, Louisiana, October, 1989. - Rebecca Wirfs-Brock, Alan McKean, Object Design : Roles, Responsibilities, and Collaborations , Addison- Wesley, 2002.
  • 83. 83 / 객체지향적인 도메인 레이어 구축하기 예매 생성 책임  예매 생성에 필요한 정보의 EXPERT에게 할당Creator Showing 상영 정보를 알고 있다 예매 정보를 생성한다
  • 84. 84 / 객체지향적인 도메인 레이어 구축하기 가격 계산 책임  영화 가격 정보를 알고 있는 EXPERT에 할당Information Expert Showing 상영 정보를 알고 있다 예매 정보를 생성한다 Movie Movie 영화 정보를 알고 있다 가격을 계산한다
  • 85. 85 / 객체지향적인 도메인 레이어 구축하기 할인율 계산 책임  할인율을 적용할 STRATEGY 객체 추가 Showing 상영 정보를 알고 있다 예매 정보를 생성한다 Movie Movie 영화 정보를 알고 있다 가격을 계산한다 Discount Strategy DiscountStrategy 할인율 정책을 알고 있다 할인된 가격을 계산한다
  • 86. 86 / 객체지향적인 도메인 레이어 구축하기 할인 여부를 판단할 책임  할인 정책을 판단하기 위한 SPECIFICATION 객체 추가 Showing 상영 정보를 알고 있다 예매 정보를 생성한다 Movie Movie 영화 정보를 알고 있다 가격을 계산한다 Discount Strategy DiscountStrategy 할인율 정책을 알고 있다 할인된 가격을 계산한다 Rule Rule 할인 정책을 알고 있다 할인 여부를 판단한다 Showing
  • 87. Appendix B. Domain Model Pattern Implementation
  • 88. 88 / 객체지향적인 도메인 레이어 구축하기 public class Showing { public Reservation reserve(Customer customer, int audienceCount) { return new Reservation(customer, this, audienceCount); } } public class Reservation { public Reservation(Customer customer, Showing showing, int audienceCount) { this.customer = customer; this.showing = showing; this.fee = showing.calculateFee().times(audienceCount); this.audienceCount = audienceCount; } } public class Showing { public Money calculateFee() { return movie.calculateFee(this); } } public class Movie { public Money calculateFee(Showing showing) { return discountStrategy.calculateFee(showing); } } Domain Layer Collaboration
  • 89. 89 / 객체지향적인 도메인 레이어 구축하기 public abstract class DiscountStrategy { public Money calculateFee(Showing showing) { for(Rule each : rules) { if (each.isStatisfiedBy(showing)) { return getDiscountedFee(showing); } } return showing.getFixedFee(); } abstract protected Money getDiscountedFee(Showing showing); public abstract class Rule { abstract public boolean isStatisfiedBy(Showing showing); } public class SequenceRule extends Rule { public boolean isStatisfiedBy(Showing showing) { return showing.isSequence(sequence); } } public class TimeOfDayRule extends Rule { public boolean isStatisfiedBy(Showing showing) { return showing.isPlayingOn(dayOfWeek) && Interval.closed(startTime, endTime) .includes(showing.getPlayngInterval()); } } Domain Layer Collaboration
  • 90. 90 / 객체지향적인 도메인 레이어 구축하기 public abstract class DiscountStrategy { public Money calculateFee(Showing showing) { for(Rule each : rules) { if (each.isStatisfiedBy(showing)) { return getDiscountedFee(showing); } } return showing.getFixedFee(); } abstract protected Money getDiscountedFee(Showing showing); public class AmountDiscountStrategy extends DiscountStrategy { protected Money getDiscountedFee(Showing showing) { return showing.getFixedFee().minus(discountAmount); } } public class NonDiscountStrategy extends DiscountStrategy { protected Money getDiscountedFee(Showing showing) { return showing.getFixedFee(); } } public class PercentDiscountStrategy extends DiscountStrategy { protected Money getDiscountedFee(Showing showing) { return showing.getFixedFee().minus(showing.getFixedFee().times(percent)); } } Domain Layer Collaboration
  • 91. 91 / 객체지향적인 도메인 레이어 구축하기 Domain Layer Collaboration :Reservation :Movie reserve() new :Showing calculateFee() calculateFee() :DiscountStrategy :Rule calculateFee() isStatisfied() *
  • 92. 92 / 객체지향적인 도메인 레이어 구축하기 Data Model MOVIE ID TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY RESERVATION ID CUSTOMER_ID(FK) SHOWING_ID(FK) FEE_AMOUNT FEE_CURRENCY AUDIENCE_COUNT RULE ID DISCOUNT_ID(FK) POSITION RULE_TYPE DAY_OF_WEEK START_TIME END_TUME SEQUENCE DISCOUNT MOVIE_ID(FK) DISCOUNT_TYPE FEE_AMOUNT FEE_CURRENCY PERCENT REGISTER_DATE SHOWING ID MOVIE_ID(FK) SEQUENCE SHOWING_TIME CUSTOMER ID CUSTOMER_ID NAME
  • 94. 94 / 객체지향적인 도메인 레이어 구축하기 Duration quantity Money amount currency running Time fee Movie title MOVIE ID(PK) TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY Movie *1 Showing Movie *1 Showing Movie *1 Showing MOVIE SHOWING ID(PK) MOVIE_ID(FK) SEQUENCE SHOWING_TIME {abstract} DiscountStrategy registerDate Percent Discount Strategy percent Amount Discount Strategy discountAmount Non Discount Strategy DISCOUNT MOVIE_ID(FK) DISCOUNT_TYPE FEE_AMOUNT FEE_CURRENCY PERCENT REGISTER_DATE AMOUNT_ DISCOUNT MOVIE_ID(FK) FEE_AMOUNT FEE_CURRENCY REGISTER_DATE PERCENT_ DISCOUNT MOVIE_ID(FK) PERCENT REGISTER_DATE DISCOUNT MOVIE_ID(FK) REGISTER_DATE AMOUNT_ DISCOUNT DISCOUNT_ID(FK) FEE_AMOUNT FEE_CURRENCY PERCENT_ DISCOUNT DISCOUNT_ID(FK) PERCENT ID(PK) TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY 임피던스 불일치Impedance Mismatch