Skip to content

[chore] 패키지 구조 with 예시 코드#12

Merged
seongjunnoh merged 15 commits into
developfrom
chore#10-build-package-template
Jun 1, 2025
Merged

[chore] 패키지 구조 with 예시 코드#12
seongjunnoh merged 15 commits into
developfrom
chore#10-build-package-template

Conversation

@seongjunnoh
Copy link
Copy Markdown
Collaborator

#️⃣ 연관된 이슈

closes #10

📝 작업 내용

  • 헥사고날 아키텍처에 기반하여 "user" 도메인에 한해 예시 코드 작성
  • 최상위 "user" 패키지 하위에 "adapter", "application", "domain" 패키지 추가

<user 패키지 하위 구조에 대한 상세 설명>

  • adapter/in/web
    • user 도메인 관련 api 진입점인 Controller는 Command/Query 2개의 class로 분리
    • 각 Controller는 하나의 Facade class 랑만 의존관계를 가짐 (Facade 또한 Command/Query 로 분리)
  • application/port/in
    • 각 Facade class는 Command or Query 와 관련된 모든 use case 에 대한 의존성 가지고 있음
      • 이렇게 controller -> facade -> usecase(= incoming port) 로 의존성 방향을 설정함으로써 비즈니스 로직 변경시에도 controller 코드의 수정사항은 없음 (facade에 usecase 의존성을 추가로 주입해주면 됨)
      • 또한 facade를 도입함으로써 하나의 use case가 너무 많은 책임을 가지게 되는 이슈를 해결할 수 있음
  • application/service
    • use case의 구현체인 Service class -> 얘가 도메인 엔티티와의 communication을 통해 비즈니스 로직을 수행
  • application/port/out
    • Service는 DB i/o를 위해 interface인 outgoing port를 호출
  • adapter/out/persistence
    • outgoing port의 구현체인 PersistenceAdapter는 실제 DB i/o 를 수행
    • 이때 domain 엔티티 <-> jpa 엔티티의 변환 과정이 필요

📸 스크린샷

image

💬 리뷰 요구사항

전체 프로젝트 도메인들에 대하여 패키지 구조를 확립하기 전에, 특정 도메인에 대한 내부 패키지 구조를 의논한 후에 전체 도메인에 동일하게 적용하는 순서가 좋지않을까 해서 일단 "user" 도메인에 대해서만 코드를 작성해봤습니다.

작성한 패키지 구조에 대한 설명을 글로만 적기가 애매모호하다고 생각해, 간단한 예시 코드를 추가해놨습니다.
예시코드는 저희 프로젝트의 api 스펙과는 무관하며, 패키지 구조에 대한 논의가 끝나면 지울 예정입니다!
'현재 패키지 구조에서는 api request -> response 과정에서 코드가 내부적으로 이렇게 흘러가는구나 ~~' 라는 느낌으로 가볍게 봐주시면 될것 같습니다!

📌 PR 진행 시 이러한 점들을 참고해 주세요

* P1 : 꼭 반영해 주세요 (Request Changes) - 이슈가 발생하거나 취약점이 발견되는 케이스 등
* P2 : 반영을 적극적으로 고려해 주시면 좋을 것 같아요 (Comment)
* P3 : 이런 방법도 있을 것 같아요~ 등의 사소한 의견입니다 (Chore)

buzz0331
buzz0331 previously approved these changes May 30, 2025
Copy link
Copy Markdown
Contributor

@buzz0331 buzz0331 left a comment

Choose a reason for hiding this comment

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

가이드라인을 명확히 제시해 주셔서 보기 편했습니다! 수고하셨습니다~ 💯

헥사고날 아키텍처 + Fascade 패턴에 대해서 Notion에 간단히 정리해봤습니다.
리뷰에 남긴 것처럼 단위 트랜잭션의 범위에 대한 정의, Fascade 패턴 추후 도입에 대한 부분을 조금더 상의해봐야 될 것 같습니다.

Comment on lines +8 to +25
@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);
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

이론적으로만 이야기하다 코드로 이 패턴을 확인해보니 2가지 정도 우려되는 부분이 있어서 작성해봤습니다.

  1. UseCase를 단위 트랜잭션으로 사용하면 CommandFascade와 QueryFascade가 같은 UseCase를 공유하는 경우가 발생할 수도 있을 것 같은데 괜찮을지 고민입니다. 현재 구조에서는 단위 트랜잭션을 기준으로 UseCase가 나뉘고, Fascade가 이를 조합하는 방식인데요. 예를 들어 회원가입 로직에서 a. 닉네임 중복 검증, b. 회원 저장이라는 두 단위 트랜잭션이 있다고 가정하면, 각각 CheckDuplicateUseCase(Query), UserSignupUseCase(Command)로 나뉘게 됩니다. 그런데 닉네임 중복 검증 로직이 다른 Query API에서도 사용된다면, CheckDuplicateUseCase를 CommandFascade, QueryFascade 양쪽에서 모두 주입받아 사용하는 상황이 발생할 수 있을 것 같아 이 부분이 괜찮을지 고민이 됩니다.

  2. 두 번째는 UseCase의 정의 기준과 그 수에 대한 우려입니다. 기존 헥사고날 아키텍처에서는 API 명세를 기준으로 UseCase를 1:1로 정의하고, 그 안에서 필요한 서비스 로직들을 구현하는 흐름으로 이해하고 있었는데요. 지금처럼 Fascade 패턴을 도입하면 UseCase가 API 명세와 1:1로 매핑되지 않고, 오히려 더 세분화되어 UseCase의 수가 많아질 수 있다는 점이 조금 고민됩니다. 물론, 이는 UseCase의 재사용 빈도에 따라 충분히 설계상의 장점이 될 수도 있지만, 전체적인 구조를 초반에 설계하는 관점에서는 고려할 지점인 것 같습니다.

