SlideShare una empresa de Scribd logo
1 de 70
Descargar para leer sin conexión
Object-Oriented Design & Architecture
Rich Domain Model
조영호
Eternity’s Chit-Chat
http://aeternum.egloos.com
2. 데이터-지향 설계
3. 책임-주도 설계
목차
4. 아키텍처 & 프레임워크
1. 영화 예매 시스템 도메인
5. 결롞
1. 영화 예매 시스템 도메인
4 / 문서의 제목
온라인 영화 예매 시스템
5 / 문서의 제목
Domain Concept - 영화
Movie
6 / 문서의 제목
Domain Concept - 상영
2010-10-20 09:30 조조
Showing
2010-10-21 20:30 5회
2010-12-01 14:20 4회
7 / 문서의 제목
Domain Concept – 할인 정책
Discount Amount Discount
Percent Discount
8,000 - 800 = 7,200
8,000 – (8,000 * 0.1) = 7,200
8 / 문서의 제목
Domain Concept – 할인 규칙
Rule Sequence Rule
Time Rule
조조 상영인 경우
월요일 10:00 ~ 12:00 상영인 경우
목요일 18:00 ~ 21:00 상영인 경우
10회 상영인 경우
9 / 문서의 제목
Domain Concept –할인 정책 + 할인 규칙
Movie Discount Rule
1 0..1 1 1..*
10 / 문서의 제목
10회 상영인 경우
Domain Concept –할인 정책 + 할인 규칙
Movie Discount Rule
1 0..1 1 1..*
이끼
8000원
Amount DC
800원
조조 상영인 경우
월요일 10:00 ~ 12:00 상영인 경우
목요일 18:00 ~ 21:00 상영인 경우
11 / 문서의 제목
10회 상영인 경우
Domain Concept –할인 적용
이끼
8000원
Amount DC
800원
조조 상영인 경우
월요일 10:00 ~ 12:00 상영인 경우
목요일 18:00 ~ 21:00 상영인 경우
상영정보
2010년 12월 23일 목요일
18:00 ~ 20:00(7회차)
12 / 문서의 제목
10회 상영인 경우
Domain Concept –할인 적용
이끼
8000원
Amount DC
800원
조조 상영인 경우
월요일 10:00 ~ 12:00 상영인 경우
목요일 18:00 ~ 21:00 상영인 경우
상영정보
2010년 12월 23일 목요일
18:00 ~ 20:00(7회차)
7,200
13 / 문서의 제목
Domain Concept –예매
Reservation
이끼
2010년 12월 23일 (목)
7회 6:00(오후) – 8:00(오후)
2명
16,000원
14,400원
제 목
상영 정보
인 원
정 가
결재 금액
2. 데이터-지향 설계
15 / 문서의 제목
무엇을 저장할 것인가 - 데이터
16 / 문서의 제목
데이터 모델
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
SHOWING
ID
MOVIE_ID(FK)
SEQUENCE
SHOWING_TIME
CUSTOMER
ID
CUSTOMER_ID
NAME
17 / 문서의 제목
또 다른 데이터 표현 – Anemic Domain Model
Movie
id
title
runningTime
fee
Reservation
id
customerId
showingId
Amounr
audienceCount
Rule
id
discountId
position
ruleType
dayOfWeek
startTime
endTime
sequence
Discount
movieId
discountType
amount
percent
Showing
id
movieId
sequence
showingTime
Customer
Id
customerId
name
18 / 문서의 제목
초기 데이터
ID TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY
1 이끼 120 8000 KRW
MOVIE
MOVIE_ID DISCOUNTYPE FEE_AMOUNT FEE_ACURRENCY PERCENT
1 A 800 KRW NULL
DISCOUNT
ID DISCOUNT_ID POSITION RULE_TYPE DAY_OF_WEEK
1 1 0 S NULL
RULE
START_TIME
NULL
END_TIME
NULL
SEQUENCE
1
2 1 1 S NULL NULL NULL 10
3 1 2 T 2 10:00 12:00 NULL
4 1 3 T 5 18:00 21:00 NULL
ID MOVIE_ID SEQUENCE SHOWING_TIME
1 1 7 2010-12-23 18:00
SHOWING
19 / 문서의 제목
어떻게 처리할 것인가 - 프로세스
20 / 문서의 제목
예매 처리 Service
<<interface>>
MovieDAO
<<interface>>
ReservationService
reserveShowing(customerId, showingId, audienceCount)
ReservationServiceImpl
reserveShowing(customerId, showingId, audienceCount)
<<interface>>
DiscountDAO
<<interface>>
RuleDAO
<<interface>>
ShowingDAO
<<interface>>
ReservationDAO
21 / 문서의 제목
데이터를 사용한 예매 프로세스 구현
@Override
public Reservation reserveShowing(int customerId, int showingId, int audienceCount) {
① 데이터베이스로부터 Movie와 Showing 정보 로딩
② 데이터베이스로부터 Rule 정보 로딩 후 Showig에 적용할 수 있는 Rule 이 있는지 판단
③ if (Rule 이 존재하면) {
Discount를 읽어 요금 할인된 요금 계산
} else {
Movie에 저장되어 있는 정액 요금 사용
}
④ Reservation 생성 후 데이터베이스 저장
}
Algorithm or Process
22 / 문서의 제목
데이터를 사용한 예매 프로세스 구현
@Override
public Reservation reserveShowing(int customerId, int showingId, int audienceCount) {
Showing showing = showingDAO.selectShowing(showingId);
Movie movie = movieDAO.selectMovie(showing.getMovieId());
② 데이터베이스로부터 Rule 정보 로딩 후 Showig에 적용할 수 있는 Rule 이 있는지 판단
③ if (Rule 이 존재하면) {
Discount를 읽어 요금 할인된 요금 계산
} else {
Movie에 저장되어 있는 정액 요금 사용
}
④ Reservation 생성 후 데이터베이스 저장
}
① 데이터베이스로부터 Movie와 Showing 정보 로딩
23 / 문서의 제목
데이터를 사용한 예매 프로세스 구현
@Override
public Reservation reserveShowing(int customerId, int showingId, int audienceCount) {
Showing showing = showingDAO.selectShowing(showingId);
Movie movie = movieDAO.selectMovie(showing.getMovieId());
Rule rule = findRule(showing, movie);
③ if (Rule 이 존재하면) {
Discount를 읽어 요금 할인된 요금 계산
} else {
Movie에 저장되어 있는 정액 요금 사용
}
④ Reservation 생성 후 데이터베이스 저장
}
private Rule findRule(Showing showing, Movie movie) {
for(Rule each : ruleDAO.selectRules(movie.getId())) {
if (each.isAccepted(showing, movie)) {
return each;
}
}
return null;
}
② 데이터베이스로부터 Rule 정보 로딩 후 Showig에 적용할 수 있는 Rule 이 있는지 판단
24 / 문서의 제목
데이터를 사용한 예매 프로세스 구현
@Override
public Reservation reserveShowing(int customerId, int showingId, int audienceCount) {
Showing showing = showingDAO.selectShowing(showingId);
Movie movie = movieDAO.selectMovie(showing.getMovieId());
Rule rule = findRule(showing, movie);
Money fee = movie.getFee();
if (rule != null) {
fee = calculateFee(movie);
}
④ Reservation 생성 후 데이터베이스 저장
}
③ if (Rule 이 존재하면) {
Discount를 읽어 요금 할인된 요금 계산
} else {
Movie에 저장되어 있는 정액 요금 사용
}
private Money calculateFee(Movie movie) {
Discount discount = discountDAO.selectDiscount(movie.getId());
if (discount.isAmountType()) {
return movie.getFee().minus(Money.wons(discount.getFee()));
} else if (discount.isPercentType()) {
return movie.getFee().minus(
movie.getFee().times(discount.getPercent()));
}
return movie.getFee();
}
25 / 문서의 제목
데이터를 사용한 예매 프로세스 구현
@Override
public Reservation reserveShowing(int customerId, int showingId, int audienceCount) {
Showing showing = showingDAO.selectShowing(showingId);
Movie movie = movieDAO.selectMovie(showing.getMovieId());
Rule rule = findRule(showing, movie);
Money fee = movie.getFee();
if (rule != null) {
fee = calculateFee(movie);
}
Reservation result = makeReservation(customerId, showingId, audienceCount, fee);
reservationDAO.insert(result);
return result;
}
④ Reservation 생성 후 데이터베이스 저장
private Reservation makeReservation(int customerId, int showingId,
int audienceCount, Money payment) {
Reservation result = new Reservation();
result.setCustomerId(customerId);
result.setShowingId(showingId);
result.setAudienceCount(audienceCount);
result.setFee(payment);
return result;
}
26 / 문서의 제목
중앙 집중식Centralized 제어 스타일
reserveShowing()
showing = selectShowing()
rules = selectRules()
isAccepted()*
discount = selectDiscount()
isAmountType()
getFee()
new
rules
:Rule
:Showing
DAO
showing
:Showing
:Reservation
Service
:Rule
DAO
:Discount
DAO
discount
:Discount
:Reservation
27 / 문서의 제목
아키텍처 패턴
Transaction Script
3. 책임-주도 설계
29 / 문서의 제목
책임Responsibility
30 / 문서의 제목
Showing
상영 정보를 알고 있다
예매 생성 책임
예매 생성에 필요한 정보의 EXPERT에게 할당Creator
예매 정보를 생성한다
31 / 문서의 제목
가격 계산 책임
영화 가격 정보를 알고 있는 EXPERT에 할당Information Expert
Showing
상영 정보를 알고 있다
예매 정보를 생성한다
Movie
Customer
Movie
영화정보를 알고 있다
가격을 계산한다
32 / 문서의 제목
Showing
상영 정보를 알고 있다
Movie
영화정보를 알고 있다 DiscountStrategy
할인율 계산 책임
할인율을 적용할 STRATEGY 객체 추가
DiscountStrategy
할인율 정책을 알고 있다
할인된 가격을 계산한다
예매 정보를 생성한다
Movie
Customer
가격을 계산한다
33 / 문서의 제목
Showing
상영 정보를 알고 있다
Movie
영화정보를 알고 있다 DiscountStrategy
DiscountStrategy
할인율 정책을 알고 있다
할인된 가격을 계산한다
예매 정보를 생성한다
Movie
Customer
가격을 계산한다
할인 여부를 판단할 책임
할인 정책을 판단하기 위한 SPECIFICATION 객체 추가
Rule
할인 정책을 알고 있다
할인 여부를 판단한다
Rule
Showing
34 / 문서의 제목
Rich Domain Model
Customer
Showing
reserve(customer, count):Reservation
Rule
isStatisfiedBy(showing):boolean
Reservation
AmountStrategy PercentStrategy NonDiscountStrategy SequenceRule TimeOfDayRule
DiscountStrategy
calculateFee(showing):Money
Movie
calculateFee(showing):Money
상속inheritance과 다형성polymorphism의 활용
<<create>>
35 / 문서의 제목
데이터에 대한 걱정은 잠시 꺼두셔도 좋습니다
36 / 문서의 제목
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);
}
}
책임 기반 구현
37 / 문서의 제목
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());
}
}
책임 기반 구현
38 / 문서의 제목
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));
}
}
39 / 문서의 제목
위임식delegated, 분산식dispersed 제어 스타일
:Reservation :Movie
reserve()
new
:Showing
calculateFee()
calculateFee()
:DiscountStrategy :Rule
calculateFee()
isStatisfied()*
40 / 문서의 제목
아키텍처 패턴
Domain Model
41 / 문서의 제목
Transaction Script의 단점
@Override
public Reservation reserveShowing(int customerId, int showingId, int audienceCount) {
Showing showing = showingDAO.selectShowing(showingId);
Movie movie = movieDAO.selectMovie(showing.getMovieId());
Rule rule = findRule(showing, movie);
Money fee = movie.getFee();
if (rule != null) {
fee = calculateFee(movie);
}
Reservation result = makeReservation(customerId, showingId, audienceCount, fee);
reservationDAO.insert(result);
return result;
}
private Money calculateFee(Movie movie) {
Discount discount = discountDAO.selectDiscount(movie.getId());
if (discount.isAmountType()) {
return movie.getFee().minus(Money.wons(discount.getFee()));
} else if (discount.isPercentType()) {
return movie.getFee().minus(
movie.getFee().times(discount.getPercent()));
}
return movie.getFee();
}
새로운 할인 정책 추가
42 / 문서의 제목
@Override
public Reservation reserveShowing(int customerId, int showingId, int audienceCount) {
Showing showing = showingDAO.selectShowing(showingId);
Movie movie = movieDAO.selectMovie(showing.getMovieId());
Rule rule = findRule(showing, movie);
Money fee = movie.getFee();
if (rule != null) {
fee = calculateFee(movie);
}
Reservation result = makeReservation(customerId, showingId, audienceCount, fee);
reservationDAO.insert(result);
return result;
}
private Money calculateFee(Movie movie) {
Discount discount = discountDAO.selectDiscount(movie.getId());
if (discount.isAmountType()) {
return movie.getFee().minus(Money.wons(discount.getFee()));
} else if (discount.isPercentType()) {
return movie.getFee().minus(
movie.getFee().times(discount.getPercent()));
} else if (discount.isMilleageType()) {
return movie.getFee().minus(
movie.getMileageBaseAmount().times(discount.getMileageFactor()));
}
return movie.getFee();
}
기졲 코드 수정
Transaction Script의 단점
43 / 문서의 제목
Rich Domain Model의 장점
Customer
Showing
reserve(customer, count):Reservation
Rule
isStatisfiedBy(showing):boolean
Reservation
AmountStrategy PercentStrategy NonDiscountStrategy SequenceRule TimeOfDayRule
DiscountStrategy
calculateFee(showing):Money
Movie
calculateFee(showing):Money
<<create>>
새로운 할인 정책 추가
44 / 문서의 제목
Rich Domain Model의 장점
Customer
Showing
reserve(customer, count):Reservation
Rule
isStatisfiedBy(showing):boolean
Reservation
AmountStrategy PercentStrategy NonDiscountStrategy SequenceRule TimeOfDayRule
DiscountStrategy
calculateFee(Showing):Money
Movie
calculateFee(showing):Money
<<create>>
MileageStrategy
OCPOpen-Closed Principle
4. 아키텍처 & 프레임워크
46 / 문서의 제목
Layered Architecture
User Interface
Service
Domain
Infrastructure
47 / 문서의 제목
도메인 레이어 캡슐화
48 / 문서의 제목
Layered Architecture
User Interface
Service
Domain
Infrastructure
49 / 문서의 제목
Service Layer
 애플리케이션 경계
 도메인 레이어의 재사용성 촉짂
