커머스 영역 예제
• 쇼핑몰 카탈로그 관리에서 주문, 재고
확인, 배송조회, 프로모션에 이르는 예
제
• MSA 적용 관심도가 가장 높은 영역중
하나
• 행사 제품과 특정 세일즈 기간에 특정
서비스가 핫-스폿으로 요청이 폭주하는
경향은 마이크로 서비스의 Self-
Healing, 결함내성, 동적 확장 등의
MSA 설계 강점을 잘 설명할 수 있음
• 챗봇을 통한 기존 고객에 대한 재방문
을 높히고 고객 성향 분석을 통한 추천
상품 제공
• MSA 플랫폼 상에 머신러닝 워크로드를
수행하는 Tensorflow, Keras 등의
Polyglot 한 다양한 플랫폼을 운영
Event Storming – Event 들을 먼저 도출
가입 탈퇴
비밀번호
분실
주문 결재완료
수취확인
입고
출고
우리 서비스에는 어떤 비즈니스 이벤트들이 발생하는가?
현업이 사용하는 용어를 그대로 사용 (Ubiquitous Language)
용어의 namespace 를 구지 나누려는 노력을 하지 않음
Event Storming – Command 도출
가입 탈퇴
비밀번호
분실
주문 결재완료
수취확인
입고
출고
가입화면
입력
탈퇴화면
비밀번호
분실화면
주문서
작성
PG결재
수취확인
버튼
Event를 발생시키는 명령은 무엇인가? UI를 통해? or 시간도래? or 다른 이벤트에 의해?
Event Storming – Entity 도출
가입 탈퇴
비밀번호
분실
주문 결재완료
수취확인
입고
출고
가입화면
입력
탈퇴화면
비밀번호
분실화면
주문서
작성
PG결재
수취확인
버튼
고객
• 이름
• 나이
• 성별
• 비밀번호
주문
• 주문번호
• 일시
• 제품정보
• 수량
• 배송상태
제고
• 제품정보
• 수량
Event Storming – Sub-domain 과
Bounded Context
가입 탈퇴
비밀번호
분실
주문 결재완료
수취확인
입고
출고
가입화면
입력
탈퇴화면
비밀번호
분실화면
주문서
작성
PG결재
수취확인
버튼
고객
• 이름
• 나이
• 성별
• 비밀번호
주문
• 주문번호
• 일시
• 제품정보
• 수량
• 배송상태
재고
• 제품정보
• 수량
Order
InventoryCustomer
Event Storming – Core / Supportive /
General Sub-domain
가입
탈퇴
주문 결재완료
입고
출고
가입화면
입력
탈퇴화면
비밀번호
분실화면
주문서
작성
PG결재
수취확인
버튼
입고입력
결재완료
사용자등록
비밀번호분
실처리
IAM (General)
Billing (Supportive)
구독일
도래
인보이
스발행
고객
• 이름
• 나이
• 성별
• 비밀번호
주문
• 주문번호
• 일시
• 제품정보
• 수량
• 배송상태
재고
• 제품정보
• 수량
수취확인
Order (Core)
Inventory
(Core)
Customer (Core)
로그발
생 수집
Event Storming to DDD and
Implementations
가입 탈퇴
주문
결재완료
입고
출고
가입화면
입력
탈퇴화면비밀번호
분실화면
주문서
작성
PG결재 수취확인
버튼
입고입력
결재완료
사용자등록
비밀번호분
실처리
구독일
도래
인보이스
발행
고객 주문 재고
수취확인
Entities or Document DB
Business Events / Kafka Topics
UI or Service (REST API by Repository Pattern) or Batch Jobs
Decomposition to Micro Services
(Spring Boot Applications)
Customer
IAM
Order Inventory
Billing
Entity Class 와 Repository 작성
고객 주문 재고
public interface OrderRepository extends
MultitenantRepository<Order, java.lang.Long> {
}
@Entity
@Table(name="Ordertable")
public class Order {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private java.lang.Long id;
private java.util.Date date;
private java.lang.String status;
@OneToMany(mappedBy="order")
private List<Item> itemList;
}
@Entity
@Multitenant
@TenantDiscriminatorColumn(
name = "TENANTID",
contextProperty = "tenant-id"
)
public class Customer {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
}
public interface CustomerRepository extends
MultitenantRepository<Customer, Long> {
List<Customer> findByLastName(String
lastName);
}
@Entity
@Table(name="Itemtable")
public class Item {
@Id @GeneratedValue(strategy=GenerationType.AUT
private java.lang.Long id;
private java.lang.String name;
private java.lang.Long stock;
@ManyToOne
private Order order;
}
public interface ItemRepository extends
MultitenantRepository<Item, java.lang.Long> {
}
Service 의 생성
주문서
작성
수취확인
버튼
Repository Pattern 으로 생성된 것
사용할 수 있는 경우
주문서 작성을 위한 백엔드 API 는
Order Repository 에서 생성된
CRUD actions 들 중 POST Service
를 그대로 사용할 수 있으므로 별
도 구현할 필요 없다. 마찬가지 주
문서 수정, 삭제도 각각 PATCH,
DELETE 로 생성된 API를 사용하면
된다.
Repository 에서 생성된 API 를 사용 못하
는 경우, 별도 Spring MVC Service 로 생성
수취 확인을 위한 백엔드 API 는 Order
Repository 에 생성된 PUT-POST-PATCH-
DELETE 중 적합한 것이 없으므로 별도 추
가 action URI를 만드는 것이 적합
@RequestMapping(method= RequestMethod.POST,
path="/orders/confirm-delivered")
public int confirmDelivered(Order order);
Domain Event 생성과 pub 처리
public class OrderPlacedEvent{
Order order;
}
#OrderPlacedEvent.java
주문
결재완료
결재완료
로그발생수취확인
@PostPersist
public void orderPlaced(){
messageChannel.send(MessageBuilder
.withPayload(new OrderPlacedEvent(this))
.build());
}
#Order.java
* 이벤트의 Publish trigger 는
주로 Entity 의 발생과 함께 하는 경우가 많음
Domain Event 의 sub 처리
Inventory 서비스 내부
주문
출고
Order (Core)
Inventory
(Core)
@StreamListener(Streams.INPUT)
public void handleOrder(@Payload OrderPlacedEvent orderPlacedEv
{
Item item = itemRepository.findOne(orderPlacedEvent.getItemId()
item.setStock(item.getStock()-1);
itemRepository.save(item);
}
Domain Event 의 sub 처리 II –
Marketing Service 의 등장
주문
출고
Order (Core) Inventory
(Core)
Marketing 서비스 내부
@StreamListener(Streams.INPUT)
public void handleOrder(@Payload OrderPlacedEvent
orderPlacedEvent) {
…. 고객 선호도 정보 저장 …
……. 유사 상품 추천 ……..
}
Marketing (Supportive)
주문
마케팅
정보
수집
• Least Coupling
• No Code Change in event
originator
• Don’t need to share database
(Store event data by each
microservices in preferred
format for their need)
Domain Event 의 sub 처리 III – Anti-
corruption Layer
주문
Order (Core)
Billing (Supportive)
Billing 서비스 내부
@StreamListener(Streams.INPUT)
public void handleOrder(@Payload MeteringLogEvent meteringEve
…. 빌링 처리 …
}
OrderPlacedEvent
Not compatible!
인보이스
발행
로그발생
Domain Event 의 sub 처리 III – Anti-
corruption Layer
주문
Anti-
Corruption
처리
Order (Core)
Order-Billing
(Anti-corruption)
Billing (Supportive)
인보이스
발행
Order-Billing 서비스 내부
@StreamListener(Streams.INPUT)
public void handleOrder(@Payload OrderPlacedEvent orderEvent
messageChannel.send(MessageBuilder
.withPayload(new MeteringLogEvent(orderEvent))
.build());
}
로그발생
• Anti-corruption Layer 를 위해 새로운
MS 를 또 관리하는 것이 부담이 되는
경우
• BPM 을 통해서 Anti-corruption Layer
를 위한 Micro service 를 그때 그때 생
성하고 폐기할 수 있음
• 마이크로 서비스간에 Glue 역할
Generate Micro services with Repository
Pattern
코드생성
Git 커밋
빌드 & 배포
서비스 접속 URL
고객
주문
재고
주문서
CRUD
고객
CRUD
재고
CRUD
Test the generated micro service –
Order Service
http http://backend-commerce-order-dev.pas-mini.io/items name="OO 건조기" stock=5
{
"_links": {
"item": {
"href": "http://backend-commerce-order-dev.pas-mini.io/items/1"
},
"order": {
"href": "http://backend-commerce-order-dev.pas-mini.io/items/1/order"
},
"self": {
"href": "http://backend-commerce-order-dev.pas-mini.io/items/1"
}
},
"name": "OO 건조기",
"stock": 5
}
Generated Code details –Spring Boot
on Spring Cloud MSA Chassis
Main Application
Domain Classes
Services and Repositories
Settings
방법1의 Entity-Repository 패
턴에 대한 작업을 대신해줌