완전히 뜯어고치는 대신 단계적으로 리팩터링하는 것이 좋다.
기존 모놀리식 애플리케이션에 새 기능이 구현된 코드는 추가하지 말자
애플리케이션은 일반적으로 다음 세 계층으로 구성된다.
-> back - front 나눠라
서비스로 추출해야 할 기능은 다음과 같다.
위 같은 상황에서 Order를 별도의 서비스로 추출하려면 프로세스 간 객체 참조는 있을 수 없기에 Restaurant을 바라보는 레퍼런스에도 작업이 필요하다.
객체 레퍼런스를 솎아내기 위해 애그리거트 관점으로 생각할 필요가 있다. 레퍼런스를 기본키 필드로 대체 하자.
도메인 모델의 클래스는 대부분 영속적이라 필드가 DB스키마에 매핑되어있다. 따라서 서비스 DB로 옮길 필요가 있다.
데이터를 복제해 DB클라이언트가 새 스키마를 사용하도록 단계적으로 업데이트하는 발상도 있다.
전이 기간 동안에는 원본 스키마를 유지하되, 원본 스키마와 신규 스키마를 동기화하는 트리거를 사용할 수 있다.
Delivery 엔티티를 추출한다면, 모놀리스 쪽에서는 배달 관련 필드는 읽기 전용으로 두고 배달 서비스의 데이터를 복제해 최신 상태를 유지하도록 한다. 그리고 모놀리스에서 배달 관련 필드를 업데이트하는 코드를 찾아 새 배달 서비스를 호출하도록 변경하면 된다.
기존 모놀리스 개발은 사실상 동결하고 요건이 있을 때마다 서비스를 추출할 것
서비스로 추출하는 것이 이로운 이유는 다음과 같다
서비스와 모놀리스는 서로 호출해야하는 경우가 있다. 따라서 데이터 일관성을 유지하는 것이 중요하다.
IPC를 인터페이스로 캡슐화하자
interface CustomerContactInfoRepository {
CustomerContactInfo findCustomerContactInfo(long customerId);
}
도메인 모델은 성격 자체가 달라 서비스-모놀리스가 소통하려면 ACL을 구현해야 한다.
ACL: 상이한 두 도메인 모델이 서로 상대편을 더럽히지 않도록 변환
모놀리스가 이벤트를 발행/소비하도록 고치기는 쉽지 않다.
모놀리스가 도메인 이벤트를 발행하는 방법은 아래 두 가지가 있다.
특정 엔터티를 변경하는 코드를 모두 찾아 이벤트 발행 API를 호출하는 코드를 끼워 넣기 -> 쉽지 않다..
DB 수준에서 도메인 이벤트 발행 (트랜잭션 로그 테일링 or 폴링) -> DB 수준에서 이벤트 발행하면 업데이트 사유 파악이 어렵고 비즈니스 이벤트 발행이 어려워진다.
모놀리스에서 구독하는 방법은 쉽다.
모놀리스에서 보상 트랜잭션 구현은 어렵다.
모놀리스에서 주방 서비스 추출한다고 했을 때 createOrder()
을 구현한다고 해보자. 그럼 다음 단계로 구성된 단일 ACID 트랜잭션을 실행한다.
모놀리스
사가
-> 시맨틱 락으로 상태를 계속 두어야 한다. 하지만 기존 모놀리스에 상태를 추가하는 건 쉽지 않은 일 ..
위 방식은 보상 트랜잭션이 필요하지만 보상 트랜잭션 없이 설계가 가능하다. 예를 들어 주방 서비스 추출이 아닌 주문 서비스를 추출할 수 있다.
-> 3번이 실패할 일이 없으므로 2번을 롤백시킬 필요가 없다.
마이크로서비스 애플리케이션은 JWT와 같은 토큰 형태로 신원을 전달한다.
주문 상태를 추적해 약속한 시간에 음식을 배달할 수 없다면 알려야하는 코드를 작성해야 한다. 모놀리스 말고 새 기능을 서비스를 구현하는 방법 알아보자ㅂ!
getDelayedOrders()
로 지연 중/배달 불가 주문 조회 서비스 추가