[volume-3] 도메인 주도 설계 및 구현#92
Merged
APapeIsName merged 9 commits intoLoopers-dev-lab:APapeIsNamefrom Mar 2, 2026
Merged
Conversation
- 회원가입 기능 (검증 + 암호화 + 저장) - 내 정보 조회 기능 (인증 + 마스킹) - 비밀번호 변경 기능 (인증 + 검증 + 변경) - 컨트롤러 구현 (REST API 엔드포인트) - 단위 테스트, 통합 테스트, E2E 테스트 작성 - 예외 처리 (ErrorType + CoreException)
- 01. 요구사항 문서 - 02. 시퀀스 다이어그램 - 03. 클래스 다이어그램 - 04. ERD - 구조 리팩토링 계획서 - 아키텍처 논의 기록
|
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 |
# Conflicts: # .gitignore # docs/analysis/class-diagram-analysis.md # docs/analysis/erd-analysis.md # docs/analysis/prompt-design-process-analysis.md # docs/analysis/requirements-gathering-analysis.md # docs/analysis/sequence-diagram-analysis.md # docs/design/02-sequence-diagrams.md # docs/design/03-class-diagram.md # docs/design/04-erd.md # docs/design/base/class-diagram-erd.md # docs/design/base/domain-definition-v2.md # docs/design/base/member-class-diagram.md # docs/design/base/requirements-input.md # docs/design/base/sequence-diagrams.md # docs/design/base/ubiquitous-language.md # docs/design/base/user-story.md
88b245e to
be6bd78
Compare
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
🧭 Context & Decision
1. Domain? Application?
고민
결론
flowchart TD START["새 로직 추가"] --> Q1{"이 규칙은 기술 구현과 무관하게 항상 성립하는가?"} Q1 -->|"Yes — 논리적"| Q2{"단일 엔티티 상태/불변식인가?"} Q1 -->|"No — 물리적"| Q5{"BC 경계를 넘는 조율인가?"} Q2 -->|"Yes"| A1["Entity 또는 VO"] Q2 -->|"No"| Q3{"같은 BC 내 cross-aggregate 규칙인가?"} Q3 -->|"Yes"| A2["Domain Service"] Q3 -->|"No"| Q5 Q5 -->|"Yes"| A3["Application Service"] Q5 -->|"No"| Q6{"물리적 기술 관심사인가? (트랜잭션, 락, 데드락 방지)"} Q6 -->|"Yes"| A3 Q6 -->|"No"| Q7{"Application Service 간 순환 참조인가?"} Q7 -->|"Yes"| A4["Facade"] Q7 -->|"No"| A3 A1 --> DOMAIN["Domain Layer"] A2 --> DOMAIN A3 --> APP["Application Layer"] A4 --> APP style DOMAIN fill:#e8f5e9 style APP fill:#e3f2fd2. VO 선정 기준
고민
결론
🏗️ Design Overview
graph LR subgraph Presentation["Presentation Layer"] direction TB P_CTRL["Controller"] P_DTO["API DTO (Request / Response)"] P_RES["ApiResponse ApiControllerAdvice"] end subgraph Application["Application Layer"] direction TB A_SVC["Service"] A_DTO["Command / Info DTO"] end subgraph Domain["Domain Layer"] direction TB D_ENT["Entity (BaseEntity → BaseTimeEntity → SoftDeletableEntity)"] D_VO["VO (LoginId, Password, Name, Money ...)"] D_PORT["Repository / Port (interface)"] D_DS["Domain Service (BrandDeleteService, ActiveProductService)"] end subgraph Infrastructure["Infrastructure Layer"] direction TB I_JPA["jpa/ RepositoryImpl JpaRepository"] I_SEC["security/ BCryptPasswordEncryptor"] I_ETC["redis/ kafka/"] end subgraph Supports["Supports (Cross-cutting)"] direction TB S_ERR["error/ ErrorType, CoreException"] S_ETC["jackson/ logging/ monitoring/"] end Presentation -->|depends on| Application Application -->|depends on| Domain Infrastructure -->|"implements (Repository, PasswordEncryptor)"| Domain Supports -.->|"used by all layers"| DomainDomain Layer
기술 구현과 상관 없는 기능적인 요구사항(공책 게임으로 구현할 수 있는 요구사항) 을 구현하는 레이어
Entity, VO
JPA
@Entity,@Embeddable를 사용: 순수 도메인 엔티티보다 현재 프로젝트에서는 JPA 엔티티로 구현했을 때 단점이 더 작다 고 판단하였기 때문.순수한 도메인 엔티티로 사용했을 때 단점
JPA 엔티티로 사용했을 때 단점
위 단점들을 비교해봤을 때 현재 프로젝트인 감성 이커머스에서는 JPA 엔티티로 구현했을 때의 단점이 순수 도메인 엔티티로 구현했을 때보다 작다 고 판단함. 또한, Repository에 DIP를 적용했음에도, Entity 까지 따로 관리했을 때 비용이 많이 들지만 얻을 수 있는 이점은 적다고 생각하였고, 만약 예상치 못한 이유로 순수 도메인으로 변경해야 한다면 AI 로 빠르게 변경할 수 있다고 판단하여 JPA Entity 로 구현하게 됨.
Domain Service
Domain Service 나만의 정의: Domain Service는 단일 엔티티에서 구현 불가능하지만, 하나의 BC 내에서 책임을 맡는 기능을 구현
Service 의 의미는 Input 과 Output 을 가지며 상태를 가지지 않는다는 걸 기반
⇒
Service == 함수의 객체화라고 정의Domain Service도 하나의 객체라는 판단 하에 SRP 를 적용
⇒ 단일 엔티티에서 구현 불가능하지만, 하나의 BC 내에서 책임을 맡는 기능이라면 Domain Service에 해당
Repository
Application Layer
**비기능적인 요구사항(트랜잭션 등)**을 구현하거나, 도메인 레이어에서 해결하지 못하는 여러 BC들을 조합하여 기능을 구현하는 레이어.
Application Service
여러 도메인 계층의 BC나 외부 기술 등을 응용하여 비즈니스 로직으로 조합시켜 만드는, 인풋과 아웃풋이 분명한 함수 같은 객체
Facade (현재 프로젝트 내에는 없음)
Service 들을 가져와서 조합해야 하는데 Service 사이의 순환 참조가 발생할 때, 이를 막기 위해 만들어진 패턴
Presentation Layer (Interfaces Layer)
클래스를 매핑하여 사용자나 다른 서버 등 인터페이스로 값을 표현하는 레이어.
API DTO
(컨트롤러 기준) Application 의 Command / Query DTO 로부터 API 요청값 및 응답값을 매핑해 레이어 사이 또는 다른 개체(클라이언트, 서버 등)와 통신함.
ApiControllerAdvice
Domain 레이어의 ErrorType을 HttpStatus로 매핑
Infrastructure Layer
Domain Layer 에서 DB 와 연결하여 도메인 객체를 가져다 쓸 수 있도록 하기 위해 기존의 의존 방향을 뒤집어, Domain Layer 의 변경을 최소화하기 위해 만들어진 레이어.
RepositoryImpl
Domain 레이어의 Repository 를 구현해 DIP 를 만족하도록 구현하는 구현체. 실제 기능은 JpaRepository 에 위임
JpaRepository
Spring Data Jpa 로 만들어둔 DB에서 값을 가져다 쓸 수 있는 Repository 객체
Support Layer
효율적인 코드 작성을 위해 유일하게 모든 레이어가 의존할 수 있는 레이어. 공통으로 사용하는 예외나 유틸성 클래스를 담음.
CoreException(Custom Exception) & ErrorType