Skip to content

refactor: 조립되는 커맨드를 빌더로 — 같은 타입이 인접한 곳부터 - #331

Open
sevineleven wants to merge 2 commits into
devfrom
refactor/300-commands-to-builder
Open

refactor: 조립되는 커맨드를 빌더로 — 같은 타입이 인접한 곳부터#331
sevineleven wants to merge 2 commits into
devfrom
refactor/300-commands-to-builder

Conversation

@sevineleven

@sevineleven sevineleven commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Situation

규약은 커맨드를 빌더로 만들라고 한다.

여러 필드를 조립하는 엔티티·커맨드·응답 객체는 Lombok @Builder 로 만든다(생성자 인자 순서 실수 방지·가독성).

그런데 toCommand() 가 조립하는 커맨드 6개가 전부 위치 기반 생성자였다.

Task

같은 타입이 인접한 곳부터 닫는다. 타입이 갈리면 컴파일러가 잡지만, 같은 타입이 나란히 있으면 뒤바뀌어도 통과하고 런타임에 조용히 틀린다.

Action

이슈가 적은 6개 중 3개는 이미 돼 있었다

이슈가 2026-08-18 에 작성된 뒤 그 사이에 처리됐다.

커맨드 상태
SocialLoginCommand 이미 됨 — #320 (CodeRabbit 지적)
AddLeaveUsage · UpdateLeaveUsage 이미 됨 — #319 · #323
GenerateCourse · RecommendRegions · DeviceRegistration 이번 PR

이슈 본문의 SocialLoginCommand 필드 목록도 낡았다 — guestId 를 적고 있는데 #280 이후 그건 사라지고 authorizationCode 가 들어왔다.

남은 셋은 전부 실제 위험이 있었다

커맨드 인접한 같은 타입 뒤바뀌면
GenerateCourse double originLat, originLng 출발지가 엉뚱한 곳 → 동선 전체가 어긋난다
RecommendRegions double originLat, originLng
DeviceRegistration String guestId, token 알림은 생기는데 푸시만 조용히 안 간다

DeviceRegistration 이 특히 그렇다. 그 실패는 예외도 로그도 남기지 않는다 — #280 이 닫은 그 모양 그대로다.

이슈 밖에서 하나 더 — GenerateCourse.first() 를 없앴다

인자 8개짜리 정적 팩토리라 커맨드와 똑같은 위험을 그대로 안고 있었다. 빌더만 붙이고 그것을 남기면 위험한 경로가 그대로 남는다.

호출부가 빌더를 직접 쓰고, 씨앗·제외 목록을 안 적으면 그대로 첫 생성이다 — seed 기본값 0 이 곧 FIRST_SEED 다. 그 사실을 record javadoc 에 적었다.

withSeedtoBuilder 로 바꿨다. 열 개를 손으로 다시 나열하던 자리라, 필드가 늘 때 여기 빠뜨리면 재생성만 조용히 옛 값을 쓴다.

public GenerateCourse withSeed(long newSeed) {
    return toBuilder().seed(newSeed).build();
}

하지 않은 것

  • service/dto 전체(35개)를 훑지 않았다. 조립되는 커맨드만 본다
  • 결과(result) DTO 는 대상이 아니다. MyLeave 처럼 도메인에서 from() 으로 나오는 것은 호출부가 조립하지 않아 인자 순서를 틀릴 자리가 없다
  • 계산으로 파생되는 값객체도 아니다 — 규약의 "조립이면 빌더, 계산이면 팩토리" 경계 그대로

Result