<<interface>>
ReservationService
reserveShowing(customerId, showingId, audienceCount)
ReservationServiceImpl
reserveShowing(customerId, showingId, audienceCount)
<<interface>>
CustomerRepository
<<interface>>
ShowingRepository
<<interface>>
ReservationRepository
Showing
50 / 문서의 제목
Service Layer
 Operation Script
 Not Transaction Script
<<interface>>
ReservationService
reserveShowing(customerId, showingId, audienceCount)
ReservationServiceImpl
reserveShowing(customerId, showingId, audienceCount)
<<interface>>
CustomerRepository
<<interface>>
ShowingRepository
<<interface>>
ReservationRepository
Showing
@Override
@Transactional(propagation=Propagation.REQUIRED)
public Reservation reserveShowing(int reserverId, int showingId,
int audienceCount) {
Customer reserver = customerRepository.find(reserverId);
Showing showing = showingRepository.find(showingId);
Reservation reservation = showing.reserve(reserver, audienceCount);
reservationRepository.save(reservation);
return reservation;
}
51 / 문서의 제목
도메인 레이어 의졲성 관리
User Interface
Service
Domain
Infrastructure
52 / 문서의 제목
순수한 객체
POJO
Plain Old Java Object
53 / 문서의 제목
POJO의 3대 요소
Dependency
Injection
Aspect-Oriented
Programming
Annotation
54 / 문서의 제목
비침투적인Non-Intrusive 프레임워크
 POJO 개발을 위한 젂제조건
 Lightweight Framework
