Skip to content
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

3단계 - 리팩터링(매장 식사 주문) #289

Open
wants to merge 63 commits into
base: pawoo0211
Choose a base branch
from

Conversation

pawoo0211
Copy link

현수님 안녕하세요~ 3단계 진행하여 PR 생성합니다.

먼저 코드가 지저분해져서 보기 어려우실 것 같아 죄송하다는 말씀 먼저 드립니다.. 코드가 지저분해진 이유는 도메인 서비스(ACL)를 강제로 의존하게 되면서 Repository에 주문 테이블이나 메뉴를 반드시 save 해야 하는 강제성 때문에 지저분해졌네요..

부패 방지 레이어(EatInOrderServiceAdapter)를 사용해서 도메인 코드를 보호하려고 했는데 뭔가 보호되지 않은 느낌이라 방향성이 좀 잘못되고 있다고 생각해 현재까지 진행한 부분에 대해서 PR 생성드린 후에 피드백 받아 개선하도록 하겠습니다.

감사합니다.

pawoo0211 added 30 commits May 23, 2024 22:03
루트 엔티티를 제외한 하위 엔티티에서는 래핑한 Vo를 반환하도록 변경
Copy link

@hyunssooo hyunssooo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요.
추가로 몇 가지 코멘트 남겼습니다.
확인 부탁드려요! 🙂

Comment on lines 19 to 23
@Transient
private BigDecimal price;

@Transient
private UUID menuId;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 경우 메뉴 MC 에서 menu name이 변경되는 경우 어떻게 처리 될까요?

얼마 전에 저희 DM 으로 Menu BC에서의 menu와 Order BC에서 Menu는 의미하는 바가 다름을 도출했는데요. 이를 코드로 녹여보는 것은 어떨까요? Order에 Menu 모델이 만들어 질 수도 있지 않을까요?

Comment on lines 27 to 29
public OrderLineItem(Long seq, long quantity, BigDecimal price) {
this(seq, quantity, price, null);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여러 생성자를 둬 클라이언트에게 편의를 주는 것은 좋은데요. menu는 없어도 괜찮나요?

Comment on lines 10 to 12

Optional<OrderTable> findBy(UUID id);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Optional<OrderTable> findBy(UUID id);
}
Optional<OrderTable> findById(UUID id);
}

Comment on lines 19 to 23
@Transient
private BigDecimal price;

@Transient
private UUID menuId;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

price와 menuId는 Transient 로 선언되어도 괜찮나요?

Comment on lines 23 to 28
@Column(name = "occupied", nullable = false)
private boolean occupied;

@Transient
private OrderTableStatus status;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

occupied 와 status 모두 필요할까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

논리적으로 동일하네요 하하..

