SlideShare a Scribd company logo
1 of 78
Download to read offline
몇 가지
도메인 구현 이야기
최범균(madvirus@madvirus.net),	
  2015-­‐11-­‐28
내용
• DIP
• AGGREGATE과 참조
• CQRS
• 이벤트
2
#1, 아키텍처와 DIP
3
흔한 구조
ReserveService JavaMailService
Reservation Reservation
Repository
4
인프라
스트럭처
도메인
impl
패키지
응용
모듈 구조
ReserveService
JavaMailService
Reservation
Reservation
Repository
JpaReservation
Repository
JPA
5
인프라
스트럭처
도메인
impl
패키지
응용
인프라로의 의존
ReserveService
JavaMailService
Reservation
Reservation
Repository
JpaReservation
Repository
JPA
6
인프라에 의존할 때의 흔한 단점
• 구현교체의어려움
• 응용서비스나 도메인로직테스트어려움
7
원인 à고수준/저수준이 뒤섞임,
즉, 저수준이 고수준에 영향을 줌
ReserveService:
예약을 위한 응용 로직 à 고수준
Java API로 메일을 발송 à 저수준
도메인:
객체 영속성 à 고수준
JPA로 보관 à 저수준
RDBMS에 보관 à 저저수준
• 고수준모듈:	
  의미있는단일기능을제공하는 모듈
• 저수준모듈:고수준모듈의기능을구현하기 위해필요한 하위기능의실제구현 8
DEPENDENCY INVERSION PRINCIPLE
• 뒤섞임을 제거하려면 à
고수준입장에서 저수준 구현을추상화해서
의존을뒤집음
ReserveService
<<interface>>
EmailNotifier
JavaMail
EmailNotifier
응용 로직을 구성하는
“이메일 통지하기"를 표현
9
ReserveService
JavaMailService
DIP 적용 예
“저수준의 상세한 내용 없이 구현하기” 참고, http://javacan.tistory.com
10
DIP?
도메인
impl
패키지
SomeDomainService
Reservation
Repository
JpaReservation
Repository
11
응용 ReserveService
인프라
스트럭처
EmailService
Java
EmailService
잘못된 DIP 적용
도메인
impl
패키지
SomeDomainService
Reservation
Repository
JpaReservation
Repository
12
응용 ReserveService
인프라
스트럭처
EmailService
Java
EmailService
JPA
올바른 DIP 적용
도메인 SomeDomainService
Reservation
Repository
13
응용 ReserveService
인프라
스트럭처
Email
Notifier
Java
EmailNotifier
JpaReservation
Repository
DIP 적용 아키텍처
Reserve
Service
Reservation Reservation
Repository
JpaReservation
Repository
Email
Notifier
JavaMail
EmailNotifier
Controller
Message
Listener
14
노력
• 끊임없는 추상화연습
• DIP	
  à고수준 모듈입장에서 추상화
15
#2,AGGREGATE, 참조
16
많은 객체
17
많은 객체
18
복잡도
관계? 이해?
작은 것에
매몰
상위 수준에서 묶어서 생각하면
19
AGGREGATE = 개념적으로 하나인 객체 군
<<ROOT>>
Order
OrderLineShippingInfo
Orderer
20
AGGREGATE
• 관련된객체들의 묶음
• 특징
• 데이터변경시 한단위로 처리됨
• 비슷한또는거의유사한 라이프사이클을 갖는객체들
• 특히,	
  삭제시함께삭제됨
• 경계를가짐
• 기본적으로,	
  한Aggregate에 속한객체는다른Aggregate에
속하지않음
• 필요성
• 많은도메인모델을 가능한간단하고 이해가능한 수준으
로만들필요
• 연관의개수를 줄임으로써 복잡도 감소
21
AGGREGATE = 개념적으로 하나인 객체 군
Order	
  order	
  =	
  orderRepository.findById(orderId);
order.changeShippingInfo(newShippingInfo);
order.calcel();
완전체를 로딩
AGG	
  ROOT가
로직/
일관성(트랜잭션)
처리	
  책임
22
도메인 모델에서 AGG 찾기
Showing Reservation Customer
Movie DiscountStrategy Rule
SeatNo Grade
23
요구 사항에 따라AGG 경계 정의
예매시영화의시간과
좌석을할당한다 회원은등급을갖는다
영화는 상영일정을갖는다?
영화별로가격할인규칙이다르다
(영화별로다른가격할인을갖는다?)
24
AGG 경계 : 규칙〮트랜잭션 범위
상영관리자가
영화일정을추가해도
영화정보는바뀌지않음
컨텐츠담당자가
영화출연자정보를변경해도
상영일정은바뀌지않음
동시성 처리를 할 때,
Moive를 변경하는 동안 관련 Showing을 잠금 필요가 없음
Showing
Movie
25
AGG 경계 : 규칙〮트랜잭션 범위
Movie DiscountStrategy Rule
• 영화 별로 할인 정책이 고정된다.
• 할인 정책 별로 적용 가능 규칙을 갖는다.
Movie가 AGG	
  루트:
• movie.updateDescription(desc);
• movie.changeDiscountStrategies(discountStrategies);
• movie.calculateFee(showing);
26
AGG 경계 : SRP
Movie DiscountStrategy Rule
• Movie는 영화 정보 제공하는 책임만 갖도록 구성
• 할인 계산은 별도 모듈로 분리
FeeCalculator
feeCalculator.calculate(movie,	
  showing)
27
편리한 참조?
Showing Reservation Customer
Movie
reservation.getShowing().getTime()
reservation.getShowing().getMovie().getTitle()
reservation.getCustomer().getName()
28
AGG 간 참조의 잠재적 문제
편한탐색을오용
(불필요한) 고민
showing.getMovie().changeDescription(…);
showing.changeDiscountStrategy(disStrategy);
//	
  Showing.java
public	
  void	
  changeDiscountStrategy(List<DiscountStrategy>	
   strategies)	
  {
this.movie.changeDiscountStrategy(strategies);
}
Lazy	
  Loading	
  vs	
  Earger	
  Loading?	
  OSIV?
29
AGG 간 참조의 잠재적 문제
확장 방해
Oracle
MySQL
Custom	
  Rule	
  Engine
30
AGG 간 ID로 참조하기
public	
  class	
  Showing	
  {
…
private	
  MovieId movieId;
…
}
public	
  class	
  Reservation	
  {
…
private	
  ShowingId showingId;
private	
  CustomerId customerId;
…
}
Showing Reservation Customer
31
연관 객체 조합은 응용 서비스에서 처리
public	
  class	
  ReserveService	
   {
public	
  ReservationId	
  reserve(ShowingId	
   showingId,	
  CustomerId	
  customerId)	
  {
Showing	
  showing	
  =	
  showingRepository.findById(showingId);
checkNotNull(shwoing);
Movie	
  movie	
  =	
  movieRepository.findById(showing.getMovie());
checkNotNull(movie);
Customer	
  customer	
  =	
  customerRepository.findById(customerId);
checkNotNull(customer);
Reservation	
  reservation	
  =	
  reservationFactory.create(
showing,	
  customer,	
  movie.calculateFee(showing)
);
return	
  reservation.getId();
}
…
} 32
ID 참조의 특징
• 복잡도낮춤
• 모델복잡도
• 구현복잡도
• Lazy	
  Loading효과
• 오용방지
• 응집도강화
• AGG별로 확장가능
• 조회성능영향
• 별도모듈
• 더많은코드
33
노력
• 인내필요
• 당장바꾸기힘든DB	
  조인중심표준
• 조인에집착하는 개발자
• 기술을떠나구현할 수있는실력쌓기
• 꼭ORM이 있어야AGGREGATE를 구현할수있는것은아님
• 기술중심이아닌도메인 중심으로AGGREGATE를 생각
34
#3, CQRS
35
도메인 모델로 뷰 처리
${resList[0].customer.name}님의 예매 목록:
<c:forEach	
  var='res'	
  items='${resList}'>
예매번호 : ${res.number}
영화 : <a	
  href="…?id=${res.showing.movie.id">
${res.showing.movie.title}
</a>
시간 : ${res.showing.time}
금액 : ${res.fee}
</c:forEach> 참조로 다 연결한 경우
List<Reservation>	
  resList	
  	
  =
reservationRepository.findByCustomer(customerId);
model.addAttribute("resList",	
   resList);
36
복잡한 도메인의 조회 기능 특징
• 여러AGG에걸쳐데이터접근
Showing
-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐
id:	
  ShowingId
time:	
  Time
…
Reservation
-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐
number:	
  ReservationNo
showing:	
   ShowingId
customer:	
   CustomerId
fee:	
  Money
…
Customer
-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐
id:	
  CustomerId
name:	
  String
…
Movie
-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐
id:	
  MovieId
title:	
   String
description:	
   String
…
${resList[0].customer.name}님의 예매 목록:
<c:forEach9var='res'9items='${resList}'>
예매번호 : ${res.number}
영화 : <a9href="…?id=${res.showing.movie.id">
${res.showing.movie.title}
</a>
시간 : ${res.showing.time}
금액 : ${res.fee}
</c:forEach>
37
복잡한 도메인의 조회 기능 특징
• 성능중요
• 최대한빨리사용자에게 화면을제공해야 함
• 고민
• 한방쿼리!
• 레프트조인!
• DB	
  전용기능!
• …
38
한 모델로 처리하면
한방쿼리!
레프트조인!
DB	
  전용기능!
…
같은연관에대해
Lazy	
  Loading
Eager	
  Loading
Batch	
  Loading