@hd0rable
Copy link
Copy Markdown
Member

수고하셨습니다~~ 설명 자세하게 적어주셔서 보기 편하네요!!💯💯
현준님이 리뷰 주신 것처럼 퍼사드 패턴을 사용한다고 했을때 트랜잭션 범위에대해서 추가적으로 고민해볼 것들이 있겠네요..🤔🤔

buzz0331
buzz0331 previously approved these changes May 31, 2025
Copy link
Copy Markdown
Collaborator Author

@seongjunnoh seongjunnoh left a comment

Choose a reason for hiding this comment

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

의논한 사항 반영해서 패키지 구조 수정 후, api 명세서를 기반으로 저희 프로젝트들의 도메인 패키지 구조를 작성해보았습니다.

각 도메인 마다 헥사고날 아키텍처의 adapter, application, domain 패키지를 정의하였고, 모든 리프 패키지마다 더미 클래스 하나씩 추가했습니다.

스프링 빈 컨텍스트 로드시, jpa entity가 인식되도록 @entity 어노테이션 추가
Copy link
Copy Markdown
Collaborator Author

@seongjunnoh seongjunnoh left a comment

Choose a reason for hiding this comment

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

@hd0rable 희진님, 현재 build가 되도록 jpa entity를 임시로 추가해뒀는데 이부분은 자유롭게 수정해주시면 됩니다!

hd0rable
hd0rable previously approved these changes Jun 1, 2025
Copy link
Copy Markdown
Member

@hd0rable hd0rable left a comment

Choose a reason for hiding this comment

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

수고하셨어요~~!! 👍🏻👍🏻 패키지양 후덜덜하네요..

import jakarta.persistence.Id;

@Entity
public class BookJpaEntity {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

이부분은 예시로 BookJpaEntity로 작성한것이 맞죠?? 실제 JpaEntity를 작성할때 도메인과 같이 Book으로 작성해도되는걸까요??

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

넵 예시로 넣어둔 클래스 중

  • BookJpaEntity -> jpa entity 를 의미
  • Book -> domain entity(= 자바 코드) 를 의미

이렇게 생각해주시면 됩니다!

JpaEntity 의 네이밍을 Book 이렇게 도메인 네이밍으로 작성하면, 도메인 엔티티의 네이밍을 Book 이 아니라 다르게 정의한다는 말씀이신가요??

저는 실제 api 구현시에 도메인 entity 가 코드 흐름의 대부분을 담당하니, 도메인 entity의 네이밍을 직관적인 Book 이런식으로 작성했긴 합니다!!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

아아 아뇨!! 어차피 패키지 구조가 달라서 구분할수있으니 같은 이름으로 정의하는 방식을 생각했었는데, 성준님이 말씀하신것처럼 JpaEntity 의 네이밍을 BookJpaEntity 이런식으로 표시하는것이 더 좋겠네요!! 참고해서 패키지 구조 머지되서 수정할떄 네이밍도 수정하도록하겠습니다~!!

buzz0331
buzz0331 previously approved these changes Jun 1, 2025
Copy link
Copy Markdown
Contributor

@buzz0331 buzz0331 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 +1 to +10
package konkuk.thip.book.application.port.in.dto;

import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class DummyResult {

}
Copy link
Copy Markdown
Contributor

@buzz0331 buzz0331 Jun 1, 2025

Choose a reason for hiding this comment

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

dto 네이밍 일부러 DummyQuery가 아닌 DummyResult로 하신건가요?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

  • Result : api response를 위해 service -> controller 로 전달되는 dto
  • Command : controller -> service 로 전달되는 dto (command api시)
  • Query : controller -> service 로 전달되는 dto (query api시)

를 의도하긴했는데, DummyQuery가 빠졌네요ㅎ

위 3가지의 dto 네이밍 어떠신가요? @hd0rable @buzz0331

Copy link
Copy Markdown
Contributor

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 +7
package konkuk.thip.comment.adapter.in.web.request;

import lombok.Getter;

@Getter
public class DummyRequest {
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

record 쓰는 것에 대해서 한번더 논의해봐야겠네욥

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

넵 좋습니다!

@seongjunnoh seongjunnoh dismissed stale reviews from buzz0331 and hd0rable via 0c17f4d June 1, 2025 15:20
@seongjunnoh seongjunnoh merged commit a2dfcc4 into develop Jun 1, 2025
1 check passed
@seongjunnoh seongjunnoh deleted the chore#10-build-package-template branch June 1, 2025 15:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[THIP2025-41] [chore] 기본 패키지 구조 작성

3 participants