55 / 문서의 제목
Dependency Injection
 객체 간의 의졲성 관리 이슈로부터 도메인 레이어 보호
 구성-사용 분리 원리the principle of separating configuration from use
<<interface>>
ReservationService
reserveShowing(customerId, showingId, audienceCount)
ReservationServiceImpl
reserveShowing(customerId, showingId, audienceCount)
<<interface>>
CustomerRepository
CustomerRepositoryImpl
56 / 문서의 제목
Dependency Injection – Spring
<bean id="reservationService”
class="org.eternity.theater.reservation.ReservationServiceImpl">
<property name="customerRepository" ref="customerRepository"/>
......
</bean>
<bean id="customerRepository“
class="org.eternity.theater.customer.hibernate.CustomerRepositoryImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<<interface>>
ReservationService
reserveShowing(customerId, showingId, audienceCount)
ReservationServiceImpl
reserveShowing(customerId, showingId, audienceCount)
<<interface>>
CustomerRepository
CustomerRepositoryImpl
57 / 문서의 제목
Impedance Mismatch
 객체 모델과 DB 스키마 간의 불일치
 객체 모델과 DB 스키마 간의 변환 계층 필요
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
58 / 문서의 제목
DATA MAPPER
 객체 모델과 DB 스키마 간의 독립성 유지
 도메인 객체는 DB에 대해 독립적
RULE
ID
DISCOUNT_ID(FK)
POSITION
RULE_TYPE
DAY_OF_WEEK
START_TIME
END_TUME
SEQUENCE
Rule
SequenceRule TimeOfDayRule
RuleMapper
insert
Update
delete
59 / 문서의 제목
O/R MAPPER - Hibernate
<hibernate-mapping package="org.eternity.theater.movie.pricing"
default-access="field">
<class name="Rule" table="RULE">
<id name="id" column="ID" type="long">
<generator class="native"/>
</id>
<discriminator column="RULE_TYPE" type="string" />
<subclass name="SequenceRule" discriminator-value="S">
<property name="sequence" column="SEQUENCE" type="integer"/>
</subclass>
<subclass name="TimeOfDayRule" discriminator-value="A">
<property name="dayOfWeek" column="DAY_OF_WEEK" type="integer"/>
<property name="startTime" column="START_TIME"
type="org.eternity.support.hibernate.TimeOfDayUserType"/>
<property name="endTime" column="END_TIME"
type="org.eternity.support.hibernate.TimeOfDayUserType"/>
</subclass>
</class>
</hibernate-mapping>
RULE
ID
DISCOUNT_ID(FK)
POSITION
RULE_TYPE
DAY_OF_WEEK
START_TIME
END_TUME
SEQUENCE
Rule
SequenceRule TimeOfDayRule
60 / 문서의 제목
트랜잭션 경계
User Interface
Service
Domain
Infrastructure
Begin TX
Commit
Rollback
61 / 문서의 제목
AOPAspect Oriented Programming
User Interface
Service
Domain
Infrastructure
Begin TX
Commit
Rollback
ASPECT
62 / 문서의 제목
Spring AOP & Annotation
User Interface
Service
Domain
Infrastructure
Begin TX
Commit
Rollback
ASPECT
<tx:annotation-driven/>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
@Override
@Transactional(propagation=Propagation.REQUIRED)
public Reservation reserveShowing(int reserverId, int showingId, int audienceCount) {
Customer reserver = customerRepository.find(reserverId);
Showing showing = showingRepository.find(showingId);
Reservation reservation = showing.reserve(reserver, audienceCount);
reservationRepository.save(reservation);
return reservation;
}
5. 결롞
64 / 문서의 제목
Rich Domain Model
 설계 관점이지 기술 관점이 아님
 훌륭한 객체 지향 설계 지침을 따를 것
65 / 문서의 제목
그러나 기술적인 제약 사항 역시 중요
 비침투적인 프레임워크를 사용하라
 프레임워크의 제약 사항을 파악하라
 프레임워크의 제약 사항에 따라 구현 가능하도록 아키텍처를 수정하라
가지고 있는 도구 또한 아키텍처에 영향을 준다는 사실을 알 수 있다. 때로는 아키
텍처를 바탕으로 도구를 선택할 수 있으며, 이롞적으로는 그것이 올바른 방법이다.
그러나 실제로는 도구에 아키텍처를 맞추어야 한다.
- Martin Fowler
66 / 문서의 제목
Rich Domain Model을 자제해야 하는 경우
객체 지향 분석/설계 경험이 부족한 경우
비침투적인 프레임워크를 사용할 수 없는 경우
비침투적인 프레임워크에 대한 경험이 부족한 경우
O/R Mapper를 사용할 수 없는 경우
비즈니스 로직이 단순하고 개발 기간이 짧은 경우
67 / 문서의 제목
첨언
Be Pragmatic
Thank you.
Question.
70 / 문서의 제목
참고자료
- Patterns of Enterprise Application Architecture, Martin Fowler, Addison-Wesley, 2002
- Domain-Driven Design, Eric Evans, Addison-Wesley, 2003
- Expert One-on-One J2EE Development without EJB, Rod Johnson, Wrox, 2004
- Applying UML and Patterns 3rd Edition, Craig Larman, Prentice Hall, 2004
- Agile Software Development, Principles, Patterns, and Practices, Robert C. Martin,
Prentice Hall, 2002
- Object Design : Roles, Responsibilities, and Collaborations , Rebecca Wirfs-Brock,
Alan McKean, Addison-Wesley,2002
- POJOs in Action, Chris Richardson, Manning, 2006
- Java Persistence with Hibernate, Christian Bauer, Gavin King, Manning, 2006
- Spring in Action 2nd Edition, Craig Walls, Manning, 2007
- The New Holy Trinity, Ramnivas Laddad,
http://www.aspectprogrammer.org/blogs/adrian/2005/03/the_new_holy_tr.html

