-
Notifications
You must be signed in to change notification settings - Fork 179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Step4/cqrs] - menu/product cqrs 적용해보기 #359
base: master
Are you sure you want to change the base?
Conversation
* docs(kitchen pos) : 이전 단계의 README.md 가져오기 * feat(kitchen pos) : 이전 단계의 프로덕션 코드 및 테스트 코드 가져오기 * fix(kitchen pos) : DeliveryOrder entity 생성으로 ddl.sql 안 맞아 주석 처리
* chore(kitchen pos) : InMemoryProductRepository 패키지 구조 옮기기 * refactor(kitchen pos) : sql script 가 작동하도록 DeliveryOrder 주석 처리 * feat(kitchen pos) : 첫번째 미션에서 수행한 테스트 코드 다시 가져오기 * fix(kitchen pos) : 레거시 코드의 마진이 남지 않는 문제 코드 수정 * fix(kitchen pos) : ControllerTest 들이 pathVariable을 잘 인식하도록 문자열 추가 * feat(kitchen pos) : 첫번째 미션에 존재하는 Menu name 빈 문자열 검증 로직 추가 * feat(kitchen pos) : 예외를 처리할 수 있도록 ExceptionHandler 추가 * style(kitchen pos) : import 문 최적화 및 정렬 * feat(kitchen pos) : 이름 생성 객체 추가 * feat(kitchen pos) : 가격 생성 객체 추가 * feat(kitchen pos) : NameCreationService 추가 및 NameCreationService 만 Name 생성 책임을 가질 수 있도록 protected 접근 제어자 사용 * refactor(kitchen pos) : Name, Price, NameCreationService 코드에 적용 * refactor(kitchen pos) : Name, Price Embeddable 설정 및 기본 생성자 null 초기화 * feat(kitchen pos) : Name, Price equals & hashcode 추가 * feat(kitchen pos) : 마진을 검증하는 MarginValidator 생성 및 적용 * refactor(kitchen pos) : MarginValidator -> ProductServiceTest 에 적용 * refactor(kitchen pos) : import 문 최적화 및 필요없는 종속성 로컬 변수로 수정하기 * chore(kitchen pos) : 첫번째 미션에서 가져온 테스트 코드 패키지 구조 변경 * fix(kitchen pos) : ProductRestControllerTest 실패 해결 ~> jsonPath expression 수정 * fix(kitchen pos) : 필요 없는 애노테이션 제거 * refactor(kitchen pos) : Name -> ProductName, Menu -> ProductMenu * refactor(kitchen pos) : NameCreationService -> ProductNameCreationService * refactor(kitchen pos) : MarginValidator 가 MenuRepository에 강하게 의존하고 있어 패키지 이동
* chore(kitchen pos) : InMemoryProductRepository 패키지 구조 옮기기 * refactor(kitchen pos) : sql script 가 작동하도록 DeliveryOrder 주석 처리 * feat(kitchen pos) : 첫번째 미션에서 수행한 테스트 코드 다시 가져오기 * fix(kitchen pos) : 레거시 코드의 마진이 남지 않는 문제 코드 수정 * fix(kitchen pos) : ControllerTest 들이 pathVariable을 잘 인식하도록 문자열 추가 * feat(kitchen pos) : 첫번째 미션에 존재하는 Menu name 빈 문자열 검증 로직 추가 * feat(kitchen pos) : 예외를 처리할 수 있도록 ExceptionHandler 추가 * style(kitchen pos) : import 문 최적화 및 정렬 * feat(kitchen pos) : 이름 생성 객체 추가 * feat(kitchen pos) : 가격 생성 객체 추가 * feat(kitchen pos) : NameCreationService 추가 및 NameCreationService 만 Name 생성 책임을 가질 수 있도록 protected 접근 제어자 사용 * refactor(kitchen pos) : Name, Price, NameCreationService 코드에 적용 * refactor(kitchen pos) : Name, Price Embeddable 설정 및 기본 생성자 null 초기화 * feat(kitchen pos) : Name, Price equals & hashcode 추가 * feat(kitchen pos) : 마진을 검증하는 MarginValidator 생성 및 적용 * refactor(kitchen pos) : MarginValidator -> ProductServiceTest 에 적용 * refactor(kitchen pos) : import 문 최적화 및 필요없는 종속성 로컬 변수로 수정하기 * chore(kitchen pos) : 첫번째 미션에서 가져온 테스트 코드 패키지 구조 변경 * fix(kitchen pos) : ProductRestControllerTest 실패 해결 ~> jsonPath expression 수정 * fix(kitchen pos) : 필요 없는 애노테이션 제거 * refactor(kitchen pos) : Name -> ProductName, Menu -> ProductMenu * refactor(kitchen pos) : NameCreationService -> ProductNameCreationService * refactor(kitchen pos) : MarginValidator 가 MenuRepository에 강하게 의존하고 있어 패키지 이동 * feat(kitchen pos) : MenuName 생성 * feat(kitchen pos) : MenuPrice 생성 * feat(kitchen pos) : MenuGroupName 생성 * refactor(kitchen pos) : MenuGroupService 리팩토링 * refactor(kitchen pos) : setDisplayed -> changeDisplay * refactor(kitchen pos) : MenuPrice, MenuName 코드에 적용하기 * refactor(kitchen pos) : MarginValidator 적용하기 * feat(kitchen pos) : MenuProductQuantity 생성 * refactor(kitchen pos) : MenuProductQuantity 적용하기 * feat(kitchen pos) : Menu 에 메뉴 그룹 및 메뉴 상품 존재 검증 로직 추가 * test(kitchen pos) : Menu 검증 로직 추가로 인한 테스트 수정 * feat(kitchen pos) : MenuProductValidator 생성 * refactor(kitchen pos) : MenuProductValidator 적용하기 * refactor(kitchen pos) : MenuService 리팩토링 * feat(kitchen pos) : MenuNameCreationService, MenuGroupNameCreationService 생성 * refactor(kitchen pos) : MenuNameCreationService 및 MenuGroupNameCreationService 적용 * style (kitchen pos) : 사용되지 않는 import 문 제거 * Revert "style (kitchen pos) : 사용되지 않는 import 문 제거" This reverts commit 3421e43. * chore(kitchen pos) : InMemoryProductRepository 패키지 구조 옮기기 * refactor(kitchen pos) : sql script 가 작동하도록 DeliveryOrder 주석 처리 * feat(kitchen pos) : 첫번째 미션에서 수행한 테스트 코드 다시 가져오기 * style(kitchen pos) : import 문 최적화 및 정렬 * feat(kitchen pos) : 이름 생성 객체 추가 * feat(kitchen pos) : 가격 생성 객체 추가 * feat(kitchen pos) : NameCreationService 추가 및 NameCreationService 만 Name 생성 책임을 가질 수 있도록 protected 접근 제어자 사용 * refactor(kitchen pos) : Name, Price, NameCreationService 코드에 적용 * refactor(kitchen pos) : Name, Price Embeddable 설정 및 기본 생성자 null 초기화 * feat(kitchen pos) : Name, Price equals & hashcode 추가 * feat(kitchen pos) : 마진을 검증하는 MarginValidator 생성 및 적용 * refactor(kitchen pos) : MarginValidator -> ProductServiceTest 에 적용 * refactor(kitchen pos) : import 문 최적화 및 필요없는 종속성 로컬 변수로 수정하기 * chore(kitchen pos) : 첫번째 미션에서 가져온 테스트 코드 패키지 구조 변경 * fix(kitchen pos) : ProductRestControllerTest 실패 해결 ~> jsonPath expression 수정 * fix(kitchen pos) : 필요 없는 애노테이션 제거 * refactor(kitchen pos) : Name -> ProductName, Menu -> ProductMenu * refactor(kitchen pos) : NameCreationService -> ProductNameCreationService * refactor(kitchen pos) : MarginValidator 가 MenuRepository에 강하게 의존하고 있어 패키지 이동 * feat(kitchen pos) : MenuName 생성 * feat(kitchen pos) : MenuPrice 생성 * feat(kitchen pos) : MenuGroupName 생성 * refactor(kitchen pos) : MenuGroupService 리팩토링 * refactor(kitchen pos) : setDisplayed -> changeDisplay * refactor(kitchen pos) : MenuPrice, MenuName 코드에 적용하기 * refactor(kitchen pos) : MarginValidator 적용하기 * feat(kitchen pos) : MenuProductQuantity 생성 * refactor(kitchen pos) : MenuProductQuantity 적용하기 * feat(kitchen pos) : Menu 에 메뉴 그룹 및 메뉴 상품 존재 검증 로직 추가 * test(kitchen pos) : Menu 검증 로직 추가로 인한 테스트 수정 * feat(kitchen pos) : MenuProductValidator 생성 * refactor(kitchen pos) : MenuProductValidator 적용하기 * refactor(kitchen pos) : MenuService 리팩토링 * feat(kitchen pos) : MenuNameCreationService, MenuGroupNameCreationService 생성 * refactor(kitchen pos) : MenuNameCreationService 및 MenuGroupNameCreationService 적용 * style (kitchen pos) : 사용되지 않는 import 문 제거 * Revert "style (kitchen pos) : 사용되지 않는 import 문 제거" This reverts commit 3421e43. * merge (kitchen pos) : upstream step1 conflict resolve * docs(kitchen pos) : 요구사항에 메뉴 카테고리 비속어 검증 추가 * refactor(kitchen pos) : MenuService 메뉴를 게시하기 전에 마진을 검증하도록 수정
…erFlowNot 관련 메소드 문제 해결 ~> 네이밍 쿼리 필드 이름 변경!
# Conflicts: # src/main/java/kitchenpos/order/common/exception/OrderLineItemExceptionMessage.java # src/main/java/kitchenpos/order/eatinorder/domain/model/EatInOrder.java # src/main/java/kitchenpos/order/eatinorder/service/EatInOrderService.java # src/test/java/kitchenpos/order/eatinorder/service/EatInOrderServiceTest.java
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안녕하세요 수찬님 😄
cqrs 모델 잘 만들어 주신것 같아요
코멘트로 제가 방향성 관련 내용을 드렸는데
일단 내용을 한번 봐주시고 방향성을 잡고 가는게 좋아서 일단 메뉴만 확인했습니다.
확인 부탁드립니다 🙂
@Entity | ||
public class MenuSummary { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
일단 이부분에 대해서 수찬님께서 어떻게 만들어 가실지 생각해보셔야 할것 같습니다. 🙂
이 읽기 모델이 단순 빠른 조회를 위함인지, 아니면 읽기를 위한 테이블을 따로 생성해서 가실건지에 따라 좀 달라질것 같습니다.
빠른 조회를 위함이라면 dto의 성격으로 클래스를 구성해야 할것 같고 읽기 테이블을 따로 운영하는 느낌으로 가신다면 엔티티 형태의 클래스로 가는게 맞을 것 같아요
dto의 성격이라면 entity 관련 정보를 제거하고 ( entity, id, join 등) 정말 기능적으로 필요한 필드만 선언해서 사용하는 방식으로 가야할 것 같습니다 😄
추가로 이 부분에 대한 제 의견을 드리면
조회 모델을 생성할 때, application 계층을 안 만들기도 하는거 같은데, 이럴 때는 쿼리 모델도 domain 계층이 아닌 infra 계층의 model 패키지를 만들어 둘 수 있을 것 같은데, 그러면 MenuQueryModelSynchronizer 와의 의존성이 잘못될 것 같아, 이 부분도 리뷰어님의 의견이 궁금합니다.
infra 계층에 model 패키지를 만드는건 조심스러운 부분인것 같습니다. 말씀하신 의존성도 그렇고
application 계층을 만들지 않더라도 조회 모델은 결국 도메인의 정의, 관계에 영향을 많이 받는 부분이라 생각이 들기 때문에 infra 계층에 어울리진 않지 않나 생각합니다.
|
||
public void setName(final String name) { | ||
this.name = new MenuName(name); | ||
registerEvent(MenuSummaryEvent.from(this)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
읽기 모델 업데이트를 위한 이벤트 👍
@Repository | ||
public interface MenuQueryRepository { | ||
|
||
List<MenuSummary> findAll(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
질문주신 2가지의 제 의견을 여기서 드릴 수 있을 것 같아요 🙂
cqrs를 적용할 때 이 처럼 최적화가 필요한 부분만 적용하는지 아니면 findById까지 적용해서 진행하는지도 궁금합니다.
저는 필요한 부분만 하면 되지 않을까 생각합니다 🙂
읽기 모델은 만든 이유는 기존 도메인 모델을 가지고 읽기 성능에 애로사항이 있기 때문이고 해당 부분한 해소시켜주면 될거라 생각합니다.
또한 쿼리 최적화를 하실 때 querydsl를 사용하는지 jdbcTemplate을 많이 사용하시는지도 궁금합니다.
저 같은 경우에는 querydsl을 쓰려고 노력하고 있습니다 😅
사실 저는 회사에서 Mybatis에서 JPA로 마이그레이션 작업을 하고 있습니다.
처음에는 jdbcTemplate이나 네이티브 쿼리로 작성해서 작업을 했었는데 하다 보니
그냥 쿼리를 mybatis 사용하듯이 작성하는데 마이그레이션의 의미가 부족해 보이는것도 있고
어떤 부분은 쿼리간에 공유해서 사용할 수 있는 부분도 있고 해서 querydsl이 더 깔끔하게 쓸수 있을것 같아서
querydsl을 쓰고 있습니다.
안녕하세요 리뷰어님!
이번에는 menu 부분 cqrs 적용해봤습니다!
조회 모델을 만들어 최적화할 부분이 findAll 부분이라 생각해 이 부분에 대해 적용해봤습니다!
그 과정에서 MenuSummary와 ProductSummary를 생성했고, 각 id는 menu와 product의 id를 사용하도록 해 싱크를 맞췄습니다!
(이후 menu가 업데이트 되어 menuSummary가 업데이트 되면 jpa save(merge) 로 업데이트 되도록)
그리고 이후 Menu가 업데이트 되면 registerEvent를 통해 이벤트를 날려 조회 모델을 계속 업데이트 하도록 만들었습니다!
(+ 이번에는 MenuQueryRepository 테스트를 진행해봤습니다. )
(+ 또한 MenuQueryModelSynchronizer는 SpringBootTest를 통해 이벤트를 수신하고 제대로 적용하는지 확인해봤습니다.)
cqrs를 적용할 때 이 처럼 최적화가 필요한 부분만 적용하는지 아니면 findById까지 적용해서 진행하는지도 궁금합니다.
또한 쿼리 최적화를 하실 때 querydsl를 사용하는지 jdbcTemplate을 많이 사용하시는지도 궁금합니다.
조회 모델을 생성할 때, application 계층을 안 만들기도 하는거 같은데, 이럴 때는 쿼리 모델도 domain 계층이 아닌 infra 계층의 model 패키지를 만들어 둘 수 있을 것 같은데, 그러면 MenuQueryModelSynchronizer 와의 의존성이 잘못될 것 같아, 이 부분도 리뷰어님의 의견이 궁금합니다.
일단 구현해보긴 했는데 제대로 적용한지는 모르겠네요 ㅎㅎ
감사합니다 :)