…
도메인모델구현복잡도 증가
39
상태 변경 모델과 조회 모델 분리
[출처 :	
  http://martinfowler.com/bliki/CQRS.html]
40
조회 전용 모델
ReservationList
-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐
customerName:	
   String
reservations:	
   List<ReservationData>
…
ReservationData
-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐
number:	
   String
movieId:	
   String
movieTitle:	
   String
showingTime:	
   Time
fee:	
  Money
…
${resList.customerName}님의 예매목록:
<c:forEach	
  var='res'	
  items='${resList.reservations}'>
예매번호:${res.number}
영화:<a	
  href="…?id=${res.movieId">
${res.movieTitle}
</a>
시간:${res.showingTime}
금액:${res.fee}
</c:forEach>
41
다른 기술, 다른 아키텍처 사용
DAO
(MyBatis)
컨트롤러
뷰 모델
컨트롤러
응용 서비스
도메인
인프라(JPA)
42
다른 저장소 사용
DAO
컨트롤러컨트롤러
응용 서비스
도메인
인프라(JPA,	
  메시징)
43
같은 기술, 뷰 모델 추가
컨트롤러
뷰 데이터 모델
컨트롤러
응용 서비스
도메인
인프라(JPA)
응용 서비스
44
CQRS 이점
• 모델복잡도감소
도메인자체에집중
조회성능을위한코드없음
45
CQRS 이점
• 조회성능향상에유리
조회전용DB를사용한처리량 향상
조회에특화된쿼리
조회단위캐시기술적용
46
부담 요인
• 더많은코드,	
  더많은기술
더 많은 코드
데이터 동기화 처리
더 많은 구현 기술
47
노력
• 장점과단점을 고려해서 CQRS	
  도입여부결정필요
• 트래픽이 없는데조회전용저장소고집하지 말것
• 트래픽이 증가하면 조회전용저장소도입검토
• 도메인이 복잡하면 효과있음
• 더많은코드à더많은시간:	
  X
• 한모델로 뷰처리비용>>	
  뷰모델로 처리비용:	
  O
48
#4, 이벤트
49
예매 취소시 환급하려면?
• 도메인모델에서 처리?
50
public	
  class	
  Reservation	
  {
public	
  void	
  cancel(RefundService	
   refundSvc)	
  {
…	
  //취소처리
refundStatus	
  =	
  State.REFUND_STARTED;
try	
  {
refundSvc.refund(this.paymentId);
refundStatus	
  =	
  State.REFUND_COMPLETED;
}	
  catch(SomeException	
   ex)	
  {
…
}
}
}
예매 취소시 환급하려면?
• 응용서비스에서 처리?
51
public	
  class	
  CancelReservation	
   {
@Transactional
public	
  void	
  cancel(ReservationId	
   resId)	
  {
Reservation	
  res	
  =	
  findById(resId);
res.cancel();
res.refundStarted();
try	
  {
refundSvc.refund(res.getPaymentId());
res.refundCompleted();
}	
  catch(SomeException	
   ex)	
  {
…	
  
}
}
}
고민거리 : 트랜잭션?
52
public	
   class	
  Reservation	
   {
public	
   void	
  cancel(RefundService	
   refundSvc)	
   {
…	
  //취소처리
refundStatus	
   =	
  State.REFUND_STARTED;
try	
  {
refundSvc.refund(this.paymentId);
refundStatus	
   =	
  State.REFUND_COMPLETED;
}	
  catch(SomeException	
   ex)	
  {
…
}
}
}
public	
   class	
  CancelReservation	
   {
@Transactional
public	
   void	
  cancel(ReservationId	
   resId)	
  {
Reservation	
   res	
  =	
  findById(resId);
res.cancel();
res.refundStarted();
try	
  {
refundSvc.refund(res.getPaymentId());
res.refundCompleted();
}	
  catch(SomeException	
   ex)	
  {
…	
  
}
}
}
외부 서비스가 정상이 아닐 경우,
트랜잭션 처리는?
고민거리 : 성능
53
public	
   class	
  Reservation	
   {
public	
   void	
  cancel(RefundService	
   refundSvc)	
   {
…	
  //취소처리
refundStatus	
   =	
  State.REFUND_STARTED;
try	
  {
refundSvc.refund(this.paymentId);
refundStatus	
   =	
  State.REFUND_COMPLETED;
}	
  catch(SomeException	
   ex)	
  {
…
}
}
}
public	
   class	
  CancelReservation	
   {
@Transactional
public	
   void	
  cancel(ReservationId	
   resId)	
  {
Reservation	
   res	
  =	
  findById(resId);
res.cancel();
res.refundStarted();
try	
  {
refundSvc.refund(res.getPaymentId());
res.refundCompleted();
}	
  catch(SomeException	
   ex)	
  {
…	
  
}
}
}
외부 서비스 완료까지
쓰레드 블록킹
고민거리 : 설계
54
public	
   class	
  Reservation	
   {
public	
   void	
  cancel(RefundService	
   refundSvc)	
   {
…	
  //취소처리
refundStatus	
   =	
  State.REFUND_STARTED;
try	
  {
refundSvc.refund(this.paymentId);
refundStatus	
   =	
  State.REFUND_COMPLETED;
}	
  catch(SomeException	
   ex)	
  {
…
}
}
}
public	
   class	
  CancelReservation	
   {
@Transactional
public	
   void	
  cancel(ReservationId	
   resId)	
  {
Reservation	
   res	
  =	
  findById(resId);
res.cancel();
res.refundStarted();
try	
  {
refundSvc.refund(res.getPaymentId());
res.refundCompleted();
}	
  catch(SomeException	
   ex)	
  {
…	
  
}
}
}
예매 도메인 모델에
환불 도메인 로직이 섞임
고민거리 : 설계
55
public	
   class	
  Reservation	
   {
public	
   void	
  cancel(RefundService	
   refundSvc)	
  {
…	
  //취소처리
refundStatus	
   =	
  State.REFUND_STARTED;
try	
  {
refundSvc.refund(this.paymentId);
refundStatus	
   =	
  State.REFUND_COMPLETED;
}	
  catch(SomeException	
   ex)	
  {
…
}
}
}
public	
   class	
  CancelReservation	
   {
@Transactional
public	
   void	
  cancel(ReservationId	
   resId)	
  {
Reservation	
   res	
  =	
  findById(resId);
res.cancel();
res.refundStarted();
try	
  {
refundSvc.refund(res.getPaymentId());
res.refundCompleted();
}	
  catch(SomeException	
   ex)	
  {
…	
  
}
}
}
기능이 추가되면 필요한 객체 파라미터 추가?
DI로 주입 시도?
적용해 볼 만한 것
56
이벤트 + 비동기
이벤트
• 과거에벌어진 어떤것
• 주로상태의변화
• 이벤트예
• 영화추가함(NewMoviedCreated)
• 예매함(RevervationCreated)
• 영화상영일정추가함(ShowingAdded)
• 영화정보변경함(MovieInfoChanged)
• 영화가격정책변경함(PricePolicyUpdated)
• 예매취소함(ReservationCanceled)
57
이벤트의 구성
• 구성
• 발생주체(주로 식별자),	
  일렬번호/버전,	
  타입,	
  발생시간
• 내용(payload)
• 예,	
  회원암호변경이벤트
• 발생주체:	
  "회원mad"
• 버전:	
  1
• 타입:	
  "PasswordChangedEvent"
• 발생시간 :	
  2015-­‐11-­‐27	
  09:59:59
• 내용:	
  {id:"mad",	
  newPwd:	
  "xxxx"}
58
이벤트 관련 구성 요소
59
이벤트 생성 주체
이벤트 디스패처
(이벤트 퍼블리셔)
이벤트 핸들러
(이벤트 구독자)
이벤트
이벤트 용도 1
• 트리거
• 다른기능을수행하기 위한트리거로 이벤트를 사용
• 예시
• 예매를하면SMS로통지한다.
• 예매함이벤트àSMS	
  통지트리거
• 예매를취소하면환불한다.
• 예매취소이벤트à환불트리거
60
예매
취소
이벤트
디스패처
예매취소됨
이벤트
핸들러예매
취소됨
이벤트
예매
취소됨
이벤트
환불
처리
이벤트 용도 2
• 데이터동기화
• 다른시스템간데이터동기화목적으로 이벤트 사용
• 예시
• 상영일정추가이벤트핸들러
à조회전용저장소에 추가데이터반영
61
상영일정
추가
이벤트
디스패처
일정추가됨
이벤트
핸들러일정
추가됨
이벤트
일정
추가됨
이벤트
일정데이터
추가
커맨드 모델
저장소
쿼리 모델
저장소
도메인과 이벤트
• 도메인의 상태변경을이벤트로 표현
• "~할때","~가발생하면", "만약~하면" 등의요구사항이 실
제로상태변경인지 확인
• 예시
• "영화정보를변경할때" àMovieInfoChangedEvent
• "예매를취소하면" àReservationCanceledEvent
62
(도메인) 이벤트 발생과 처리
63
public	
  class	
  Reservation	
  {
public	
  void	
  cancel()	
  {
…취소로직
Events.raise(new	
  ReservationCanceledEvent(getId(),	
  getPaymentNo(),	
  …));
}
}
public	
  class	
  CancelReservationService	
   {
@Transactional
public	
  void	
  cancel(ReservationId	
   resId)	
  {
Events.register(
(ReservationCanceledEvent	
  evt)	
  -­‐>	
  refundSvc.refund(evt.getPaymentNo())
);
Reservation	
  resv	
  =	
  findById(resId);
resv.cancel();
}
}
이벤트 적용 장점
• 서로다른도메인영역의 로직이섞이는것방지
• 불필요한 결합(coupling)	
  제거
64
예매!
취소
이벤트!
디스패처
예매!취소됨
이벤트!
핸들러예매!!
취소됨
이벤트
예매!!
취소됨
이벤트
환불!
처리
예매 취소에 더 이상 환불 로직 없음
예매 도메인에서 환불 도메인으로의 의존 제거
이벤트 적용 장점
• 이벤트핸들러 추가로기능확장
65
예매
취소
이벤트
디스패처
예매취소됨
이벤트
핸들러예매
취소됨
이벤트
예매
취소됨
이벤트
환불
처리
예매취소됨
이벤트
핸들러2
이메일
통지
예매
취소됨
이벤트
동기 이벤트 처리의 단점
• 트랜잭션 처리문제,성능(처리량) 문제
66
public	
  class	
  ReservationService	
   {
@Transactional
public	
  void	
  reserve(MovieId	
   movieId,	
  ShowingId	
  showingId,	
  CustomerId	
  custId)	
  {
Events.register(
(ReservationCreatedEvent	
   evt)	
  -­‐>	
  emailNotifier.notify(…)
);
…//	
  예약도메인로직에서이벤트발생
}
}
이메일 발송 중 익셉션이 발생하면?
이메일 서버가 응답 시간이 길면?
비동기 : 이벤트 처리 시간
• "A할 때,	
  B해라" 요구사항에서 A와B의간격
• 도메인전문가의 '바로'는 '즉시 실행'이 아님
• 수용가능한지연허용범위가있음
• 예시
• 예매취소시, (늦어도 30분 이내에) 환급처리함
• 결제완료후, (늦어도 다음날7시부터) 배송상태를조회
할수있어야함
• 티켓예매시, (최대10분 안에) 분단위티켓판매 통계에반
영함
• 분단위티켓판매통계가10분주기로생성되어도 대세지장없음
67
비동기 : 이벤트와 데이터일관성
• "A할 때,B해라" 요구사항에서 A와B의일관성
• 실제로는 한트랜잭션이 아닌경우많음
• 예시
• 이메일발송실패한다고 회원가입을못하지않음
• 고객이예매취소하면, 운영자가 수동으로환불처리가능
68
응용/인프라
비동기 이벤트 처리 방식 1
• 이벤트디스패처에서 메시지 큐에전송
69
이벤트
디스패처
메시지큐도메인
메시지
리스너
스토리지
도입시 고려사항
• 글로벌 트랜잭션
• 메시지큐가 비정상일 때 이벤트 재전송 방안
이벤트
핸들러
비동기 이벤트 처리 방식 2
• 로컬이벤트핸들러가 DB에 저장
• 포워더가 이벤트를 전달
70
응용/인프라
이벤트
디스패처
로컬
핸들러
도메인
메시지
리스너
스토리지
메시지큐포워더
단일 트랜잭션으로
처리이벤트
저장
이벤트를 주기적으로 읽어와 전달
어디까지 전달했는지 추적
DB 저장과 포워더 구현 예
• 쇼핑몰, ERP, 택배사연동
71
쇼핑
도메인
쇼핑+이벤트
DB
포워더
주문/결제시
관련 이벤트를
한 트랜잭션으로 저장
ERP
연동모듈
택배사
연동모듈
1분 주기로 새로
전달할 이벤트를
읽어와 외부 시스템에
전달
비동기 이벤트 처리 방식 3
• 로컬 이벤트핸들러가 DB에 저장
• 이벤트수신측에서 이벤트를 직접가져감(pull)
• 이벤트제공API 이용(RESTful	
  API등)
72
응용/인프라
이벤트
디스패처
로컬
핸들러
도메인
스토리지
이벤트
저장
이벤트
(REST)	
  API
이벤트
Fetcher
이벤트
핸들러
단일 트랜잭션으로 처리
읽어올 이벤트 범위를
지정해서 가져와 핸들러에 전달
이벤트 데이터 제공함
도메인과 같은 프로세스에서
실행해도 무방
비동기 이벤트의 특징
• 이벤트생성자와 핸들
러의트랜잭션 분리
• 처리량향상
• 고객에게 빠른응답
• 구조가복잡해짐
• 재발송, 재처리등고려
사항증가
73
이벤트 도입시 고려사항
• 이벤트도착순서
• 이벤트발송실패시 재발송
• 이벤트재처리
74
노력
• 사고전환
• 상태의변경==이벤트
• 순차실행à이벤트+핸들러
• 트랜잭션 일관성:비동기처리+Eventually	
  일관성
• 기술집착버림
• 이벤트, 비동기자체에 대한이해필요
• 메시지큐가있어보이지만, 간단한기술로도 충분히구현
가능
• 이벤트+	
  CQRS
75
#5, 정리
76
내용
• DIP
• AGGREGATE
• CQRS
• 이벤트
77
78
끝
최범균 |	
  madvirus@madvirus.net |	
  http://javacan.tistory.com

More Related Content

What's hot

Solid principles
Solid principlesSolid principles
Solid principlesToan Nguyen
 
ORM을 활용할 경우의 설계, 개발 과정
ORM을 활용할 경우의 설계, 개발 과정ORM을 활용할 경우의 설계, 개발 과정
ORM을 활용할 경우의 설계, 개발 과정Javajigi Jaesung
 
카카오 광고 플랫폼 MSA 적용 사례 및 API Gateway와 인증 구현에 대한 소개
카카오 광고 플랫폼 MSA 적용 사례 및 API Gateway와 인증 구현에 대한 소개카카오 광고 플랫폼 MSA 적용 사례 및 API Gateway와 인증 구현에 대한 소개
카카오 광고 플랫폼 MSA 적용 사례 및 API Gateway와 인증 구현에 대한 소개if kakao
 
애플리케이션 아키텍처와 객체지향
애플리케이션 아키텍처와 객체지향 애플리케이션 아키텍처와 객체지향
애플리케이션 아키텍처와 객체지향 Young-Ho Cho
 
[WhaTap DevOps Day] 세션 4 : 롯데ON MSA 모니터링 최적화 사례
[WhaTap DevOps Day] 세션 4 : 롯데ON MSA 모니터링 최적화 사례[WhaTap DevOps Day] 세션 4 : 롯데ON MSA 모니터링 최적화 사례
[WhaTap DevOps Day] 세션 4 : 롯데ON MSA 모니터링 최적화 사례WhaTap Labs
 
FIWARE Training: NGSI-LD Advanced Operations
FIWARE Training: NGSI-LD Advanced OperationsFIWARE Training: NGSI-LD Advanced Operations
FIWARE Training: NGSI-LD Advanced OperationsFIWARE
 
한글과컴퓨터의 클라우드 마이그레이션, 거버넌스 그리고 모더나이제이션-박인재, AWS ISV SA Manager / 박상형, 한글과컴퓨터 I...
한글과컴퓨터의 클라우드 마이그레이션, 거버넌스 그리고 모더나이제이션-박인재, AWS ISV SA Manager / 박상형, 한글과컴퓨터 I...한글과컴퓨터의 클라우드 마이그레이션, 거버넌스 그리고 모더나이제이션-박인재, AWS ISV SA Manager / 박상형, 한글과컴퓨터 I...
한글과컴퓨터의 클라우드 마이그레이션, 거버넌스 그리고 모더나이제이션-박인재, AWS ISV SA Manager / 박상형, 한글과컴퓨터 I...Amazon Web Services Korea
 
AWS KMS를 활용하여 안전한 AWS 환경을 구축하기 위한 전략::임기성::AWS Summit Seoul 2018
AWS KMS를 활용하여 안전한 AWS 환경을 구축하기 위한 전략::임기성::AWS Summit Seoul 2018AWS KMS를 활용하여 안전한 AWS 환경을 구축하기 위한 전략::임기성::AWS Summit Seoul 2018
AWS KMS를 활용하여 안전한 AWS 환경을 구축하기 위한 전략::임기성::AWS Summit Seoul 2018Amazon Web Services Korea
 
JSON:APIについてざっくり入門
JSON:APIについてざっくり入門JSON:APIについてざっくり入門
JSON:APIについてざっくり入門iPride Co., Ltd.
 
서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...
서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...
서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...Jemin Huh
 
이스티오 (Istio) 자습서 v0.5.0
이스티오 (Istio) 자습서 v0.5.0이스티오 (Istio) 자습서 v0.5.0
이스티오 (Istio) 자습서 v0.5.0Jo Hoon
 
[JWPA-1]의존성 주입(Dependency injection)
[JWPA-1]의존성 주입(Dependency injection)[JWPA-1]의존성 주입(Dependency injection)
[JWPA-1]의존성 주입(Dependency injection)Young-Ho Cho
 
우아한 객체지향
우아한 객체지향우아한 객체지향
우아한 객체지향Young-Ho Cho
 
1. 아키텍쳐 설계 프로세스
1. 아키텍쳐 설계 프로세스1. 아키텍쳐 설계 프로세스
1. 아키텍쳐 설계 프로세스Terry Cho
 
[2017 Windows on AWS] AWS 를 활용한 Active Directory 연동 및 이관 방안
[2017 Windows on AWS] AWS 를 활용한 Active Directory 연동 및 이관 방안[2017 Windows on AWS] AWS 를 활용한 Active Directory 연동 및 이관 방안
[2017 Windows on AWS] AWS 를 활용한 Active Directory 연동 및 이관 방안Amazon Web Services Korea
 
AWS 네트워크 보안을 위한 계층별 보안 구성 모범 사례 – 조이정, AWS 솔루션즈 아키텍트:: AWS 온라인 이벤트 – 클라우드 보안 특집
AWS 네트워크 보안을 위한 계층별 보안 구성 모범 사례 – 조이정, AWS 솔루션즈 아키텍트:: AWS 온라인 이벤트 – 클라우드 보안 특집AWS 네트워크 보안을 위한 계층별 보안 구성 모범 사례 – 조이정, AWS 솔루션즈 아키텍트:: AWS 온라인 이벤트 – 클라우드 보안 특집
AWS 네트워크 보안을 위한 계층별 보안 구성 모범 사례 – 조이정, AWS 솔루션즈 아키텍트:: AWS 온라인 이벤트 – 클라우드 보안 특집Amazon Web Services Korea
 
코틀린 멀티플랫폼, 미지와의 조우
코틀린 멀티플랫폼, 미지와의 조우코틀린 멀티플랫폼, 미지와의 조우
코틀린 멀티플랫폼, 미지와의 조우Arawn Park
 
201210 그루터 빅데이터_플랫폼_아키텍쳐_및_솔루션_소개
201210 그루터 빅데이터_플랫폼_아키텍쳐_및_솔루션_소개201210 그루터 빅데이터_플랫폼_아키텍쳐_및_솔루션_소개
201210 그루터 빅데이터_플랫폼_아키텍쳐_및_솔루션_소개Gruter
 

What's hot (20)

Solid principles
Solid principlesSolid principles
Solid principles
 
ORM을 활용할 경우의 설계, 개발 과정
ORM을 활용할 경우의 설계, 개발 과정ORM을 활용할 경우의 설계, 개발 과정
ORM을 활용할 경우의 설계, 개발 과정
 
Clean code: SOLID
Clean code: SOLIDClean code: SOLID
Clean code: SOLID
 
카카오 광고 플랫폼 MSA 적용 사례 및 API Gateway와 인증 구현에 대한 소개
카카오 광고 플랫폼 MSA 적용 사례 및 API Gateway와 인증 구현에 대한 소개카카오 광고 플랫폼 MSA 적용 사례 및 API Gateway와 인증 구현에 대한 소개
카카오 광고 플랫폼 MSA 적용 사례 및 API Gateway와 인증 구현에 대한 소개
 
Rich domain model
Rich domain modelRich domain model
Rich domain model
 
애플리케이션 아키텍처와 객체지향
애플리케이션 아키텍처와 객체지향 애플리케이션 아키텍처와 객체지향
애플리케이션 아키텍처와 객체지향
 
[WhaTap DevOps Day] 세션 4 : 롯데ON MSA 모니터링 최적화 사례
[WhaTap DevOps Day] 세션 4 : 롯데ON MSA 모니터링 최적화 사례[WhaTap DevOps Day] 세션 4 : 롯데ON MSA 모니터링 최적화 사례
[WhaTap DevOps Day] 세션 4 : 롯데ON MSA 모니터링 최적화 사례
 
FIWARE Training: NGSI-LD Advanced Operations
FIWARE Training: NGSI-LD Advanced OperationsFIWARE Training: NGSI-LD Advanced Operations
FIWARE Training: NGSI-LD Advanced Operations
 
한글과컴퓨터의 클라우드 마이그레이션, 거버넌스 그리고 모더나이제이션-박인재, AWS ISV SA Manager / 박상형, 한글과컴퓨터 I...
한글과컴퓨터의 클라우드 마이그레이션, 거버넌스 그리고 모더나이제이션-박인재, AWS ISV SA Manager / 박상형, 한글과컴퓨터 I...한글과컴퓨터의 클라우드 마이그레이션, 거버넌스 그리고 모더나이제이션-박인재, AWS ISV SA Manager / 박상형, 한글과컴퓨터 I...
한글과컴퓨터의 클라우드 마이그레이션, 거버넌스 그리고 모더나이제이션-박인재, AWS ISV SA Manager / 박상형, 한글과컴퓨터 I...
 
AWS KMS를 활용하여 안전한 AWS 환경을 구축하기 위한 전략::임기성::AWS Summit Seoul 2018
AWS KMS를 활용하여 안전한 AWS 환경을 구축하기 위한 전략::임기성::AWS Summit Seoul 2018AWS KMS를 활용하여 안전한 AWS 환경을 구축하기 위한 전략::임기성::AWS Summit Seoul 2018
AWS KMS를 활용하여 안전한 AWS 환경을 구축하기 위한 전략::임기성::AWS Summit Seoul 2018
 
JSON:APIについてざっくり入門
JSON:APIについてざっくり入門JSON:APIについてざっくり入門
JSON:APIについてざっくり入門
 
서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...
서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...
서비스 모니터링 구현 사례 공유 - Realtime log monitoring platform-PMon을 ...
 
이스티오 (Istio) 자습서 v0.5.0
이스티오 (Istio) 자습서 v0.5.0이스티오 (Istio) 자습서 v0.5.0
이스티오 (Istio) 자습서 v0.5.0
 
[JWPA-1]의존성 주입(Dependency injection)
[JWPA-1]의존성 주입(Dependency injection)[JWPA-1]의존성 주입(Dependency injection)
[JWPA-1]의존성 주입(Dependency injection)
 
우아한 객체지향
우아한 객체지향우아한 객체지향
우아한 객체지향
 
1. 아키텍쳐 설계 프로세스
1. 아키텍쳐 설계 프로세스1. 아키텍쳐 설계 프로세스
1. 아키텍쳐 설계 프로세스
 
[2017 Windows on AWS] AWS 를 활용한 Active Directory 연동 및 이관 방안
[2017 Windows on AWS] AWS 를 활용한 Active Directory 연동 및 이관 방안[2017 Windows on AWS] AWS 를 활용한 Active Directory 연동 및 이관 방안
[2017 Windows on AWS] AWS 를 활용한 Active Directory 연동 및 이관 방안
 
AWS 네트워크 보안을 위한 계층별 보안 구성 모범 사례 – 조이정, AWS 솔루션즈 아키텍트:: AWS 온라인 이벤트 – 클라우드 보안 특집
AWS 네트워크 보안을 위한 계층별 보안 구성 모범 사례 – 조이정, AWS 솔루션즈 아키텍트:: AWS 온라인 이벤트 – 클라우드 보안 특집AWS 네트워크 보안을 위한 계층별 보안 구성 모범 사례 – 조이정, AWS 솔루션즈 아키텍트:: AWS 온라인 이벤트 – 클라우드 보안 특집
AWS 네트워크 보안을 위한 계층별 보안 구성 모범 사례 – 조이정, AWS 솔루션즈 아키텍트:: AWS 온라인 이벤트 – 클라우드 보안 특집
 
코틀린 멀티플랫폼, 미지와의 조우
코틀린 멀티플랫폼, 미지와의 조우코틀린 멀티플랫폼, 미지와의 조우
코틀린 멀티플랫폼, 미지와의 조우
 
201210 그루터 빅데이터_플랫폼_아키텍쳐_및_솔루션_소개
201210 그루터 빅데이터_플랫폼_아키텍쳐_및_솔루션_소개201210 그루터 빅데이터_플랫폼_아키텍쳐_및_솔루션_소개
201210 그루터 빅데이터_플랫폼_아키텍쳐_및_솔루션_소개
 

Viewers also liked

Ddd start 부록 지앤선&ksug
Ddd start 부록 지앤선&ksugDdd start 부록 지앤선&ksug
Ddd start 부록 지앤선&ksugbeom kyun choi
 
모델링 연습 리뷰
모델링 연습 리뷰모델링 연습 리뷰
모델링 연습 리뷰beom kyun choi
 
객체 지향 발담그기 JCO 컨퍼런스 14회
객체 지향 발담그기 JCO 컨퍼런스 14회객체 지향 발담그기 JCO 컨퍼런스 14회
객체 지향 발담그기 JCO 컨퍼런스 14회beom kyun choi
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven DesignYoung-Ho Cho
 
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델명환 안
 
객체지향적인 도메인 레이어 구축하기
객체지향적인 도메인 레이어 구축하기객체지향적인 도메인 레이어 구축하기
객체지향적인 도메인 레이어 구축하기Young-Ho Cho
 
도메인 주도 설계 (Domain Driven Design)
도메인 주도 설계 (Domain Driven Design)도메인 주도 설계 (Domain Driven Design)
도메인 주도 설계 (Domain Driven Design)Ashal aka JOKER
 
Domain driven design 8장
Domain driven design 8장Domain driven design 8장
Domain driven design 8장kukuman
 

Viewers also liked (10)

Ddd start 부록 지앤선&ksug
Ddd start 부록 지앤선&ksugDdd start 부록 지앤선&ksug
Ddd start 부록 지앤선&ksug
 
모델링 연습 리뷰
모델링 연습 리뷰모델링 연습 리뷰
모델링 연습 리뷰
 
객체 지향 발담그기 JCO 컨퍼런스 14회
객체 지향 발담그기 JCO 컨퍼런스 14회객체 지향 발담그기 JCO 컨퍼런스 14회
객체 지향 발담그기 JCO 컨퍼런스 14회
 
DDD 산책
DDD 산책DDD 산책
DDD 산책
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven Design
 
MVP 패턴 소개
MVP 패턴 소개MVP 패턴 소개
MVP 패턴 소개
 
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델
 
객체지향적인 도메인 레이어 구축하기
객체지향적인 도메인 레이어 구축하기객체지향적인 도메인 레이어 구축하기
객체지향적인 도메인 레이어 구축하기
 
도메인 주도 설계 (Domain Driven Design)
도메인 주도 설계 (Domain Driven Design)도메인 주도 설계 (Domain Driven Design)
도메인 주도 설계 (Domain Driven Design)
 
Domain driven design 8장
Domain driven design 8장Domain driven design 8장
Domain driven design 8장
 

Similar to 도메인구현 KSUG 20151128

From event storming to spring cloud implementation
From event storming to spring cloud implementationFrom event storming to spring cloud implementation
From event storming to spring cloud implementationuEngine Solutions
 
The Cucumber for Java
The Cucumber for JavaThe Cucumber for Java
The Cucumber for JavaJonghwa Lee
 
안드로이드 오픈소스 그리고 패턴
안드로이드 오픈소스 그리고 패턴  안드로이드 오픈소스 그리고 패턴
안드로이드 오픈소스 그리고 패턴 YoungSu Son
 
안드로이드 오픈소스 패턴 - 0.1
안드로이드 오픈소스 패턴 - 0.1안드로이드 오픈소스 패턴 - 0.1
안드로이드 오픈소스 패턴 - 0.1YoungSu Son
 
CloudWatch 성능 모니터링과 신속한 대응을 위한 노하우 - 박선용 솔루션즈 아키텍트:: AWS Cloud Track 3 Gaming
CloudWatch 성능 모니터링과 신속한 대응을 위한 노하우 - 박선용 솔루션즈 아키텍트:: AWS Cloud Track 3 GamingCloudWatch 성능 모니터링과 신속한 대응을 위한 노하우 - 박선용 솔루션즈 아키텍트:: AWS Cloud Track 3 Gaming
CloudWatch 성능 모니터링과 신속한 대응을 위한 노하우 - 박선용 솔루션즈 아키텍트:: AWS Cloud Track 3 GamingAmazon Web Services Korea
 
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호, 조영준 BSG Partners::AWS Summit ...
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호, 조영준 BSG Partners::AWS Summit ...기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호, 조영준 BSG Partners::AWS Summit ...
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호, 조영준 BSG Partners::AWS Summit ...Amazon Web Services Korea
 
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호, 조영준 BSG Partners::AWS Summit ...
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호, 조영준 BSG Partners::AWS Summit ...기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호, 조영준 BSG Partners::AWS Summit ...
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호, 조영준 BSG Partners::AWS Summit ...Amazon Web Services Korea
 
GraphQL in Action - REST와 이별할 때 생각해야 하는 것들
GraphQL in Action - REST와 이별할 때 생각해야 하는 것들GraphQL in Action - REST와 이별할 때 생각해야 하는 것들
GraphQL in Action - REST와 이별할 때 생각해야 하는 것들Kivol
 
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출GDG Korea
 
안드로이드 개발자에 필요한 오픈소스이야기
안드로이드 개발자에 필요한 오픈소스이야기안드로이드 개발자에 필요한 오픈소스이야기
안드로이드 개발자에 필요한 오픈소스이야기YoungSu Son
 
Cloud-Barista 제5차 오픈 컨퍼런스 : 멀티클라우드 인프라 연동 (CB-Spider)
Cloud-Barista 제5차 오픈 컨퍼런스 : 멀티클라우드 인프라 연동 (CB-Spider)Cloud-Barista 제5차 오픈 컨퍼런스 : 멀티클라우드 인프라 연동 (CB-Spider)
Cloud-Barista 제5차 오픈 컨퍼런스 : 멀티클라우드 인프라 연동 (CB-Spider)Cloud-Barista Community
 
엔터프라이즈 클라우드 마이그레이션 준비와 실행. 그리고, 클라우드 운영 모범 사례 공유-최지웅, 오픈소스컨설팅 CTO / 장진환, 스마일샤...
엔터프라이즈 클라우드 마이그레이션 준비와 실행. 그리고, 클라우드 운영 모범 사례 공유-최지웅, 오픈소스컨설팅 CTO / 장진환, 스마일샤...엔터프라이즈 클라우드 마이그레이션 준비와 실행. 그리고, 클라우드 운영 모범 사례 공유-최지웅, 오픈소스컨설팅 CTO / 장진환, 스마일샤...
엔터프라이즈 클라우드 마이그레이션 준비와 실행. 그리고, 클라우드 운영 모범 사례 공유-최지웅, 오픈소스컨설팅 CTO / 장진환, 스마일샤...Amazon Web Services Korea
 
Aurora MySQL Backtrack을 이용한 빠른 복구 방법 - 진교선 :: AWS Database Modernization Day 온라인
Aurora MySQL Backtrack을 이용한 빠른 복구 방법 - 진교선 :: AWS Database Modernization Day 온라인Aurora MySQL Backtrack을 이용한 빠른 복구 방법 - 진교선 :: AWS Database Modernization Day 온라인
Aurora MySQL Backtrack을 이용한 빠른 복구 방법 - 진교선 :: AWS Database Modernization Day 온라인Amazon Web Services Korea
 
ksqlDB로 시작하는 스트림 프로세싱
ksqlDB로 시작하는 스트림 프로세싱ksqlDB로 시작하는 스트림 프로세싱
ksqlDB로 시작하는 스트림 프로세싱confluent
 
React native 개발 및 javascript 기본
React native 개발 및 javascript 기본React native 개발 및 javascript 기본
React native 개발 및 javascript 기본Tj .
 
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호 상무, 조영준 상무, BSG::AWS Summit Se...
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호 상무, 조영준 상무, BSG::AWS Summit Se...기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호 상무, 조영준 상무, BSG::AWS Summit Se...
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호 상무, 조영준 상무, BSG::AWS Summit Se...Amazon Web Services Korea
 
[2017 AWS Startup Day] AWS 비용 최대 90% 절감하기: 스팟 인스턴스 Deep-Dive
[2017 AWS Startup Day] AWS 비용 최대 90% 절감하기: 스팟 인스턴스 Deep-Dive [2017 AWS Startup Day] AWS 비용 최대 90% 절감하기: 스팟 인스턴스 Deep-Dive
[2017 AWS Startup Day] AWS 비용 최대 90% 절감하기: 스팟 인스턴스 Deep-Dive Amazon Web Services Korea
 
자바 웹 개발 시작하기 (6주차 : 커뮤니티를 만들어보자!)
자바 웹 개발 시작하기 (6주차 : 커뮤니티를 만들어보자!)자바 웹 개발 시작하기 (6주차 : 커뮤니티를 만들어보자!)
자바 웹 개발 시작하기 (6주차 : 커뮤니티를 만들어보자!)DK Lee
 

Similar to 도메인구현 KSUG 20151128 (20)

From event storming to spring cloud implementation
From event storming to spring cloud implementationFrom event storming to spring cloud implementation
From event storming to spring cloud implementation
 
The Cucumber for Java
The Cucumber for JavaThe Cucumber for Java
The Cucumber for Java
 
CQRS
CQRSCQRS
CQRS
 
안드로이드 오픈소스 그리고 패턴
안드로이드 오픈소스 그리고 패턴  안드로이드 오픈소스 그리고 패턴
안드로이드 오픈소스 그리고 패턴
 
안드로이드 오픈소스 패턴 - 0.1
안드로이드 오픈소스 패턴 - 0.1안드로이드 오픈소스 패턴 - 0.1
안드로이드 오픈소스 패턴 - 0.1
 
CloudWatch 성능 모니터링과 신속한 대응을 위한 노하우 - 박선용 솔루션즈 아키텍트:: AWS Cloud Track 3 Gaming
CloudWatch 성능 모니터링과 신속한 대응을 위한 노하우 - 박선용 솔루션즈 아키텍트:: AWS Cloud Track 3 GamingCloudWatch 성능 모니터링과 신속한 대응을 위한 노하우 - 박선용 솔루션즈 아키텍트:: AWS Cloud Track 3 Gaming
CloudWatch 성능 모니터링과 신속한 대응을 위한 노하우 - 박선용 솔루션즈 아키텍트:: AWS Cloud Track 3 Gaming
 
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호, 조영준 BSG Partners::AWS Summit ...
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호, 조영준 BSG Partners::AWS Summit ...기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호, 조영준 BSG Partners::AWS Summit ...
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호, 조영준 BSG Partners::AWS Summit ...
 
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호, 조영준 BSG Partners::AWS Summit ...
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호, 조영준 BSG Partners::AWS Summit ...기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호, 조영준 BSG Partners::AWS Summit ...
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호, 조영준 BSG Partners::AWS Summit ...
 
GraphQL in Action - REST와 이별할 때 생각해야 하는 것들
GraphQL in Action - REST와 이별할 때 생각해야 하는 것들GraphQL in Action - REST와 이별할 때 생각해야 하는 것들
GraphQL in Action - REST와 이별할 때 생각해야 하는 것들
 
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출
 
안드로이드 개발자에 필요한 오픈소스이야기
안드로이드 개발자에 필요한 오픈소스이야기안드로이드 개발자에 필요한 오픈소스이야기
안드로이드 개발자에 필요한 오픈소스이야기
 
Cloud-Barista 제5차 오픈 컨퍼런스 : 멀티클라우드 인프라 연동 (CB-Spider)
Cloud-Barista 제5차 오픈 컨퍼런스 : 멀티클라우드 인프라 연동 (CB-Spider)Cloud-Barista 제5차 오픈 컨퍼런스 : 멀티클라우드 인프라 연동 (CB-Spider)
Cloud-Barista 제5차 오픈 컨퍼런스 : 멀티클라우드 인프라 연동 (CB-Spider)
 
엔터프라이즈 클라우드 마이그레이션 준비와 실행. 그리고, 클라우드 운영 모범 사례 공유-최지웅, 오픈소스컨설팅 CTO / 장진환, 스마일샤...
엔터프라이즈 클라우드 마이그레이션 준비와 실행. 그리고, 클라우드 운영 모범 사례 공유-최지웅, 오픈소스컨설팅 CTO / 장진환, 스마일샤...엔터프라이즈 클라우드 마이그레이션 준비와 실행. 그리고, 클라우드 운영 모범 사례 공유-최지웅, 오픈소스컨설팅 CTO / 장진환, 스마일샤...
엔터프라이즈 클라우드 마이그레이션 준비와 실행. 그리고, 클라우드 운영 모범 사례 공유-최지웅, 오픈소스컨설팅 CTO / 장진환, 스마일샤...
 
Aurora MySQL Backtrack을 이용한 빠른 복구 방법 - 진교선 :: AWS Database Modernization Day 온라인
Aurora MySQL Backtrack을 이용한 빠른 복구 방법 - 진교선 :: AWS Database Modernization Day 온라인Aurora MySQL Backtrack을 이용한 빠른 복구 방법 - 진교선 :: AWS Database Modernization Day 온라인
Aurora MySQL Backtrack을 이용한 빠른 복구 방법 - 진교선 :: AWS Database Modernization Day 온라인
 
OpenStack Swift Debugging
OpenStack Swift DebuggingOpenStack Swift Debugging
OpenStack Swift Debugging
 
ksqlDB로 시작하는 스트림 프로세싱
ksqlDB로 시작하는 스트림 프로세싱ksqlDB로 시작하는 스트림 프로세싱
ksqlDB로 시작하는 스트림 프로세싱
 
React native 개발 및 javascript 기본
React native 개발 및 javascript 기본React native 개발 및 javascript 기본
React native 개발 및 javascript 기본
 
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호 상무, 조영준 상무, BSG::AWS Summit Se...
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호 상무, 조영준 상무, BSG::AWS Summit Se...기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호 상무, 조영준 상무, BSG::AWS Summit Se...
기업 IT 담당자라면 꼭 알아야 할 Enterprise AWS 사례와 특징::김종호 상무, 조영준 상무, BSG::AWS Summit Se...
 
[2017 AWS Startup Day] AWS 비용 최대 90% 절감하기: 스팟 인스턴스 Deep-Dive
[2017 AWS Startup Day] AWS 비용 최대 90% 절감하기: 스팟 인스턴스 Deep-Dive [2017 AWS Startup Day] AWS 비용 최대 90% 절감하기: 스팟 인스턴스 Deep-Dive
[2017 AWS Startup Day] AWS 비용 최대 90% 절감하기: 스팟 인스턴스 Deep-Dive
 
자바 웹 개발 시작하기 (6주차 : 커뮤니티를 만들어보자!)
자바 웹 개발 시작하기 (6주차 : 커뮤니티를 만들어보자!)자바 웹 개발 시작하기 (6주차 : 커뮤니티를 만들어보자!)
자바 웹 개발 시작하기 (6주차 : 커뮤니티를 만들어보자!)
 

More from beom kyun choi

옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개beom kyun choi
 
TDD 발담그기 @ 공감세미나
TDD 발담그기 @ 공감세미나TDD 발담그기 @ 공감세미나
TDD 발담그기 @ 공감세미나beom kyun choi
 
keras 빨리 훑어보기(intro)
keras 빨리 훑어보기(intro)keras 빨리 훑어보기(intro)
keras 빨리 훑어보기(intro)beom kyun choi
 
Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀beom kyun choi
 
파이썬 언어 기초
파이썬 언어 기초파이썬 언어 기초
파이썬 언어 기초beom kyun choi
 
Event source 학습 내용 공유
Event source 학습 내용 공유Event source 학습 내용 공유
Event source 학습 내용 공유beom kyun choi
 
ALS WS에 대한 이해 자료
ALS WS에 대한 이해 자료ALS WS에 대한 이해 자료
ALS WS에 대한 이해 자료beom kyun choi
 
Ji 개발 리뷰 (신림프로그래머)
Ji 개발 리뷰 (신림프로그래머)Ji 개발 리뷰 (신림프로그래머)
Ji 개발 리뷰 (신림프로그래머)beom kyun choi
 
리뷰의 기술 소개
리뷰의 기술 소개리뷰의 기술 소개
리뷰의 기술 소개beom kyun choi
 
스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해beom kyun choi
 
자바8 스트림 API 소개
자바8 스트림 API 소개자바8 스트림 API 소개
자바8 스트림 API 소개beom kyun choi
 
자바8 람다식 소개
자바8 람다식 소개자바8 람다식 소개
자바8 람다식 소개beom kyun choi
 
하둡2 YARN 짧게 보기
하둡2 YARN 짧게 보기하둡2 YARN 짧게 보기
하둡2 YARN 짧게 보기beom kyun choi
 
차원축소 훑어보기 (PCA, SVD, NMF)
차원축소 훑어보기 (PCA, SVD, NMF)차원축소 훑어보기 (PCA, SVD, NMF)
차원축소 훑어보기 (PCA, SVD, NMF)beom kyun choi
 
Hive 입문 발표 자료
Hive 입문 발표 자료Hive 입문 발표 자료
Hive 입문 발표 자료beom kyun choi
 

More from beom kyun choi (20)

옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
 
TDD 발담그기 @ 공감세미나
TDD 발담그기 @ 공감세미나TDD 발담그기 @ 공감세미나
TDD 발담그기 @ 공감세미나
 
keras 빨리 훑어보기(intro)
keras 빨리 훑어보기(intro)keras 빨리 훑어보기(intro)
keras 빨리 훑어보기(intro)
 
Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀
 
파이썬 언어 기초
파이썬 언어 기초파이썬 언어 기초
파이썬 언어 기초
 
Event source 학습 내용 공유
Event source 학습 내용 공유Event source 학습 내용 공유
Event source 학습 내용 공유
 
Spring Boot 소개
Spring Boot 소개Spring Boot 소개
Spring Boot 소개
 
ALS WS에 대한 이해 자료
ALS WS에 대한 이해 자료ALS WS에 대한 이해 자료
ALS WS에 대한 이해 자료
 
Ji 개발 리뷰 (신림프로그래머)
Ji 개발 리뷰 (신림프로그래머)Ji 개발 리뷰 (신림프로그래머)
Ji 개발 리뷰 (신림프로그래머)
 
리뷰의 기술 소개
리뷰의 기술 소개리뷰의 기술 소개
리뷰의 기술 소개
 
스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해
 
자바8 스트림 API 소개
자바8 스트림 API 소개자바8 스트림 API 소개
자바8 스트림 API 소개
 
자바8 람다식 소개
자바8 람다식 소개자바8 람다식 소개
자바8 람다식 소개
 
Zookeeper 소개
Zookeeper 소개Zookeeper 소개
Zookeeper 소개
 
하둡2 YARN 짧게 보기
하둡2 YARN 짧게 보기하둡2 YARN 짧게 보기
하둡2 YARN 짧게 보기
 
차원축소 훑어보기 (PCA, SVD, NMF)
차원축소 훑어보기 (PCA, SVD, NMF)차원축소 훑어보기 (PCA, SVD, NMF)
차원축소 훑어보기 (PCA, SVD, NMF)
 
Storm 훑어보기
Storm 훑어보기Storm 훑어보기
Storm 훑어보기
 
Hive 입문 발표 자료
Hive 입문 발표 자료Hive 입문 발표 자료
Hive 입문 발표 자료
 
HBase 훑어보기
HBase 훑어보기HBase 훑어보기
HBase 훑어보기
 
Flume 훑어보기
Flume 훑어보기Flume 훑어보기
Flume 훑어보기
 

도메인구현 KSUG 20151128

  • 1. 몇 가지 도메인 구현 이야기 최범균(madvirus@madvirus.net),  2015-­‐11-­‐28
  • 2. 내용 • DIP • AGGREGATE과 참조 • CQRS • 이벤트 2
  • 7. 인프라에 의존할 때의 흔한 단점 • 구현교체의어려움 • 응용서비스나 도메인로직테스트어려움 7
  • 8. 원인 à고수준/저수준이 뒤섞임, 즉, 저수준이 고수준에 영향을 줌 ReserveService: 예약을 위한 응용 로직 à 고수준 Java API로 메일을 발송 à 저수준 도메인: 객체 영속성 à 고수준 JPA로 보관 à 저수준 RDBMS에 보관 à 저저수준 • 고수준모듈:  의미있는단일기능을제공하는 모듈 • 저수준모듈:고수준모듈의기능을구현하기 위해필요한 하위기능의실제구현 8
  • 9. DEPENDENCY INVERSION PRINCIPLE • 뒤섞임을 제거하려면 à 고수준입장에서 저수준 구현을추상화해서 의존을뒤집음 ReserveService <<interface>> EmailNotifier JavaMail EmailNotifier 응용 로직을 구성하는 “이메일 통지하기"를 표현 9 ReserveService JavaMailService
  • 10. DIP 적용 예 “저수준의 상세한 내용 없이 구현하기” 참고, http://javacan.tistory.com 10
  • 13. 올바른 DIP 적용 도메인 SomeDomainService Reservation Repository 13 응용 ReserveService 인프라 스트럭처 Email Notifier Java EmailNotifier JpaReservation Repository
  • 14. DIP 적용 아키텍처 Reserve Service Reservation Reservation Repository JpaReservation Repository Email Notifier JavaMail EmailNotifier Controller Message Listener 14
  • 15. 노력 • 끊임없는 추상화연습 • DIP  à고수준 모듈입장에서 추상화 15
  • 19. 상위 수준에서 묶어서 생각하면 19
  • 20. AGGREGATE = 개념적으로 하나인 객체 군 <<ROOT>> Order OrderLineShippingInfo Orderer 20
  • 21. AGGREGATE • 관련된객체들의 묶음 • 특징 • 데이터변경시 한단위로 처리됨 • 비슷한또는거의유사한 라이프사이클을 갖는객체들 • 특히,  삭제시함께삭제됨 • 경계를가짐 • 기본적으로,  한Aggregate에 속한객체는다른Aggregate에 속하지않음 • 필요성 • 많은도메인모델을 가능한간단하고 이해가능한 수준으 로만들필요 • 연관의개수를 줄임으로써 복잡도 감소 21
  • 22. AGGREGATE = 개념적으로 하나인 객체 군 Order  order  =  orderRepository.findById(orderId); order.changeShippingInfo(newShippingInfo); order.calcel(); 완전체를 로딩 AGG  ROOT가 로직/ 일관성(트랜잭션) 처리  책임 22
  • 23. 도메인 모델에서 AGG 찾기 Showing Reservation Customer Movie DiscountStrategy Rule SeatNo Grade 23
  • 24. 요구 사항에 따라AGG 경계 정의 예매시영화의시간과 좌석을할당한다 회원은등급을갖는다 영화는 상영일정을갖는다? 영화별로가격할인규칙이다르다 (영화별로다른가격할인을갖는다?) 24
  • 25. AGG 경계 : 규칙〮트랜잭션 범위 상영관리자가 영화일정을추가해도 영화정보는바뀌지않음 컨텐츠담당자가 영화출연자정보를변경해도 상영일정은바뀌지않음 동시성 처리를 할 때, Moive를 변경하는 동안 관련 Showing을 잠금 필요가 없음 Showing Movie 25
  • 26. AGG 경계 : 규칙〮트랜잭션 범위 Movie DiscountStrategy Rule • 영화 별로 할인 정책이 고정된다. • 할인 정책 별로 적용 가능 규칙을 갖는다. Movie가 AGG  루트: • movie.updateDescription(desc); • movie.changeDiscountStrategies(discountStrategies); • movie.calculateFee(showing); 26
  • 27. AGG 경계 : SRP Movie DiscountStrategy Rule • Movie는 영화 정보 제공하는 책임만 갖도록 구성 • 할인 계산은 별도 모듈로 분리 FeeCalculator feeCalculator.calculate(movie,  showing) 27
  • 28. 편리한 참조? Showing Reservation Customer Movie reservation.getShowing().getTime() reservation.getShowing().getMovie().getTitle() reservation.getCustomer().getName() 28
  • 29. AGG 간 참조의 잠재적 문제 편한탐색을오용 (불필요한) 고민 showing.getMovie().changeDescription(…); showing.changeDiscountStrategy(disStrategy); //  Showing.java public  void  changeDiscountStrategy(List<DiscountStrategy>   strategies)  { this.movie.changeDiscountStrategy(strategies); } Lazy  Loading  vs  Earger  Loading?  OSIV? 29
  • 30. AGG 간 참조의 잠재적 문제 확장 방해 Oracle MySQL Custom  Rule  Engine 30
  • 31. AGG 간 ID로 참조하기 public  class  Showing  { … private  MovieId movieId; … } public  class  Reservation  { … private  ShowingId showingId; private  CustomerId customerId; … } Showing Reservation Customer 31
  • 32. 연관 객체 조합은 응용 서비스에서 처리 public  class  ReserveService   { public  ReservationId  reserve(ShowingId   showingId,  CustomerId  customerId)  { Showing  showing  =  showingRepository.findById(showingId); checkNotNull(shwoing); Movie  movie  =  movieRepository.findById(showing.getMovie()); checkNotNull(movie); Customer  customer  =  customerRepository.findById(customerId); checkNotNull(customer); Reservation  reservation  =  reservationFactory.create( showing,  customer,  movie.calculateFee(showing) ); return  reservation.getId(); } … } 32
  • 33. ID 참조의 특징 • 복잡도낮춤 • 모델복잡도 • 구현복잡도 • Lazy  Loading효과 • 오용방지 • 응집도강화 • AGG별로 확장가능 • 조회성능영향 • 별도모듈 • 더많은코드 33
  • 34. 노력 • 인내필요 • 당장바꾸기힘든DB  조인중심표준 • 조인에집착하는 개발자 • 기술을떠나구현할 수있는실력쌓기 • 꼭ORM이 있어야AGGREGATE를 구현할수있는것은아님 • 기술중심이아닌도메인 중심으로AGGREGATE를 생각 34
  • 36. 도메인 모델로 뷰 처리 ${resList[0].customer.name}님의 예매 목록: <c:forEach  var='res'  items='${resList}'> 예매번호 : ${res.number} 영화 : <a  href="…?id=${res.showing.movie.id"> ${res.showing.movie.title} </a> 시간 : ${res.showing.time} 금액 : ${res.fee} </c:forEach> 참조로 다 연결한 경우 List<Reservation>  resList    = reservationRepository.findByCustomer(customerId); model.addAttribute("resList",   resList); 36
  • 37. 복잡한 도메인의 조회 기능 특징 • 여러AGG에걸쳐데이터접근 Showing -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ id:  ShowingId time:  Time … Reservation -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ number:  ReservationNo showing:   ShowingId customer:   CustomerId fee:  Money … Customer -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ id:  CustomerId name:  String … Movie -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ id:  MovieId title:   String description:   String … ${resList[0].customer.name}님의 예매 목록: <c:forEach9var='res'9items='${resList}'> 예매번호 : ${res.number} 영화 : <a9href="…?id=${res.showing.movie.id"> ${res.showing.movie.title} </a> 시간 : ${res.showing.time} 금액 : ${res.fee} </c:forEach> 37
  • 38. 복잡한 도메인의 조회 기능 특징 • 성능중요 • 최대한빨리사용자에게 화면을제공해야 함 • 고민 • 한방쿼리! • 레프트조인! • DB  전용기능! • … 38
  • 39. 한 모델로 처리하면 한방쿼리! 레프트조인! DB  전용기능! … 같은연관에대해 Lazy  Loading Eager  Loading Batch  Loading … 도메인모델구현복잡도 증가 39
  • 40. 상태 변경 모델과 조회 모델 분리 [출처 :  http://martinfowler.com/bliki/CQRS.html] 40
  • 41. 조회 전용 모델 ReservationList -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ customerName:   String reservations:   List<ReservationData> … ReservationData -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ number:   String movieId:   String movieTitle:   String showingTime:   Time fee:  Money … ${resList.customerName}님의 예매목록: <c:forEach  var='res'  items='${resList.reservations}'> 예매번호:${res.number} 영화:<a  href="…?id=${res.movieId"> ${res.movieTitle} </a> 시간:${res.showingTime} 금액:${res.fee} </c:forEach> 41
  • 42. 다른 기술, 다른 아키텍처 사용 DAO (MyBatis) 컨트롤러 뷰 모델 컨트롤러 응용 서비스 도메인 인프라(JPA) 42
  • 43. 다른 저장소 사용 DAO 컨트롤러컨트롤러 응용 서비스 도메인 인프라(JPA,  메시징) 43
  • 44. 같은 기술, 뷰 모델 추가 컨트롤러 뷰 데이터 모델 컨트롤러 응용 서비스 도메인 인프라(JPA) 응용 서비스 44
  • 46. CQRS 이점 • 조회성능향상에유리 조회전용DB를사용한처리량 향상 조회에특화된쿼리 조회단위캐시기술적용 46
  • 47. 부담 요인 • 더많은코드,  더많은기술 더 많은 코드 데이터 동기화 처리 더 많은 구현 기술 47
  • 48. 노력 • 장점과단점을 고려해서 CQRS  도입여부결정필요 • 트래픽이 없는데조회전용저장소고집하지 말것 • 트래픽이 증가하면 조회전용저장소도입검토 • 도메인이 복잡하면 효과있음 • 더많은코드à더많은시간:  X • 한모델로 뷰처리비용>>  뷰모델로 처리비용:  O 48
  • 50. 예매 취소시 환급하려면? • 도메인모델에서 처리? 50 public  class  Reservation  { public  void  cancel(RefundService   refundSvc)  { …  //취소처리 refundStatus  =  State.REFUND_STARTED; try  { refundSvc.refund(this.paymentId); refundStatus  =  State.REFUND_COMPLETED; }  catch(SomeException   ex)  { … } } }
  • 51. 예매 취소시 환급하려면? • 응용서비스에서 처리? 51 public  class  CancelReservation   { @Transactional public  void  cancel(ReservationId   resId)  { Reservation  res  =  findById(resId); res.cancel(); res.refundStarted(); try  { refundSvc.refund(res.getPaymentId()); res.refundCompleted(); }  catch(SomeException   ex)  { …   } } }
  • 52. 고민거리 : 트랜잭션? 52 public   class  Reservation   { public   void  cancel(RefundService   refundSvc)   { …  //취소처리 refundStatus   =  State.REFUND_STARTED; try  { refundSvc.refund(this.paymentId); refundStatus   =  State.REFUND_COMPLETED; }  catch(SomeException   ex)  { … } } } public   class  CancelReservation   { @Transactional public   void  cancel(ReservationId   resId)  { Reservation   res  =  findById(resId); res.cancel(); res.refundStarted(); try  { refundSvc.refund(res.getPaymentId()); res.refundCompleted(); }  catch(SomeException   ex)  { …   } } } 외부 서비스가 정상이 아닐 경우, 트랜잭션 처리는?
  • 53. 고민거리 : 성능 53 public   class  Reservation   { public   void  cancel(RefundService   refundSvc)   { …  //취소처리 refundStatus   =  State.REFUND_STARTED; try  { refundSvc.refund(this.paymentId); refundStatus   =  State.REFUND_COMPLETED; }  catch(SomeException   ex)  { … } } } public   class  CancelReservation   { @Transactional public   void  cancel(ReservationId   resId)  { Reservation   res  =  findById(resId); res.cancel(); res.refundStarted(); try  { refundSvc.refund(res.getPaymentId()); res.refundCompleted(); }  catch(SomeException   ex)  { …   } } } 외부 서비스 완료까지 쓰레드 블록킹
  • 54. 고민거리 : 설계 54 public   class  Reservation   { public   void  cancel(RefundService   refundSvc)   { …  //취소처리 refundStatus   =  State.REFUND_STARTED; try  { refundSvc.refund(this.paymentId); refundStatus   =  State.REFUND_COMPLETED; }  catch(SomeException   ex)  { … } } } public   class  CancelReservation   { @Transactional public   void  cancel(ReservationId   resId)  { Reservation   res  =  findById(resId); res.cancel(); res.refundStarted(); try  { refundSvc.refund(res.getPaymentId()); res.refundCompleted(); }  catch(SomeException   ex)  { …   } } } 예매 도메인 모델에 환불 도메인 로직이 섞임
  • 55. 고민거리 : 설계 55 public   class  Reservation   { public   void  cancel(RefundService   refundSvc)  { …  //취소처리 refundStatus   =  State.REFUND_STARTED; try  { refundSvc.refund(this.paymentId); refundStatus   =  State.REFUND_COMPLETED; }  catch(SomeException   ex)  { … } } } public   class  CancelReservation   { @Transactional public   void  cancel(ReservationId   resId)  { Reservation   res  =  findById(resId); res.cancel(); res.refundStarted(); try  { refundSvc.refund(res.getPaymentId()); res.refundCompleted(); }  catch(SomeException   ex)  { …   } } } 기능이 추가되면 필요한 객체 파라미터 추가? DI로 주입 시도?
  • 56. 적용해 볼 만한 것 56 이벤트 + 비동기
  • 57. 이벤트 • 과거에벌어진 어떤것 • 주로상태의변화 • 이벤트예 • 영화추가함(NewMoviedCreated) • 예매함(RevervationCreated) • 영화상영일정추가함(ShowingAdded) • 영화정보변경함(MovieInfoChanged) • 영화가격정책변경함(PricePolicyUpdated) • 예매취소함(ReservationCanceled) 57
  • 58. 이벤트의 구성 • 구성 • 발생주체(주로 식별자),  일렬번호/버전,  타입,  발생시간 • 내용(payload) • 예,  회원암호변경이벤트 • 발생주체:  "회원mad" • 버전:  1 • 타입:  "PasswordChangedEvent" • 발생시간 :  2015-­‐11-­‐27  09:59:59 • 내용:  {id:"mad",  newPwd:  "xxxx"} 58
  • 59. 이벤트 관련 구성 요소 59 이벤트 생성 주체 이벤트 디스패처 (이벤트 퍼블리셔) 이벤트 핸들러 (이벤트 구독자) 이벤트
  • 60. 이벤트 용도 1 • 트리거 • 다른기능을수행하기 위한트리거로 이벤트를 사용 • 예시 • 예매를하면SMS로통지한다. • 예매함이벤트àSMS  통지트리거 • 예매를취소하면환불한다. • 예매취소이벤트à환불트리거 60 예매 취소 이벤트 디스패처 예매취소됨 이벤트 핸들러예매 취소됨 이벤트 예매 취소됨 이벤트 환불 처리
  • 61. 이벤트 용도 2 • 데이터동기화 • 다른시스템간데이터동기화목적으로 이벤트 사용 • 예시 • 상영일정추가이벤트핸들러 à조회전용저장소에 추가데이터반영 61 상영일정 추가 이벤트 디스패처 일정추가됨 이벤트 핸들러일정 추가됨 이벤트 일정 추가됨 이벤트 일정데이터 추가 커맨드 모델 저장소 쿼리 모델 저장소
  • 62. 도메인과 이벤트 • 도메인의 상태변경을이벤트로 표현 • "~할때","~가발생하면", "만약~하면" 등의요구사항이 실 제로상태변경인지 확인 • 예시 • "영화정보를변경할때" àMovieInfoChangedEvent • "예매를취소하면" àReservationCanceledEvent 62
  • 63. (도메인) 이벤트 발생과 처리 63 public  class  Reservation  { public  void  cancel()  { …취소로직 Events.raise(new  ReservationCanceledEvent(getId(),  getPaymentNo(),  …)); } } public  class  CancelReservationService   { @Transactional public  void  cancel(ReservationId   resId)  { Events.register( (ReservationCanceledEvent  evt)  -­‐>  refundSvc.refund(evt.getPaymentNo()) ); Reservation  resv  =  findById(resId); resv.cancel(); } }
  • 64. 이벤트 적용 장점 • 서로다른도메인영역의 로직이섞이는것방지 • 불필요한 결합(coupling)  제거 64 예매! 취소 이벤트! 디스패처 예매!취소됨 이벤트! 핸들러예매!! 취소됨 이벤트 예매!! 취소됨 이벤트 환불! 처리 예매 취소에 더 이상 환불 로직 없음 예매 도메인에서 환불 도메인으로의 의존 제거
  • 65. 이벤트 적용 장점 • 이벤트핸들러 추가로기능확장 65 예매 취소 이벤트 디스패처 예매취소됨 이벤트 핸들러예매 취소됨 이벤트 예매 취소됨 이벤트 환불 처리 예매취소됨 이벤트 핸들러2 이메일 통지 예매 취소됨 이벤트
  • 66. 동기 이벤트 처리의 단점 • 트랜잭션 처리문제,성능(처리량) 문제 66 public  class  ReservationService   { @Transactional public  void  reserve(MovieId   movieId,  ShowingId  showingId,  CustomerId  custId)  { Events.register( (ReservationCreatedEvent   evt)  -­‐>  emailNotifier.notify(…) ); …//  예약도메인로직에서이벤트발생 } } 이메일 발송 중 익셉션이 발생하면? 이메일 서버가 응답 시간이 길면?
  • 67. 비동기 : 이벤트 처리 시간 • "A할 때,  B해라" 요구사항에서 A와B의간격 • 도메인전문가의 '바로'는 '즉시 실행'이 아님 • 수용가능한지연허용범위가있음 • 예시 • 예매취소시, (늦어도 30분 이내에) 환급처리함 • 결제완료후, (늦어도 다음날7시부터) 배송상태를조회 할수있어야함 • 티켓예매시, (최대10분 안에) 분단위티켓판매 통계에반 영함 • 분단위티켓판매통계가10분주기로생성되어도 대세지장없음 67
  • 68. 비동기 : 이벤트와 데이터일관성 • "A할 때,B해라" 요구사항에서 A와B의일관성 • 실제로는 한트랜잭션이 아닌경우많음 • 예시 • 이메일발송실패한다고 회원가입을못하지않음 • 고객이예매취소하면, 운영자가 수동으로환불처리가능 68
  • 69. 응용/인프라 비동기 이벤트 처리 방식 1 • 이벤트디스패처에서 메시지 큐에전송 69 이벤트 디스패처 메시지큐도메인 메시지 리스너 스토리지 도입시 고려사항 • 글로벌 트랜잭션 • 메시지큐가 비정상일 때 이벤트 재전송 방안 이벤트 핸들러
  • 70. 비동기 이벤트 처리 방식 2 • 로컬이벤트핸들러가 DB에 저장 • 포워더가 이벤트를 전달 70 응용/인프라 이벤트 디스패처 로컬 핸들러 도메인 메시지 리스너 스토리지 메시지큐포워더 단일 트랜잭션으로 처리이벤트 저장 이벤트를 주기적으로 읽어와 전달 어디까지 전달했는지 추적
  • 71. DB 저장과 포워더 구현 예 • 쇼핑몰, ERP, 택배사연동 71 쇼핑 도메인 쇼핑+이벤트 DB 포워더 주문/결제시 관련 이벤트를 한 트랜잭션으로 저장 ERP 연동모듈 택배사 연동모듈 1분 주기로 새로 전달할 이벤트를 읽어와 외부 시스템에 전달
  • 72. 비동기 이벤트 처리 방식 3 • 로컬 이벤트핸들러가 DB에 저장 • 이벤트수신측에서 이벤트를 직접가져감(pull) • 이벤트제공API 이용(RESTful  API등) 72 응용/인프라 이벤트 디스패처 로컬 핸들러 도메인 스토리지 이벤트 저장 이벤트 (REST)  API 이벤트 Fetcher 이벤트 핸들러 단일 트랜잭션으로 처리 읽어올 이벤트 범위를 지정해서 가져와 핸들러에 전달 이벤트 데이터 제공함 도메인과 같은 프로세스에서 실행해도 무방
  • 73. 비동기 이벤트의 특징 • 이벤트생성자와 핸들 러의트랜잭션 분리 • 처리량향상 • 고객에게 빠른응답 • 구조가복잡해짐 • 재발송, 재처리등고려 사항증가 73
  • 74. 이벤트 도입시 고려사항 • 이벤트도착순서 • 이벤트발송실패시 재발송 • 이벤트재처리 74
  • 75. 노력 • 사고전환 • 상태의변경==이벤트 • 순차실행à이벤트+핸들러 • 트랜잭션 일관성:비동기처리+Eventually  일관성 • 기술집착버림 • 이벤트, 비동기자체에 대한이해필요 • 메시지큐가있어보이지만, 간단한기술로도 충분히구현 가능 • 이벤트+  CQRS 75
  • 77. 내용 • DIP • AGGREGATE • CQRS • 이벤트 77
  • 78. 78 끝 최범균 |  madvirus@madvirus.net |  http://javacan.tistory.com