Más contenido relacionado

La actualidad más candente

mongodb와 mysql의 CRUD 연산의 성능 비교
mongodb와 mysql의 CRUD 연산의 성능 비교mongodb와 mysql의 CRUD 연산의 성능 비교
mongodb와 mysql의 CRUD 연산의 성능 비교
Woo Yeong Choi
 
아마존 웹 서비스 상에서 MS SQL 100% 활용하기::김석원::AWS Summit Seoul 2018
아마존 웹 서비스 상에서 MS SQL 100% 활용하기::김석원::AWS Summit Seoul 2018아마존 웹 서비스 상에서 MS SQL 100% 활용하기::김석원::AWS Summit Seoul 2018
아마존 웹 서비스 상에서 MS SQL 100% 활용하기::김석원::AWS Summit Seoul 2018
Amazon Web Services Korea
 

La actualidad más candente (20)

이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정
 
우아한 객체지향
우아한 객체지향우아한 객체지향
우아한 객체지향
 
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
 
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다
잘 키운 모노리스 하나 열 마이크로서비스 안 부럽다
 
카카오 광고 플랫폼 MSA 적용 사례 및 API Gateway와 인증 구현에 대한 소개
카카오 광고 플랫폼 MSA 적용 사례 및 API Gateway와 인증 구현에 대한 소개카카오 광고 플랫폼 MSA 적용 사례 및 API Gateway와 인증 구현에 대한 소개
카카오 광고 플랫폼 MSA 적용 사례 및 API Gateway와 인증 구현에 대한 소개
 
도메인구현 KSUG 20151128
도메인구현 KSUG 20151128도메인구현 KSUG 20151128
도메인구현 KSUG 20151128
 
우아한 모노리스
우아한 모노리스우아한 모노리스
우아한 모노리스
 
[오픈소스컨설팅]쿠버네티스를 활용한 개발환경 구축
[오픈소스컨설팅]쿠버네티스를 활용한 개발환경 구축[오픈소스컨설팅]쿠버네티스를 활용한 개발환경 구축
[오픈소스컨설팅]쿠버네티스를 활용한 개발환경 구축
 
[236] 카카오의데이터파이프라인 윤도영
[236] 카카오의데이터파이프라인 윤도영[236] 카카오의데이터파이프라인 윤도영
[236] 카카오의데이터파이프라인 윤도영
 
webservice scaling for newbie
webservice scaling for newbiewebservice scaling for newbie
webservice scaling for newbie
 
Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄
 
Jpa 잘 (하는 척) 하기
Jpa 잘 (하는 척) 하기Jpa 잘 (하는 척) 하기
Jpa 잘 (하는 척) 하기
 
도메인 주도 설계 (Domain Driven Design)
도메인 주도 설계 (Domain Driven Design)도메인 주도 설계 (Domain Driven Design)
도메인 주도 설계 (Domain Driven Design)
 
mongodb와 mysql의 CRUD 연산의 성능 비교
mongodb와 mysql의 CRUD 연산의 성능 비교mongodb와 mysql의 CRUD 연산의 성능 비교
mongodb와 mysql의 CRUD 연산의 성능 비교
 
DDD로 복잡함 다루기
DDD로 복잡함 다루기DDD로 복잡함 다루기
DDD로 복잡함 다루기
 
점진적인 레거시 웹 애플리케이션 개선 과정
점진적인 레거시 웹 애플리케이션 개선 과정점진적인 레거시 웹 애플리케이션 개선 과정
점진적인 레거시 웹 애플리케이션 개선 과정
 
도커 무작정 따라하기: 도커가 처음인 사람도 60분이면 웹 서버를 올릴 수 있습니다!
도커 무작정 따라하기: 도커가 처음인 사람도 60분이면 웹 서버를 올릴 수 있습니다!도커 무작정 따라하기: 도커가 처음인 사람도 60분이면 웹 서버를 올릴 수 있습니다!
도커 무작정 따라하기: 도커가 처음인 사람도 60분이면 웹 서버를 올릴 수 있습니다!
 
마이크로서비스 기반 클라우드 아키텍처 구성 모범 사례 - 윤석찬 (AWS 테크에반젤리스트)
마이크로서비스 기반 클라우드 아키텍처 구성 모범 사례 - 윤석찬 (AWS 테크에반젤리스트) 마이크로서비스 기반 클라우드 아키텍처 구성 모범 사례 - 윤석찬 (AWS 테크에반젤리스트)
마이크로서비스 기반 클라우드 아키텍처 구성 모범 사례 - 윤석찬 (AWS 테크에반젤리스트)
 
Ksug2015 - JPA3, JPA 내부구조
Ksug2015 - JPA3, JPA 내부구조Ksug2015 - JPA3, JPA 내부구조
Ksug2015 - JPA3, JPA 내부구조
 
아마존 웹 서비스 상에서 MS SQL 100% 활용하기::김석원::AWS Summit Seoul 2018
아마존 웹 서비스 상에서 MS SQL 100% 활용하기::김석원::AWS Summit Seoul 2018아마존 웹 서비스 상에서 MS SQL 100% 활용하기::김석원::AWS Summit Seoul 2018
아마존 웹 서비스 상에서 MS SQL 100% 활용하기::김석원::AWS Summit Seoul 2018
 

Similar a Rich domain model

A6 객체지향적인 도메인 레이어 구축하기
A6 객체지향적인 도메인 레이어 구축하기A6 객체지향적인 도메인 레이어 구축하기
A6 객체지향적인 도메인 레이어 구축하기
NAVER D2
 
[Td 2015]치즈케이크 팩토리는 알겠는데, 데이터 팩토리는 뭔가요(한기환)
[Td 2015]치즈케이크 팩토리는 알겠는데, 데이터 팩토리는 뭔가요(한기환)[Td 2015]치즈케이크 팩토리는 알겠는데, 데이터 팩토리는 뭔가요(한기환)
[Td 2015]치즈케이크 팩토리는 알겠는데, 데이터 팩토리는 뭔가요(한기환)
Sang Don Kim
 
실전 프로젝트로 이야기하는 AWS IoT::김민성::AWS Summit Seoul 2018
실전 프로젝트로 이야기하는 AWS IoT::김민성::AWS Summit Seoul 2018실전 프로젝트로 이야기하는 AWS IoT::김민성::AWS Summit Seoul 2018
실전 프로젝트로 이야기하는 AWS IoT::김민성::AWS Summit Seoul 2018
Amazon Web Services Korea
 
