[chore] 패키지 구조 with 예시 코드#12
Conversation
| @Component | ||
| @RequiredArgsConstructor | ||
| public class UserCommandFacade { | ||
|
|
||
| /** | ||
| * 여기에 command 관련 use case(= incoming port = interface) 전부 주입 | ||
| */ | ||
| private final UserSignupUseCase userSignupUseCase; | ||
| private final UserUpdateUseCase userUpdateUseCase; | ||
|
|
||
| public Long signup(UserSignupCommand command) { | ||
| return userSignupUseCase.signup(command); | ||
| } | ||
|
|
||
| public void updateUser(UserUpdateCommand command) { | ||
| userUpdateUseCase.update(command); | ||
| } | ||
| } |
There was a problem hiding this comment.
이론적으로만 이야기하다 코드로 이 패턴을 확인해보니 2가지 정도 우려되는 부분이 있어서 작성해봤습니다.
-
UseCase를 단위 트랜잭션으로 사용하면 CommandFascade와 QueryFascade가 같은 UseCase를 공유하는 경우가 발생할 수도 있을 것 같은데 괜찮을지 고민입니다. 현재 구조에서는 단위 트랜잭션을 기준으로 UseCase가 나뉘고, Fascade가 이를 조합하는 방식인데요. 예를 들어 회원가입 로직에서
a. 닉네임 중복 검증, b. 회원 저장이라는 두 단위 트랜잭션이 있다고 가정하면, 각각 CheckDuplicateUseCase(Query), UserSignupUseCase(Command)로 나뉘게 됩니다. 그런데 닉네임 중복 검증 로직이 다른 Query API에서도 사용된다면, CheckDuplicateUseCase를 CommandFascade, QueryFascade 양쪽에서 모두 주입받아 사용하는 상황이 발생할 수 있을 것 같아 이 부분이 괜찮을지 고민이 됩니다. -
두 번째는 UseCase의 정의 기준과 그 수에 대한 우려입니다. 기존 헥사고날 아키텍처에서는 API 명세를 기준으로 UseCase를 1:1로 정의하고, 그 안에서 필요한 서비스 로직들을 구현하는 흐름으로 이해하고 있었는데요. 지금처럼 Fascade 패턴을 도입하면 UseCase가 API 명세와 1:1로 매핑되지 않고, 오히려 더 세분화되어 UseCase의 수가 많아질 수 있다는 점이 조금 고민됩니다. 물론, 이는 UseCase의 재사용 빈도에 따라 충분히 설계상의 장점이 될 수도 있지만, 전체적인 구조를 초반에 설계하는 관점에서는 고려할 지점인 것 같습니다.
|
수고하셨습니다~~ 설명 자세하게 적어주셔서 보기 편하네요!!💯💯 |
seongjunnoh
left a comment
There was a problem hiding this comment.
의논한 사항 반영해서 패키지 구조 수정 후, api 명세서를 기반으로 저희 프로젝트들의 도메인 패키지 구조를 작성해보았습니다.
각 도메인 마다 헥사고날 아키텍처의 adapter, application, domain 패키지를 정의하였고, 모든 리프 패키지마다 더미 클래스 하나씩 추가했습니다.
스프링 빈 컨텍스트 로드시, jpa entity가 인식되도록 @entity 어노테이션 추가
seongjunnoh
left a comment
There was a problem hiding this comment.
@hd0rable 희진님, 현재 build가 되도록 jpa entity를 임시로 추가해뒀는데 이부분은 자유롭게 수정해주시면 됩니다!
hd0rable
left a comment
There was a problem hiding this comment.
수고하셨어요~~!! 👍🏻👍🏻 패키지양 후덜덜하네요..
| import jakarta.persistence.Id; | ||
|
|
||
| @Entity | ||
| public class BookJpaEntity { |
There was a problem hiding this comment.
이부분은 예시로 BookJpaEntity로 작성한것이 맞죠?? 실제 JpaEntity를 작성할때 도메인과 같이 Book으로 작성해도되는걸까요??
There was a problem hiding this comment.
넵 예시로 넣어둔 클래스 중
- BookJpaEntity -> jpa entity 를 의미
- Book -> domain entity(= 자바 코드) 를 의미
이렇게 생각해주시면 됩니다!
JpaEntity 의 네이밍을 Book 이렇게 도메인 네이밍으로 작성하면, 도메인 엔티티의 네이밍을 Book 이 아니라 다르게 정의한다는 말씀이신가요??
저는 실제 api 구현시에 도메인 entity 가 코드 흐름의 대부분을 담당하니, 도메인 entity의 네이밍을 직관적인 Book 이런식으로 작성했긴 합니다!!
There was a problem hiding this comment.
아아 아뇨!! 어차피 패키지 구조가 달라서 구분할수있으니 같은 이름으로 정의하는 방식을 생각했었는데, 성준님이 말씀하신것처럼 JpaEntity 의 네이밍을 BookJpaEntity 이런식으로 표시하는것이 더 좋겠네요!! 참고해서 패키지 구조 머지되서 수정할떄 네이밍도 수정하도록하겠습니다~!!
buzz0331
left a comment
There was a problem hiding this comment.
패키지 구조 짜느라 고생하셨습니다~!! 🥇
| package konkuk.thip.book.application.port.in.dto; | ||
|
|
||
| import lombok.Builder; | ||
| import lombok.Getter; | ||
|
|
||
| @Getter | ||
| @Builder | ||
| public class DummyResult { | ||
|
|
||
| } |
There was a problem hiding this comment.
dto 네이밍 일부러 DummyQuery가 아닌 DummyResult로 하신건가요?
| package konkuk.thip.comment.adapter.in.web.request; | ||
|
|
||
| import lombok.Getter; | ||
|
|
||
| @Getter | ||
| public class DummyRequest { | ||
| } |
There was a problem hiding this comment.
record 쓰는 것에 대해서 한번더 논의해봐야겠네욥
#️⃣ 연관된 이슈
📝 작업 내용
<user 패키지 하위 구조에 대한 상세 설명>
📸 스크린샷
💬 리뷰 요구사항
전체 프로젝트 도메인들에 대하여 패키지 구조를 확립하기 전에, 특정 도메인에 대한 내부 패키지 구조를 의논한 후에 전체 도메인에 동일하게 적용하는 순서가 좋지않을까 해서 일단 "user" 도메인에 대해서만 코드를 작성해봤습니다.
작성한 패키지 구조에 대한 설명을 글로만 적기가 애매모호하다고 생각해, 간단한 예시 코드를 추가해놨습니다.
예시코드는 저희 프로젝트의 api 스펙과는 무관하며, 패키지 구조에 대한 논의가 끝나면 지울 예정입니다!
'현재 패키지 구조에서는 api request -> response 과정에서 코드가 내부적으로 이렇게 흘러가는구나 ~~' 라는 느낌으로 가볍게 봐주시면 될것 같습니다!
📌 PR 진행 시 이러한 점들을 참고해 주세요