[volume-3] 도메인 구현 - 김진수#116
Open
plan11plan wants to merge 108 commits intoLoopers-dev-lab:plan11planfrom
Open
Conversation
- Password VO를 EncryptedPassword로 변경하여 암호화된 비밀번호임을 명확히 표현 - 서비스 계층에 SignupCommand, ChangePasswordCommand, UserInfo DTO 도입 - 컨트롤러에서 엔티티(UserModel) 직접 노출 제거 - Example 관련 코드 삭제 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- EncryptedPassword.of() 오버로드 제거 → 하나만 유지 (형식 검증 + 암호화) - UserModel 생성자에서 rawPassword + encoder를 받아 birthDate 교차 검증 수행 - 생성/변경 두 경로 모두 UserModel이 검증 → 일관성 확보 - 패스워드 설계 결정 문서 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…티 전파 보장 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
개인 목표 및 회고
목표
행동
아쉬웠던 점
기본 Application 컨벤션이 "도메인 안의 XXService(Repository 존재)를 조합하는 것"이다 보니, 일단 도메인들을 전부 패키지 분리로 시작하고 이후 합치는 상황을 고려하게 되었다.
개인적으로 DIP나 레이어별 책임이나 이런 고민들은, AI와 코딩하며, 그때 그때 컨벤션 문서를 업데이트해나가는식으로 개선해갔고, 레이버별 책임이 탄탄해진 것 같으나, 누가 내게 물어보면 말을 할 수 있겠는데, 문서 없이는 힘들 것 같아서 내가 왜 이렇게 규칙을 정했는지 계속 생각하고 읽어봐야겠다.
도메인간 경계를 무너뜨리고 합칠지, 분리할지가 이번 미션에서 나의 큰 관심사중 하나였다. Brand 1: N Product는 같은 패키지안에 둬야하나, 분리해야하나, Product에 like 필드를 지금 상황에서는 두는게 맞는것같은데, 미래를 생각해서 또는 비즈니스적 가치가 높은가로 엔티티로 쪼갤까 말까 하는 등등. 이게 현재 상황에서는 최소화가 맞는 것 같은데, 어느시점까지 이 정책들을 유지할 수 있는지 그런게 좀 감이 잘 안잡힌다.
Context & Decision
선택지와 결정
1. 레이어 간 책임 분리
2. 도메인 간 참조 방식
@ManyToOne+@JoinColumn)private Long brandId)@JoinColumn(foreignKey = NO_CONSTRAINT))product.getBrand().getName()편의보다 일관성이 더 중요하다고 판단하여 ID 참조로 리팩토링BrandService.getActiveNameMapByIds()로 Facade에서 조합3. 좋아요 수 집계 방식
4. likes_desc 정렬 방식
Design Overview
변경 범위
아키텍처 구조
의존 방향:
interfaces → application → domain ← infrastructure주요 컴포넌트 책임
Facade (Cross-Domain 오케스트레이션):
BrandFacade: Brand CRUD, 목록 조회ProductFacade: Product CRUD + Brand 이름 조합 + Like 수 enrichment + likes_desc 정렬OrderFacade: 주문 생성 (재고 차감, 가격 검증, 스냅샷 생성) + 소유권 검증LikeFacade: 좋아요 등록/취소 + Product 존재 검증UserFacade: 회원가입 (암호화) + 내 정보 조회 + 비밀번호 변경Domain Service (단일 도메인 규칙):
BrandService: 중복 이름 검증, 활성 브랜드 필터링, ID → 이름 맵 제공ProductService: 재고 차감, 가격 검증, 브랜드별/전체 조회OrderService: 주문 생성, 소유권 검증, 기간별 조회ProductLikeService: 좋아요 등록/취소, 일괄 좋아요 수 집계UserService: 회원가입, 비밀번호 변경, 로그인 ID 조회Domain Model (비즈니스 규칙 캡슐화):
ProductModel:decreaseStock(),validateExpectedPrice(),isSoldOut()— 엔티티가 상태 변경의 주체OrderModel:validateOwner()— 소유권 검증은 엔티티 책임OrderItemModel:productName,brandName스냅샷 필드 — 주문 시점 기록 보존ProductLikeModel:userId + productId유니크 제약 — DB 레벨 중복 방지도메인 관계
graph TB User["User"] Brand["Brand"] Product["Product"] Like["Like"] Order["Order"] OrderItem["OrderItem"] Brand ---|"ID 참조"| Product User ---|"ID 참조"| Like User ---|"ID 참조"| Order Product ---|"ID 참조"| Like Product -->|"스냅샷"| OrderItem Order --- OrderItemAPI 엔드포인트
Flow Diagram
주문 생성 (Cross-Domain: 재고 차감 + 가격 검증 + 스냅샷)
sequenceDiagram autonumber participant Client participant Controller participant OrderFacade participant ProductService participant BrandService participant OrderService Client->>Controller: POST /api/v1/orders Controller->>OrderFacade: createOrder(userId, criteria) OrderFacade->>ProductService: getAllByIds(productIds) ProductService-->>OrderFacade: List<ProductModel> loop 각 주문 항목 Note over OrderFacade: product.validateExpectedPrice(expectedPrice) Note over OrderFacade: product.decreaseStock(quantity) end OrderFacade->>BrandService: getNameMapByIds(brandIds) BrandService-->>OrderFacade: Map<brandId, name> Note over OrderFacade: OrderItem 생성 (productName, brandName 스냅샷) OrderFacade->>OrderService: createOrder(command) OrderService-->>OrderFacade: OrderModel OrderFacade-->>Controller: OrderSummary Controller-->>Client: ApiResponse상품 목록 조회 (Cross-Domain: Brand 이름 + Like 수 조합)
sequenceDiagram autonumber participant Client participant Controller participant ProductFacade participant ProductService participant BrandService participant LikeService Client->>Controller: GET /api/v1/products Controller->>ProductFacade: getProductsWithActiveBrand(pageable) ProductFacade->>ProductService: getAll(pageable) ProductService-->>ProductFacade: Page<ProductModel> ProductFacade->>BrandService: getActiveNameMapByIds(brandIds) BrandService-->>ProductFacade: Map<brandId, name> ProductFacade->>LikeService: countLikesByProductIds(productIds) LikeService-->>ProductFacade: Map<productId, count> Note over ProductFacade: 활성 브랜드 필터 + likeCount enrichment ProductFacade-->>Controller: Page<ProductResult> Controller-->>Client: ListResponse구현 범위 요약
테스트
주요 리팩토링 이력
@EmbeddableJPA 마찰(null 전파,@AttributeOverride) 대비 이점이 적었음