프로그래밍 패러다임의 진화 및 Spring의 금융권 적용
프로그래밍 패러다임의 진화 및 Spring의 금융권 적용프로그래밍 패러다임의 진화 및 Spring의 금융권 적용
프로그래밍 패러다임의 진화 및 Spring의 금융권 적용
중선 곽
 

Similar a Rich domain model (19)

A6 객체지향적인 도메인 레이어 구축하기
A6 객체지향적인 도메인 레이어 구축하기A6 객체지향적인 도메인 레이어 구축하기
A6 객체지향적인 도메인 레이어 구축하기
 
What's new in IE11
What's new in IE11What's new in IE11
What's new in IE11
 
[Td 2015]치즈케이크 팩토리는 알겠는데, 데이터 팩토리는 뭔가요(한기환)
[Td 2015]치즈케이크 팩토리는 알겠는데, 데이터 팩토리는 뭔가요(한기환)[Td 2015]치즈케이크 팩토리는 알겠는데, 데이터 팩토리는 뭔가요(한기환)
[Td 2015]치즈케이크 팩토리는 알겠는데, 데이터 팩토리는 뭔가요(한기환)
 
Web applications that analyze used smartphone prices
Web applications that analyze used smartphone pricesWeb applications that analyze used smartphone prices
Web applications that analyze used smartphone prices
 
실전 프로젝트로 이야기하는 AWS IoT::김민성::AWS Summit Seoul 2018
실전 프로젝트로 이야기하는 AWS IoT::김민성::AWS Summit Seoul 2018실전 프로젝트로 이야기하는 AWS IoT::김민성::AWS Summit Seoul 2018
실전 프로젝트로 이야기하는 AWS IoT::김민성::AWS Summit Seoul 2018
 
주가 정보 다루기.pdf
주가 정보 다루기.pdf주가 정보 다루기.pdf
주가 정보 다루기.pdf
 
[패스트캠퍼스]해외 영화의 매출액 예측하기
[패스트캠퍼스]해외 영화의 매출액 예측하기[패스트캠퍼스]해외 영화의 매출액 예측하기
[패스트캠퍼스]해외 영화의 매출액 예측하기
 
한국투자증권의 디지털 플랫폼 구현 사례.pdf
한국투자증권의 디지털 플랫폼 구현 사례.pdf한국투자증권의 디지털 플랫폼 구현 사례.pdf
한국투자증권의 디지털 플랫폼 구현 사례.pdf
 
20140528 AWS Meister BlackBelt - Amazon Kinesis (Korean)
20140528 AWS Meister BlackBelt - Amazon Kinesis (Korean)20140528 AWS Meister BlackBelt - Amazon Kinesis (Korean)
20140528 AWS Meister BlackBelt - Amazon Kinesis (Korean)
 
9조 발표
9조 발표9조 발표
9조 발표
 
제 15회 보아즈(BOAZ) 빅데이터 컨퍼런스 - [YouPlace 팀] : 카프카와 스파크를 활용한 유튜브 영상 속 제주 명소 검색
제 15회 보아즈(BOAZ) 빅데이터 컨퍼런스 - [YouPlace 팀] : 카프카와 스파크를 활용한 유튜브 영상 속 제주 명소 검색 제 15회 보아즈(BOAZ) 빅데이터 컨퍼런스 - [YouPlace 팀] : 카프카와 스파크를 활용한 유튜브 영상 속 제주 명소 검색
제 15회 보아즈(BOAZ) 빅데이터 컨퍼런스 - [YouPlace 팀] : 카프카와 스파크를 활용한 유튜브 영상 속 제주 명소 검색
 
AWS Summit Seoul 2023 | 갤럭시 규모의 서비스를 위한 Amazon DynamoDB의 역할과 비용 최적화 방법
AWS Summit Seoul 2023 | 갤럭시 규모의 서비스를 위한 Amazon DynamoDB의 역할과 비용 최적화 방법AWS Summit Seoul 2023 | 갤럭시 규모의 서비스를 위한 Amazon DynamoDB의 역할과 비용 최적화 방법
AWS Summit Seoul 2023 | 갤럭시 규모의 서비스를 위한 Amazon DynamoDB의 역할과 비용 최적화 방법
 
Refactoring_1_4
Refactoring_1_4Refactoring_1_4
Refactoring_1_4
 
Test driven development short lesson
Test driven development   short lessonTest driven development   short lesson
Test driven development short lesson
 
알아봅시다, Polymer: Web Components & Web Animations
알아봅시다, Polymer: Web Components & Web Animations알아봅시다, Polymer: Web Components & Web Animations
알아봅시다, Polymer: Web Components & Web Animations
 
Swt J Face 2/3
Swt J Face 2/3Swt J Face 2/3
Swt J Face 2/3
 
꿀밋업2탄_도메인 모델에 따른 데이터 분리 저장과 API 연결
꿀밋업2탄_도메인 모델에 따른 데이터 분리 저장과 API 연결꿀밋업2탄_도메인 모델에 따른 데이터 분리 저장과 API 연결
꿀밋업2탄_도메인 모델에 따른 데이터 분리 저장과 API 연결
 
AWS Finance Symposium_SBI 저축은행 사례 공유
AWS Finance Symposium_SBI 저축은행 사례 공유AWS Finance Symposium_SBI 저축은행 사례 공유
AWS Finance Symposium_SBI 저축은행 사례 공유
 
프로그래밍 패러다임의 진화 및 Spring의 금융권 적용
프로그래밍 패러다임의 진화 및 Spring의 금융권 적용프로그래밍 패러다임의 진화 및 Spring의 금융권 적용
프로그래밍 패러다임의 진화 및 Spring의 금융권 적용
 

Más de 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
 
[JWAP-2] DI & Spring
[JWAP-2] DI & Spring[JWAP-2] DI & Spring
[JWAP-2] DI & Spring
Young-Ho Cho
 
[PreSchool-1] 프로그래밍 '개념' 맛보기
[PreSchool-1] 프로그래밍 '개념' 맛보기[PreSchool-1] 프로그래밍 '개념' 맛보기
[PreSchool-1] 프로그래밍 '개념' 맛보기
Young-Ho Cho
 

Más de Young-Ho Cho (11)