Comment on lines 18 to 20
@EventListener
public void setEmptyTable(CompletedOrderEvent event) {
System.out.println("주문 테이블 빈 테이블 설정");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

필요하다면 로그를 남기는 것은 어떨까요?

Comment on lines +1 to 2
package kitchenpos.menus.tobe.domain.common;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

패키지가 조금 어색한 것 같은데요. 모든 BC에서 사용한다면 kitchenpos.common 으로 둬도 괜찮을 것 같긴해요!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 좀 설명이 부족했던 것 같은데요. price 클래스가 여러개로 보이네요. BC 별로 정의 한다면 명확하게 정의하는 것이 좋을 것 같고 모든 BC에서 사용하면 kitchenpos.common 에 위치할 수 있을 것 같아요.

Comment on lines +30 to +43

@SpringBootTest
@DisplayName("매장 주문 완료 도메인 서비스 테스트")
public class EatInOrderCompletePolicyTest {
@Autowired
private EatInOrderCompletePolicy completePolicy;
@MockBean
private EatInOrderRepository orderRepository;
@MockBean
private OrderTableRepository tableRepository;

private MenuRepository menuRepository;
private ToBeFixtures toBeFixtures;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

꼼꼼한 테스트 👍
EatInOrderCompletePolicy에 ApplicationEventPublisher를 주입 받고 있어 SpringBootTest를 사용하신 것 같네요. 여러방법이 있지만 ApplicationEventPublisher는 인터페이스입니다. 이를 활용해 fake 객체를 만들어 보는 것도 좋을 것 같아요.
혹은 이벤트를 도메인 모델에서 발급해도 괜찮을 것 같아요. AbstractAggregateRoot

별도로 @RecordApplicationEvents , ApplicationEvents 도 찾아보면 좋을 것 같아요.

이 부분은 참고만 부탁드립니다. :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵, 말씀 감사합니다!

제가 이벤트 기반이 익숙치 않아서 일단 가장 기본적인 형태로 구현했습니다. 말씀해주신 부분들도 학습해보겠습니다~

Comment on lines +8 to +10

public class FakeEatInOrderRepository implements EatInOrderRepository {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

가짜 객체 👍

Comment on lines +12 to +18

@DisplayName("주문 항목 도메인 테스트")
public class OrderLineItemTest {

@Test
@DisplayName("주문 항목을 생성한다.")
void create() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위에서도 남겼지만 주문 항목에 menu는 필수가 아닌가요?

Copy link

@hyunssooo hyunssooo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요.
가벼운 코멘트 몇 가지 남겼습니다!
끝이 보이는데요! 마지막까지 힘내시면 좋겠습니다! 🙂
언제든 DM 남겨주세요!

Comment on lines +10 to +12

@Embeddable
public class MenuInEatInOrders {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eatinorders 내부에 Menu 정의 👍

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기본 생성자는 필요하지 않을까요?

Comment on lines +16 to +20
@Transient
private boolean isDisplayedMenu;

@Transient
private Price price;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Transient 인 이유가 따로 있나요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

주문 테이블에서 위 정보를 굳이 저장할 필요성을 못느껴서 Transient를 적용했습니다.

DM에서도 현수님께서 이미 주문된 메뉴는 변경 가능성이 없다고 하셨는데 저 또한 해당 필드를 영속성으로 유지하거나 DB에 저장할 필요성을 못느껴서 Transient를 적용했습니다.

Comment on lines +12 to +14

@Component
public class UpdateMenuInOrders {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 도메인 서비스는 어떤 경우에 사용되나요?
메뉴의 변경에 따라서 이미 주문된 order 내부의 menu를 모두 update 하는 것 같은데요. 🤔

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메뉴의 정보가 바뀌었을 때를 가정하여 만든 도메인 서비스입니다. 실제 요구사항은 없지만 해당 상황을 가정하고 만드는 걸로 이해하여 만들었습니다.

Comment on lines +7 to +10

@Component
public class ChangedMenuSender {
private final ApplicationEventPublisher publisher;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

강의에서 다뤘을 것 같은데요. AbstractAggregateRoot 통해서 이벤트 발급도 가능합니다. :)
@TransactionalEventListener, @EventListener 키워드도 함께 찾아보면 좋을 것 같아요.
참고만 해주세요~

Comment on lines 16 to +18

public class ToBeFixtures {
public Menu 메뉴_치킨 = new kitchenpos.menus.tobe.domain.entity.Menu(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixtures 도 패키지가 나눠지면 좋을 것 같아요. :)

Comment on lines +12 to +14

public class EatInOrderAccept {
private OrderTableRepository tableRepository;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 클래스는 EatInOrder를 생성하는 시점에 사용될 것 같아요.

MenuInEatInOrders의 생성 시점은 언제인가요? 🤔

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bean으로 등록되지 않아도 괜찮나요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MenuInEatInOrders 생성 시점도 EatInOrders와 동일한 생성 시점으로 생각하고 있습니다.

MenuInEatInOrders에 대한 유효성을 검증하기 위해서는 EatInOrder 객체가 생성되어 하기에 EatInOrderTest 클래스에서 유효성 검증 테스트 코드 작성했습니다.

Comment on lines +1 to 2
package kitchenpos.menus.tobe.domain.common;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 좀 설명이 부족했던 것 같은데요. price 클래스가 여러개로 보이네요. BC 별로 정의 한다면 명확하게 정의하는 것이 좋을 것 같고 모든 BC에서 사용하면 kitchenpos.common 에 위치할 수 있을 것 같아요.

Comment on lines +19 to +21
@DisplayName("주문 도메인 테스트")
public class OrderTest {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테스트 클래스 이름이 EatInOrderTest 가 아니네요. 🤔

아래에 대한 요구 사항은 어떤 클래스의 책임일까요? 테스트로 작성되어야 하지 않을까요?
주문한 메뉴의 가격은 실제 메뉴 가격과 일치해야 한다.

Comment on lines +18 to +25
@Column(name = "quantity", nullable = false)
private long quantity;

@Embedded
private Price price;

@Embedded
private MenuInEatInOrders menuInOrders;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

궁금해서 그러는데 price는 MenuInEatInOrders.price와 동일한가요? 그렇다면 중복인 것 같은데요.
quantity * MenuInEatInOrders.price 라면 직접 계산할 수 도 있을 것 같아서요.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants