Application Service 도메인 로직 누출 제거: Votes·Platform 도메인 객체로 추출#843
Application Service 도메인 로직 누출 제거: Votes·Platform 도메인 객체로 추출#843
Conversation
|
@codex review |
There was a problem hiding this comment.
Pull request overview
This PR moves domain rules that had leaked into RoomApplicationService down into domain objects (Votes, Platform) while keeping the existing ID-reference + bulk-operation approach.
Changes:
- Extract vote delta calculation into
Votes.diff()and vote aggregation intoVotes.calculateStatistic()returningVotes.Statistic. - Extract platform notification scheduling/outbox creation into
Platform.createNotificationOutboxes(...). - Update
RoomApplicationServiceto use the new domain APIs and add unit tests forVotes/Platform.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| core/src/main/java/com/estime/room/platform/Platform.java | Adds outbox creation logic based on enabled notification types. |
| core/src/main/java/com/estime/room/participant/vote/Votes.java | Introduces Votes.Diff and Votes.Statistic domain results and refactors service-facing logic into Votes. |
| application/src/main/java/com/estime/room/service/RoomApplicationService.java | Replaces in-service domain logic with calls to Platform/Votes domain APIs. |
| core/src/test/java/com/estime/room/platform/PlatformTest.java | Adds tests verifying outbox creation is filtered by notification settings. |
| core/src/test/java/com/estime/room/participant/vote/VotesDiffTest.java | Adds tests for vote diff behavior. |
| core/src/test/java/com/estime/room/participant/vote/VoteStatisticTest.java | Adds tests for vote statistics queries (allParticipantIds, slots, per-slot ids). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
core/src/test/java/com/estime/room/participant/vote/VoteStatisticTest.java
Show resolved
Hide resolved
|
Codex Review: Didn't find any major issues. Keep it up! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
배경: 왜 서비스 분리나 엔티티 연관 관계 개선이 아닌 도메인 객체 추출인가
Room → Participant → Vote, Room → Platform은 하나의 애그리거트 경계 안에 있는 올바른 계층 구조입니다. DDD 교과서대로라면 JPA 연관관계를 통해 애그리거트를 통째로 로드하고 루트(Room)가 하위 엔티티를 직접 조율하는 것이 자연스럽습니다.
하지만 현재 설계는 의도적으로 ID 참조 기반을 선택했고, 그 위에 다음 최적화가 구축되어 있습니다:
Vote의Persistable구현 → 신규 엔티티 INSERT 시 SELECT 제거deleteAllInBatch/saveAll→ 벌크 연산participantRepository.findIdsByRoomId()→ 필요한 ID만 조회JPA 연관관계로 전환하면 이 최적화를 포기하고, 지연 로딩 전략·N+1 문제를 새로 관리해야 합니다. 서비스를 분리하는 것도 같은 애그리거트 내 엔티티를 다루는 이상 책임 경계가 모호해집니다.
따라서 ID 참조와 Application Service의 조율 역할은 유지하되, 서비스에 누출된 도메인 지식만 도메인 객체로 내리는 접근을 선택했습니다.
동기: 서비스에 누출된 도메인 지식 3건
RoomApplicationService가 조율 역할을 넘어 "왜 이렇게 하는가"에 해당하는 도메인 지식까지 직접 수행하고 있었습니다.subtract두 번 호출 → "기존 대비 변경분 계산"이라는 개념이 숨겨짐Map<DateTimeSlot, Set<Long>>직접 조작 → 통계 집계·참여자 추출 로직이 서비스에 노출PlatformNotificationType.values()순회 + 필터링 → "플랫폼이 어떤 알림을 스케줄하는가"라는 규칙이 서비스에 존재Diff·Statistic을Votes의 inner record로 둔 이유둘 다
Votes의 연산 결과이며Votes없이 단독으로 생성되지 않습니다. 별도 파일로 분리하면 파일 수만 늘고 소속이 모호해지지만, inner record로 두면Votes.Diff,Votes.Statistic이라는 이름에서 소속과 의도가 동시에 드러납니다. 이는 프로젝트의 기존 패턴(DateTimeSlotStatisticOutput.DateTimeParticipantsOutput등)과도 일관됩니다.