[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
 
[JWAP-2] DI & Spring
[JWAP-2] DI & Spring[JWAP-2] DI & Spring
[JWAP-2] DI & Spring
 
[NEXT 프연 Week1] Git 시작하기
[NEXT 프연 Week1] Git 시작하기[NEXT 프연 Week1] Git 시작하기
[NEXT 프연 Week1] Git 시작하기
 
[JWPA-1]의존성 주입(Dependency injection)
[JWPA-1]의존성 주입(Dependency injection)[JWPA-1]의존성 주입(Dependency injection)
[JWPA-1]의존성 주입(Dependency injection)
 
[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] 프로그래밍 '개념' 맛보기
 

Rich domain model

  • 1. Object-Oriented Design & Architecture Rich Domain Model 조영호 Eternity’s Chit-Chat http://aeternum.egloos.com
  • 2. 2. 데이터-지향 설계 3. 책임-주도 설계 목차 4. 아키텍처 & 프레임워크 1. 영화 예매 시스템 도메인 5. 결롞
  • 3. 1. 영화 예매 시스템 도메인
  • 4. 4 / 문서의 제목 온라인 영화 예매 시스템
  • 5. 5 / 문서의 제목 Domain Concept - 영화 Movie
  • 6. 6 / 문서의 제목 Domain Concept - 상영 2010-10-20 09:30 조조 Showing 2010-10-21 20:30 5회 2010-12-01 14:20 4회
  • 7. 7 / 문서의 제목 Domain Concept – 할인 정책 Discount Amount Discount Percent Discount 8,000 - 800 = 7,200 8,000 – (8,000 * 0.1) = 7,200
  • 8. 8 / 문서의 제목 Domain Concept – 할인 규칙 Rule Sequence Rule Time Rule 조조 상영인 경우 월요일 10:00 ~ 12:00 상영인 경우 목요일 18:00 ~ 21:00 상영인 경우 10회 상영인 경우
  • 9. 9 / 문서의 제목 Domain Concept –할인 정책 + 할인 규칙 Movie Discount Rule 1 0..1 1 1..*
  • 10. 10 / 문서의 제목 10회 상영인 경우 Domain Concept –할인 정책 + 할인 규칙 Movie Discount Rule 1 0..1 1 1..* 이끼 8000원 Amount DC 800원 조조 상영인 경우 월요일 10:00 ~ 12:00 상영인 경우 목요일 18:00 ~ 21:00 상영인 경우
  • 11. 11 / 문서의 제목 10회 상영인 경우 Domain Concept –할인 적용 이끼 8000원 Amount DC 800원 조조 상영인 경우 월요일 10:00 ~ 12:00 상영인 경우 목요일 18:00 ~ 21:00 상영인 경우 상영정보 2010년 12월 23일 목요일 18:00 ~ 20:00(7회차)
  • 12. 12 / 문서의 제목 10회 상영인 경우 Domain Concept –할인 적용 이끼 8000원 Amount DC 800원 조조 상영인 경우 월요일 10:00 ~ 12:00 상영인 경우 목요일 18:00 ~ 21:00 상영인 경우 상영정보 2010년 12월 23일 목요일 18:00 ~ 20:00(7회차) 7,200
  • 13. 13 / 문서의 제목 Domain Concept –예매 Reservation 이끼 2010년 12월 23일 (목) 7회 6:00(오후) – 8:00(오후) 2명 16,000원 14,400원 제 목 상영 정보 인 원 정 가 결재 금액
  • 15. 15 / 문서의 제목 무엇을 저장할 것인가 - 데이터
  • 16. 16 / 문서의 제목 데이터 모델 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 SHOWING ID MOVIE_ID(FK) SEQUENCE SHOWING_TIME CUSTOMER ID CUSTOMER_ID NAME
  • 17. 17 / 문서의 제목 또 다른 데이터 표현 – Anemic Domain Model Movie id title runningTime fee Reservation id customerId showingId Amounr audienceCount Rule id discountId position ruleType dayOfWeek startTime endTime sequence Discount movieId discountType amount percent Showing id movieId sequence showingTime Customer Id customerId name
  • 18. 18 / 문서의 제목 초기 데이터 ID TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY 1 이끼 120 8000 KRW MOVIE MOVIE_ID DISCOUNTYPE FEE_AMOUNT FEE_ACURRENCY PERCENT 1 A 800 KRW NULL DISCOUNT ID DISCOUNT_ID POSITION RULE_TYPE DAY_OF_WEEK 1 1 0 S NULL RULE START_TIME NULL END_TIME NULL SEQUENCE 1 2 1 1 S NULL NULL NULL 10 3 1 2 T 2 10:00 12:00 NULL 4 1 3 T 5 18:00 21:00 NULL ID MOVIE_ID SEQUENCE SHOWING_TIME 1 1 7 2010-12-23 18:00 SHOWING
  • 19. 19 / 문서의 제목 어떻게 처리할 것인가 - 프로세스
  • 20. 20 / 문서의 제목 예매 처리 Service <<interface>> MovieDAO <<interface>> ReservationService reserveShowing(customerId, showingId, audienceCount) ReservationServiceImpl reserveShowing(customerId, showingId, audienceCount) <<interface>> DiscountDAO <<interface>> RuleDAO <<interface>> ShowingDAO <<interface>> ReservationDAO
  • 21. 21 / 문서의 제목 데이터를 사용한 예매 프로세스 구현 @Override public Reservation reserveShowing(int customerId, int showingId, int audienceCount) { ① 데이터베이스로부터 Movie와 Showing 정보 로딩 ② 데이터베이스로부터 Rule 정보 로딩 후 Showig에 적용할 수 있는 Rule 이 있는지 판단 ③ if (Rule 이 존재하면) { Discount를 읽어 요금 할인된 요금 계산 } else { Movie에 저장되어 있는 정액 요금 사용 } ④ Reservation 생성 후 데이터베이스 저장 } Algorithm or Process
  • 22. 22 / 문서의 제목 데이터를 사용한 예매 프로세스 구현 @Override public Reservation reserveShowing(int customerId, int showingId, int audienceCount) { Showing showing = showingDAO.selectShowing(showingId); Movie movie = movieDAO.selectMovie(showing.getMovieId()); ② 데이터베이스로부터 Rule 정보 로딩 후 Showig에 적용할 수 있는 Rule 이 있는지 판단 ③ if (Rule 이 존재하면) { Discount를 읽어 요금 할인된 요금 계산 } else { Movie에 저장되어 있는 정액 요금 사용 } ④ Reservation 생성 후 데이터베이스 저장 } ① 데이터베이스로부터 Movie와 Showing 정보 로딩
  • 23. 23 / 문서의 제목 데이터를 사용한 예매 프로세스 구현 @Override public Reservation reserveShowing(int customerId, int showingId, int audienceCount) { Showing showing = showingDAO.selectShowing(showingId); Movie movie = movieDAO.selectMovie(showing.getMovieId()); Rule rule = findRule(showing, movie); ③ if (Rule 이 존재하면) { Discount를 읽어 요금 할인된 요금 계산 } else { Movie에 저장되어 있는 정액 요금 사용 } ④ Reservation 생성 후 데이터베이스 저장 } private Rule findRule(Showing showing, Movie movie) { for(Rule each : ruleDAO.selectRules(movie.getId())) { if (each.isAccepted(showing, movie)) { return each; } } return null; } ② 데이터베이스로부터 Rule 정보 로딩 후 Showig에 적용할 수 있는 Rule 이 있는지 판단
  • 24. 24 / 문서의 제목 데이터를 사용한 예매 프로세스 구현 @Override public Reservation reserveShowing(int customerId, int showingId, int audienceCount) { Showing showing = showingDAO.selectShowing(showingId); Movie movie = movieDAO.selectMovie(showing.getMovieId()); Rule rule = findRule(showing, movie); Money fee = movie.getFee(); if (rule != null) { fee = calculateFee(movie); } ④ Reservation 생성 후 데이터베이스 저장 } ③ if (Rule 이 존재하면) { Discount를 읽어 요금 할인된 요금 계산 } else { Movie에 저장되어 있는 정액 요금 사용 } private Money calculateFee(Movie movie) { Discount discount = discountDAO.selectDiscount(movie.getId()); if (discount.isAmountType()) { return movie.getFee().minus(Money.wons(discount.getFee())); } else if (discount.isPercentType()) { return movie.getFee().minus( movie.getFee().times(discount.getPercent())); } return movie.getFee(); }
  • 25. 25 / 문서의 제목 데이터를 사용한 예매 프로세스 구현 @Override public Reservation reserveShowing(int customerId, int showingId, int audienceCount) { Showing showing = showingDAO.selectShowing(showingId); Movie movie = movieDAO.selectMovie(showing.getMovieId()); Rule rule = findRule(showing, movie); Money fee = movie.getFee(); if (rule != null) { fee = calculateFee(movie); } Reservation result = makeReservation(customerId, showingId, audienceCount, fee); reservationDAO.insert(result); return result; } ④ Reservation 생성 후 데이터베이스 저장 private Reservation makeReservation(int customerId, int showingId, int audienceCount, Money payment) { Reservation result = new Reservation(); result.setCustomerId(customerId); result.setShowingId(showingId); result.setAudienceCount(audienceCount); result.setFee(payment); return result; }
  • 26. 26 / 문서의 제목 중앙 집중식Centralized 제어 스타일 reserveShowing() showing = selectShowing() rules = selectRules() isAccepted()* discount = selectDiscount() isAmountType() getFee() new rules :Rule :Showing DAO showing :Showing :Reservation Service :Rule DAO :Discount DAO discount :Discount :Reservation
  • 27. 27 / 문서의 제목 아키텍처 패턴 Transaction Script
  • 29. 29 / 문서의 제목 책임Responsibility
  • 30. 30 / 문서의 제목 Showing 상영 정보를 알고 있다 예매 생성 책임 예매 생성에 필요한 정보의 EXPERT에게 할당Creator 예매 정보를 생성한다
  • 31. 31 / 문서의 제목 가격 계산 책임 영화 가격 정보를 알고 있는 EXPERT에 할당Information Expert Showing 상영 정보를 알고 있다 예매 정보를 생성한다 Movie Customer Movie 영화정보를 알고 있다 가격을 계산한다
  • 32. 32 / 문서의 제목 Showing 상영 정보를 알고 있다 Movie 영화정보를 알고 있다 DiscountStrategy 할인율 계산 책임 할인율을 적용할 STRATEGY 객체 추가 DiscountStrategy 할인율 정책을 알고 있다 할인된 가격을 계산한다 예매 정보를 생성한다 Movie Customer 가격을 계산한다
  • 33. 33 / 문서의 제목 Showing 상영 정보를 알고 있다 Movie 영화정보를 알고 있다 DiscountStrategy DiscountStrategy 할인율 정책을 알고 있다 할인된 가격을 계산한다 예매 정보를 생성한다 Movie Customer 가격을 계산한다 할인 여부를 판단할 책임 할인 정책을 판단하기 위한 SPECIFICATION 객체 추가 Rule 할인 정책을 알고 있다 할인 여부를 판단한다 Rule Showing
  • 34. 34 / 문서의 제목 Rich Domain Model Customer Showing reserve(customer, count):Reservation Rule isStatisfiedBy(showing):boolean Reservation AmountStrategy PercentStrategy NonDiscountStrategy SequenceRule TimeOfDayRule DiscountStrategy calculateFee(showing):Money Movie calculateFee(showing):Money 상속inheritance과 다형성polymorphism의 활용 <<create>>
  • 35. 35 / 문서의 제목 데이터에 대한 걱정은 잠시 꺼두셔도 좋습니다
  • 36. 36 / 문서의 제목 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); } } 책임 기반 구현
  • 37. 37 / 문서의 제목 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()); } } 책임 기반 구현
  • 38. 38 / 문서의 제목 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)); } }
  • 39. 39 / 문서의 제목 위임식delegated, 분산식dispersed 제어 스타일 :Reservation :Movie reserve() new :Showing calculateFee() calculateFee() :DiscountStrategy :Rule calculateFee() isStatisfied()*
  • 40. 40 / 문서의 제목 아키텍처 패턴 Domain Model
  • 41. 41 / 문서의 제목 Transaction Script의 단점 @Override public Reservation reserveShowing(int customerId, int showingId, int audienceCount) { Showing showing = showingDAO.selectShowing(showingId); Movie movie = movieDAO.selectMovie(showing.getMovieId()); Rule rule = findRule(showing, movie); Money fee = movie.getFee(); if (rule != null) { fee = calculateFee(movie); } Reservation result = makeReservation(customerId, showingId, audienceCount, fee); reservationDAO.insert(result); return result; } private Money calculateFee(Movie movie) { Discount discount = discountDAO.selectDiscount(movie.getId()); if (discount.isAmountType()) { return movie.getFee().minus(Money.wons(discount.getFee())); } else if (discount.isPercentType()) { return movie.getFee().minus( movie.getFee().times(discount.getPercent())); } return movie.getFee(); } 새로운 할인 정책 추가
  • 42. 42 / 문서의 제목 @Override public Reservation reserveShowing(int customerId, int showingId, int audienceCount) { Showing showing = showingDAO.selectShowing(showingId); Movie movie = movieDAO.selectMovie(showing.getMovieId()); Rule rule = findRule(showing, movie); Money fee = movie.getFee(); if (rule != null) { fee = calculateFee(movie); } Reservation result = makeReservation(customerId, showingId, audienceCount, fee); reservationDAO.insert(result); return result; } private Money calculateFee(Movie movie) { Discount discount = discountDAO.selectDiscount(movie.getId()); if (discount.isAmountType()) { return movie.getFee().minus(Money.wons(discount.getFee())); } else if (discount.isPercentType()) { return movie.getFee().minus( movie.getFee().times(discount.getPercent())); } else if (discount.isMilleageType()) { return movie.getFee().minus( movie.getMileageBaseAmount().times(discount.getMileageFactor())); } return movie.getFee(); } 기졲 코드 수정 Transaction Script의 단점
  • 43. 43 / 문서의 제목 Rich Domain Model의 장점 Customer Showing reserve(customer, count):Reservation Rule isStatisfiedBy(showing):boolean Reservation AmountStrategy PercentStrategy NonDiscountStrategy SequenceRule TimeOfDayRule DiscountStrategy calculateFee(showing):Money Movie calculateFee(showing):Money <<create>> 새로운 할인 정책 추가
  • 44. 44 / 문서의 제목 Rich Domain Model의 장점 Customer Showing reserve(customer, count):Reservation Rule isStatisfiedBy(showing):boolean Reservation AmountStrategy PercentStrategy NonDiscountStrategy SequenceRule TimeOfDayRule DiscountStrategy calculateFee(Showing):Money Movie calculateFee(showing):Money <<create>> MileageStrategy OCPOpen-Closed Principle
  • 45. 4. 아키텍처 & 프레임워크
  • 46. 46 / 문서의 제목 Layered Architecture User Interface Service Domain Infrastructure
  • 47. 47 / 문서의 제목 도메인 레이어 캡슐화
  • 48. 48 / 문서의 제목 Layered Architecture User Interface Service Domain Infrastructure
  • 49. 49 / 문서의 제목 Service Layer  애플리케이션 경계  도메인 레이어의 재사용성 촉짂 <<interface>> ReservationService reserveShowing(customerId, showingId, audienceCount) ReservationServiceImpl reserveShowing(customerId, showingId, audienceCount) <<interface>> CustomerRepository <<interface>> ShowingRepository <<interface>> ReservationRepository Showing
  • 50. 50 / 문서의 제목 Service Layer  Operation Script  Not Transaction Script <<interface>> ReservationService reserveShowing(customerId, showingId, audienceCount) ReservationServiceImpl reserveShowing(customerId, showingId, audienceCount) <<interface>> CustomerRepository <<interface>> ShowingRepository <<interface>> ReservationRepository Showing @Override @Transactional(propagation=Propagation.REQUIRED) public Reservation reserveShowing(int reserverId, int showingId, int audienceCount) { Customer reserver = customerRepository.find(reserverId); Showing showing = showingRepository.find(showingId); Reservation reservation = showing.reserve(reserver, audienceCount); reservationRepository.save(reservation); return reservation; }
  • 51. 51 / 문서의 제목 도메인 레이어 의졲성 관리 User Interface Service Domain Infrastructure
  • 52. 52 / 문서의 제목 순수한 객체 POJO Plain Old Java Object
  • 53. 53 / 문서의 제목 POJO의 3대 요소 Dependency Injection Aspect-Oriented Programming Annotation
  • 54. 54 / 문서의 제목 비침투적인Non-Intrusive 프레임워크  POJO 개발을 위한 젂제조건  Lightweight Framework
  • 55. 55 / 문서의 제목 Dependency Injection  객체 간의 의졲성 관리 이슈로부터 도메인 레이어 보호  구성-사용 분리 원리the principle of separating configuration from use <<interface>> ReservationService reserveShowing(customerId, showingId, audienceCount) ReservationServiceImpl reserveShowing(customerId, showingId, audienceCount) <<interface>> CustomerRepository CustomerRepositoryImpl
  • 56. 56 / 문서의 제목 Dependency Injection – Spring <bean id="reservationService” class="org.eternity.theater.reservation.ReservationServiceImpl"> <property name="customerRepository" ref="customerRepository"/> ...... </bean> <bean id="customerRepository“ class="org.eternity.theater.customer.hibernate.CustomerRepositoryImpl"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <<interface>> ReservationService reserveShowing(customerId, showingId, audienceCount) ReservationServiceImpl reserveShowing(customerId, showingId, audienceCount) <<interface>> CustomerRepository CustomerRepositoryImpl
  • 57. 57 / 문서의 제목 Impedance Mismatch  객체 모델과 DB 스키마 간의 불일치  객체 모델과 DB 스키마 간의 변환 계층 필요 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
  • 58. 58 / 문서의 제목 DATA MAPPER  객체 모델과 DB 스키마 간의 독립성 유지  도메인 객체는 DB에 대해 독립적 RULE ID DISCOUNT_ID(FK) POSITION RULE_TYPE DAY_OF_WEEK START_TIME END_TUME SEQUENCE Rule SequenceRule TimeOfDayRule RuleMapper insert Update delete
  • 59. 59 / 문서의 제목 O/R MAPPER - Hibernate <hibernate-mapping package="org.eternity.theater.movie.pricing" default-access="field"> <class name="Rule" table="RULE"> <id name="id" column="ID" type="long"> <generator class="native"/> </id> <discriminator column="RULE_TYPE" type="string" /> <subclass name="SequenceRule" discriminator-value="S"> <property name="sequence" column="SEQUENCE" type="integer"/> </subclass> <subclass name="TimeOfDayRule" discriminator-value="A"> <property name="dayOfWeek" column="DAY_OF_WEEK" type="integer"/> <property name="startTime" column="START_TIME" type="org.eternity.support.hibernate.TimeOfDayUserType"/> <property name="endTime" column="END_TIME" type="org.eternity.support.hibernate.TimeOfDayUserType"/> </subclass> </class> </hibernate-mapping> RULE ID DISCOUNT_ID(FK) POSITION RULE_TYPE DAY_OF_WEEK START_TIME END_TUME SEQUENCE Rule SequenceRule TimeOfDayRule
  • 60. 60 / 문서의 제목 트랜잭션 경계 User Interface Service Domain Infrastructure Begin TX Commit Rollback
  • 61. 61 / 문서의 제목 AOPAspect Oriented Programming User Interface Service Domain Infrastructure Begin TX Commit Rollback ASPECT
  • 62. 62 / 문서의 제목 Spring AOP & Annotation User Interface Service Domain Infrastructure Begin TX Commit Rollback ASPECT <tx:annotation-driven/> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> @Override @Transactional(propagation=Propagation.REQUIRED) public Reservation reserveShowing(int reserverId, int showingId, int audienceCount) { Customer reserver = customerRepository.find(reserverId); Showing showing = showingRepository.find(showingId); Reservation reservation = showing.reserve(reserver, audienceCount); reservationRepository.save(reservation); return reservation; }
  • 64. 64 / 문서의 제목 Rich Domain Model  설계 관점이지 기술 관점이 아님  훌륭한 객체 지향 설계 지침을 따를 것
  • 65. 65 / 문서의 제목 그러나 기술적인 제약 사항 역시 중요  비침투적인 프레임워크를 사용하라  프레임워크의 제약 사항을 파악하라  프레임워크의 제약 사항에 따라 구현 가능하도록 아키텍처를 수정하라 가지고 있는 도구 또한 아키텍처에 영향을 준다는 사실을 알 수 있다. 때로는 아키 텍처를 바탕으로 도구를 선택할 수 있으며, 이롞적으로는 그것이 올바른 방법이다. 그러나 실제로는 도구에 아키텍처를 맞추어야 한다. - Martin Fowler
  • 66. 66 / 문서의 제목 Rich Domain Model을 자제해야 하는 경우 객체 지향 분석/설계 경험이 부족한 경우 비침투적인 프레임워크를 사용할 수 없는 경우 비침투적인 프레임워크에 대한 경험이 부족한 경우 O/R Mapper를 사용할 수 없는 경우 비즈니스 로직이 단순하고 개발 기간이 짧은 경우
  • 67. 67 / 문서의 제목 첨언 Be Pragmatic
  • 70. 70 / 문서의 제목 참고자료 - Patterns of Enterprise Application Architecture, Martin Fowler, Addison-Wesley, 2002 - Domain-Driven Design, Eric Evans, Addison-Wesley, 2003 - Expert One-on-One J2EE Development without EJB, Rod Johnson, Wrox, 2004 - Applying UML and Patterns 3rd Edition, Craig Larman, Prentice Hall, 2004 - Agile Software Development, Principles, Patterns, and Practices, Robert C. Martin, Prentice Hall, 2002 - Object Design : Roles, Responsibilities, and Collaborations , Rebecca Wirfs-Brock, Alan McKean, Addison-Wesley,2002 - POJOs in Action, Chris Richardson, Manning, 2006 - Java Persistence with Hibernate, Christian Bauer, Gavin King, Manning, 2006 - Spring in Action 2nd Edition, Craig Walls, Manning, 2007 - The New Holy Trinity, Ramnivas Laddad, http://www.aspectprogrammer.org/blogs/adrian/2005/03/the_new_holy_tr.html