new GenerateCourse( · GenerateCourse.first( · new RecommendRegions( · new DeviceRegistration( 을 전수 검색해 위치 인수 생성이 0건임을 확인했다.

동작은 그대로다. 테스트를 더하지 않은 이유가 그것이다 — 빌더는 같은 생성자를 부르고, record 의 compact constructor(제외 목록 정규화·startDayLeave 기본값)도 그대로 탄다. 기존 1,834건이 그 경로를 이미 덮는다.

작업을 마치기 전 자문 셋

질문
운영에서 버티는가 적재·인덱스와 무관하다
외부 API 한도 해당 없음
코스의 완성도 코스와 무관한 내부 개선이다. 다만 GenerateCourse 는 코스 생성의 입구라, 위경도가 뒤바뀌면 그 코스는 통째로 틀린다

연관 이슈

Summary by CodeRabbit

  • 리팩터링

    • 기기 등록, 코스 생성·재생성, 지역 추천 요청의 데이터 생성 방식을 명시적인 빌더 방식으로 통일했습니다.
    • 필드 매핑이 명확해져 식별자, 토큰, 위치 정보 등의 값이 잘못 조합될 가능성을 줄였습니다.
    • 코스 생성의 기본 씨앗과 제외 목록 처리 방식을 유지하면서 객체 구성을 개선했습니다.
    • 기존 기능과 요청 값의 동작은 변경되지 않았습니다.
  • 테스트

    • 코스 생성 통합 테스트를 변경된 객체 생성 방식에 맞게 업데이트했습니다.

- RecommendRegions 는 originLat·originLng 이 둘 다 double 로 나란히 있다. 위치
  인수로 넘기면 뒤바뀌어도 컴파일이 통과하고, 출발지가 엉뚱한 곳에 찍혀 추천이
  통째로 어긋난다
- DeviceRegistration 은 guestId·token 이 둘 다 String 이다. 뒤바뀌면 발송이 기기를
  못 찾아 알림은 만들어지는데 푸시만 조용히 안 간다 — 예외도 로그도 없다.
  #280 이 닫은 그 실패 모양 그대로다
- 규약이 "여러 필드를 조립하는 커맨드는 @builder" 라고 적고 있는데 service/dto 에
  실제로 쓰는 곳이 거의 없었다. 왜 빌더여야 하는지를 각 record javadoc 에 근거로
  남겨, 다음 사람이 규칙인지 예외인지 헷갈리지 않게 한다
- GenerateCourse 는 인자가 열이고 그중 originLat·originLng 이 같은 타입으로
  나란히 있다. 뒤바뀌면 출발지가 엉뚱한 곳에 찍혀 동선이 통째로 어긋난다
- first() 를 남기지 않았다. 인자 8개짜리 정적 팩토리라 커맨드와 똑같은 위험을
  그대로 안고 있어, 빌더만 붙이고 그것을 두면 위험한 경로가 그대로 남는다.
  호출부가 빌더를 직접 쓰고, 씨앗·제외 목록을 안 적으면 그대로 첫 생성이다
  (seed 기본값 0 이 곧 FIRST_SEED) — 그 사실을 record javadoc 에 적었다
- withSeed 는 toBuilder 로 베낀다. 열 개를 손으로 다시 나열하던 자리라, 필드가
  늘 때 여기 빠뜨리면 재생성만 조용히 옛 값을 쓴다
- new GenerateCourse( · GenerateCourse.first( · new RecommendRegions( ·
  new DeviceRegistration( 을 전수 검색해 위치 인수 생성이 0건임을 확인했다
@sevineleven sevineleven added the refactor 구조 개선 (외부 동작 불변) label Aug 25, 2026
@sevineleven sevineleven self-assigned this Aug 25, 2026
@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 87f18f8c-eff4-4149-8ece-64a2ebd80905

📥 Commits

Reviewing files that changed from the base of the PR and between c60b2ca and 917fceb.

📒 Files selected for processing (8)
  • src/main/java/com/offway/core/device/controller/dto/DeviceRegisterRequest.java
  • src/main/java/com/offway/core/device/service/dto/DeviceRegistration.java
  • src/main/java/com/offway/core/itinerary/controller/dto/CourseGenerateRequest.java
  • src/main/java/com/offway/core/itinerary/controller/dto/CourseRegenerateRequest.java
  • src/main/java/com/offway/core/itinerary/service/dto/GenerateCourse.java
  • src/main/java/com/offway/core/trip/controller/dto/RegionRecommendRequest.java
  • src/main/java/com/offway/core/trip/service/dto/RecommendRegions.java
  • src/test/java/com/offway/core/itinerary/service/CourseGenerationIntegrationTest.java

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

서비스 커맨드 DTO에 Lombok 빌더를 추가했습니다. 요청 DTO와 통합 테스트의 객체 생성 코드를 빌더 방식으로 전환하고, GenerateCourse.first(...)를 제거했습니다.

Changes

서비스 커맨드 빌더 전환

Layer / File(s) Summary
커맨드 빌더 계약 정의
src/main/java/com/offway/core/device/service/dto/DeviceRegistration.java, src/main/java/com/offway/core/itinerary/service/dto/GenerateCourse.java, src/main/java/com/offway/core/trip/service/dto/RecommendRegions.java
세 서비스 DTO에 @Builder를 추가했습니다. GenerateCourse@Builder(toBuilder = true)를 사용하며, first(...)를 제거하고 withSeed(long)toBuilder() 기반으로 변경했습니다.
요청 DTO 생성 경로 전환
src/main/java/com/offway/core/device/controller/dto/DeviceRegisterRequest.java, src/main/java/com/offway/core/itinerary/controller/dto/CourseGenerateRequest.java, src/main/java/com/offway/core/itinerary/controller/dto/CourseRegenerateRequest.java, src/main/java/com/offway/core/trip/controller/dto/RegionRecommendRequest.java, src/test/java/com/offway/core/itinerary/service/CourseGenerationIntegrationTest.java
요청 변환 코드와 통합 테스트가 위치 기반 생성자 대신 필드명을 지정하는 빌더를 사용하도록 변경했습니다. GenerateCourse의 기본 시드와 제외 목록 설정도 빌더 생성 흐름에 반영했습니다.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 917fc

This PR replaces positional command construction with builders and removes an equivalent factory path; no actionable merge-blocking risk remains beyond normal checks and review.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 커맨드 조립을 Lombok 빌더로 변경하는 핵심 내용을 명확하고 간결하게 설명합니다.
Linked Issues check ✅ Passed GenerateCourse, RecommendRegions, DeviceRegistration에 @Builder를 적용하고 호출부를 builder() 방식으로 변경했습니다. GenerateCourse.first() 제거와 withSeed()의 toBuilder() 전환도 이슈 #300의 요구사항에 해당합니다. 나머지 대상 커맨드는 별도 변경으로 처리되었다는…
Out of Scope Changes check ✅ Passed 변경된 요청 DTO, 서비스 DTO, 관련 통합 테스트, Javadoc은 모두 커맨드 빌더 전환과 인자 순서 오류 방지 목적에 직접 관련됩니다. 확인되는 범위에서 무관한 변경은 없습니다.
Full details: Linked Issues check

Explanation

GenerateCourse, RecommendRegions, DeviceRegistration에 @Builder를 적용하고 호출부를 builder() 방식으로 변경했습니다. GenerateCourse.first() 제거와 withSeed()의 toBuilder() 전환도 이슈 #300의 요구사항에 해당합니다. 나머지 대상 커맨드는 별도 변경으로 처리되었다는 명시가 있어 전체 목표와 일치합니다.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/300-commands-to-builder

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor 구조 개선 (외부 동작 불변)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[refactor] service/dto 커맨드를 빌더로 만든다

1 participant