Skip to content

Conversation

@chaiminwoo0223
Copy link
Contributor

@chaiminwoo0223 chaiminwoo0223 commented Dec 23, 2025

📌 작업 내용 및 특이사항

✅ Java → Kotlin 마이그레이션 개요

  • StudyLogDailyMission, DailyMission, Mission 전반을 Java → Kotlin으로 마이그레이션했습니다.
  • 단순 문법 변환이 아니라, Kotlin–Java 혼용 환경에서도 안정적으로 동작하도록 구조를 정리하는 데 초점을 맞췄습니다.
  • 마이그레이션 과정에서 기존 로직의 의미가 변경되지 않도록, 정적 팩토리 메서드(of, from)도메인 책임 구조(Factory, Policy, Service, Facade)를 최대한 유지했습니다.

✅ 테스트 코드 Kotlin 마이그레이션

  • Java로 작성된 StudyLogDailyMission, DailyMission, Mission 테스트 코드를 Kotlin으로 전환했습니다.
  • 단순히 코드를 옮기는 데 그치지 않고, Kotlin의 간결한 문법을 활용해 테스트 구조를 정리하고 누락된 케이스(완료 상태 검증)를 추가했습니다.
  • Kotlin–Java 혼용 환경에서 발생할 수 있는 접근자 차이(getter 인식 문제, record → data class 전환에 따른 호출 방식 변화 등)를 테스트 단계에서 먼저 확인했습니다.
  • StudyLogDailyMission, DailyMission, Mission 도메인 전반에 대해 단위 테스트와 통합 테스트를 Kotlin 기준으로 정비했습니다.
  • Fixture는 object 사용을 지양하고, class + DSL(withXXX) 패턴으로 통일하여 테스트 간 상태 공유 문제를 해결했습니다.
  • 마이그레이션의 기준은 컴파일 성공이 아니라 모든 테스트 통과이며, 테스트가 통과하는 상태를 확인한 후에야 마이그레이션을 완료했습니다.

@JvmStatic 적용으로 인한 Java ↔ Kotlin 정적 호출 문제 해결

  • Kotlin 마이그레이션 과정에서 Java ↔ Kotlin 간 JVM 상호운용 방식 차이로 인해 정적 메서드 호출 이슈가 발생했습니다.
  • Kotlin의 object에 정의된 메서드는 JVM 레벨에서 기본적으로 INSTANCE.create() 형태로 노출됩니다.
  • 하지만, 기존 Java 코드 및 테스트 / Fixture에서는 xxxFactory.create() 형태의 정적(static) 호출 방식을 사용하고 있었습니다.
  • 이로 인해 Kotlin object로 전환 후, 일부 코드에서 컴파일 오류가 발생했습니다.
  • 이를 해결하기 위해 @JvmStatic을 적용하여, create() 메서드가 JVM 레벨의 static 메서드로 노출되도록 변경하여 문제를 해결했습니다.
  • 본 설정은 Java–Kotlin 혼용 구간에서의 호환성을 위한 임시 조치이며, Kotlin 마이그레이션이 모두 완료되면 @JvmStatic을 제거할 예정입니다.

✅ StudyLogDailyMission 도메인 Kotlin 마이그레이션

  • StudyLogDailyMissionQueryService, StudyLogDailyMissionCommandService Kotlin 전환
  • StudyLogDailyMissionRepository, StudyLogDailyMissionJpaRepository, StudyLogDailyMissionRepositoryAdapter Kotlin 전환
  • StudyLogDailyMissionFactory Kotlin 전환

✅ DailyMission 도메인 Kotlin 마이그레이션

  • DailyMissionQueryService, DailyMissionCommandService Kotlin 전환
  • DailyMissionRepository, DailyMissionJpaRepository, DailyMissionRepositoryAdapter Kotlin 전환
  • DailyMissionErrorCode, DailyMissionPolicy Kotlin 전환
  • DailyMissionFactory Kotlin 전환

✅ Mission 도메인 Kotlin 마이그레이션

  • MissionController Kotlin 전환
  • MissionFacade, MissionQueryService, MissionCommandService Kotlin 전환
  • MissionRepository, MissionJpaRepository, MissionRepositoryAdapter Kotlin 전환
  • MissionErrorCode, MissionPolicy Kotlin 전환
  • MissionFactory Kotlin 전환

✅ DTO Kotlin 마이그레이션

  • StudyLogDailyMission Application DTO: StudyLogDailyMissionInfo Kotlin 전환
  • DailyMission Application DTO: DailyMissionInfo Kotlin 전환
  • Mission Presentation Reqeust DTO: CreateMissionRequest, UpdateMissionRequest Kotlin 전환
  • Mission Presentation Response DTO: CreateMissionResponse, LoadMissionInfoResponse Kotlin 전환
  • Mission Application DTO: MissionInfo, MissionsInfo Kotlin 전환

🌱 관련 이슈


🔍 참고사항(선택)

  • StudyLogControllerIntegrationTest IssuePresignedUrl, ConfirmImage에 학습 로그 ID 검증 케이스를 추가했습니다.
  • Kotlin 마이그레이션 완료 후, 기존 Java StudyLogDailyMission, DailyMission, Mission 관련 패키지는 제거했습니다. (메인, 테스트)

📚 기타(선택)

…그레이션(#122)

* feat: StudyLogDailyMissionQueryService.kt, StudyLogDailyMissionCommandService.kt 구현
* feat: StudyLogDailyMissionRepository.kt, StudyLogDailyMissionJpaRepository.kt, StudyLogDailyMissionRepositoryAdapter.kt 구현
* feat: StudyLogDailyMissionFactory.kt 구현

* feat: DailyMissionQueryService.kt, DailyMissionCommandService.kt 구현
* feat: DailyMissionRepository.kt, DailyMissionJpaRepository.kt, DailyMissionRepositoryAdapter.kt 구현
* feat: DailyMissionErrorCode.kt, DailyMissionPolicy.kt 구현
* feat: DailyMissionFactory 구현

* feat: MissionController.kt 구현
* feat: MissionFacade.kt 구현
* feat: MissionQueryService.kt, MissionCommandService.kt 구현
* feat: MissionRepository.kt, MissionJpaRepository.kt, MissionRepositoryAdapter.kt 구현
* feat: MissionErrorCode.kt, MissionPolicy.kt 구현
* feat: MissionFactory.kt 구현

* feat: StudyLogDailyMissionInfo.kt DTO 추가
* feat: DailyMissionInfo DTO 추가
* feat: CreateMissionRequest.kt, UpdateMissionRequest.kt DTO 추가
* feat: CreateMissionResponse.kt, LoadMissionInfoResponse.kt DTO 추가
* feat: MissionInfo.kt, MissionsInfo.kt DTO 추가

* refactor: record → data class 전환에 따른 DTO 접근자 호출 방식(x() → getX()) 수정

* refactor: java studylog application 패키지 제거 (Kotlin 마이그레이션 완료)
* refactor: java studylog infra jpa 패키지 제거 (Kotlin 마이그레이션 완료)
* refactor: java studylog domain factory 패키지 제거 (Kotlin 마이그레이션 완료)
* refactor: java mission presentation, application 패키지 제거 (Kotlin 마이그레이션 완료)
* refactor: java mission infra jpa 패키지 제거 (Kotlin 마이그레이션 완료)
* refactor: java mission domain error, policy 패키지 제거 (Kotlin 마이그레이션 완료)

* test: StudyLogDailyMissionFixture.kt 추가
* test: StudyLogDailyMissionTestHelper.kt 추가
* test: StudyLogDailyMissionQueryServiceTest.kt, StudyLogDailyMissionCommandServiceTest.kt 단위 테스트 추가

* test: DailyMissionFixture.kt 추가
* test: DailyMissionTestHelper.kt 추가
* test: DailyMissionQueryServiceTest.kt, DailyMissionCommandServiceTest.kt 단위 테스트 추가

* test: MissionFixture.kt, CreateMissionRequestFixture.kt, UpdateMissionRequestFixture.kt 추가
* test: MissionTestHelper 추가
* test: MissionQueryServiceTest.kt, MissionCommandServiceTest.kt 단위 테스트 추가
* test: MissionControllerIntegrationTest 통합 테스트 추가

* test: test java studylog 패키지 제거 (Kotlin 마이그레이션 완료)
* test: test java mission 패키지 제거 (Kotlin 마이그레이션 완료)

* test: StudyLogControllerIntegrationTest.kt IssuePresignedUrl 통합 테스트 개선
* test: StudyLogControllerIntegrationTest.kt ConfirmImage 통합 테스트 개선
@chaiminwoo0223 chaiminwoo0223 self-assigned this Dec 23, 2025
@chaiminwoo0223 chaiminwoo0223 added the 🪄refactor 기능 개선 및 리팩토링 label Dec 23, 2025
Copy link
Contributor

@hisonghy hisonghy left a comment

Choose a reason for hiding this comment

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

Fixture 클래스에서 object를 지양하는 이유가 궁금합니다!

@chaiminwoo0223
Copy link
Contributor Author

chaiminwoo0223 commented Dec 27, 2025

Fixture 클래스에서 object를 지양하는 이유가 궁금합니다!

Mission을 기준으로 설명드리겠습니다.

처음에는 MissionFixture, CreateMissionRequestFixture, UpdateMissionRequestFixture를 모두 Kotlin의 object로 구현하여 사용했습니다. 하지만, object는 JVM 상에서 하나의 싱글톤 인스턴스로 생성되기 때문에, 내부에 상태(var)를 가지는 경우 해당 값이 테스트 간에 공유되는 문제가 발생했습니다.

이를 처음 인지하게 된 것은 UpdateMissionRequestFixture를 사용하던 중이었습니다. 한 테스트에서 withName()을 통해 변경한 값이 다음 테스트에도 그대로 남아 있어, 테스트 실행 순서에 따라 결과가 달라지는 현상이 발생했습니다. 이는 테스트의 독립성을 해치는 원인이 되었고, 원인을 추적하기도 쉽지 않았습니다.

이 문제를 해결하기 위해 기존 Java 테스트 코드의 형태와 가장 유사한 class로 Fixture를 전환했습니다. 이를 통해 각 테스트마다 새로운 Fixture 인스턴스를 생성하도록 하여, 상태가 테스트 단위로 한정되도록 만들었습니다. 또한, 테스트 코드 전반에서의 명확성과 일관성을 위해, 모든 Fixture를 class 기반으로 통일하여 구현했습니다.

@hisonghy
Copy link
Contributor

Fixture 클래스에서 object를 지양하는 이유가 궁금합니다!

Mission을 기준으로 설명드리겠습니다.

처음에는 MissionFixture, CreateMissionRequestFixture, UpdateMissionRequestFixture를 모두 Kotlin의 object로 구현하여 사용했습니다. 하지만, object는 JVM 상에서 하나의 싱글톤 인스턴스로 생성되기 때문에, 내부에 상태(var)를 가지는 경우 해당 값이 테스트 간에 공유되는 문제가 발생했습니다.

이를 처음 인지하게 된 것은 UpdateMissionRequestFixture를 사용하던 중이었습니다. 한 테스트에서 withName()을 통해 변경한 값이 다음 테스트에도 그대로 남아 있어, 테스트 실행 순서에 따라 결과가 달라지는 현상이 발생했습니다. 이는 테스트의 독립성을 해치는 원인이 되었고, 원인을 추적하기도 쉽지 않았습니다.

이 문제를 해결하기 위해 기존 Java 테스트 코드의 형태와 가장 유사한 class로 Fixture를 전환했습니다. 이를 통해 각 테스트마다 새로운 Fixture 인스턴스를 생성하도록 하여, 상태가 테스트 단위로 한정되도록 만들었습니다. 또한, 테스트 코드 전반에서의 명확성과 일관성을 위해, 모든 Fixture를 class 기반으로 통일하여 구현했습니다.

설명 감사합니다~
새롭게 알게 된 사실이네요!

Copy link
Contributor

@hisonghy hisonghy left a comment

Choose a reason for hiding this comment

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

고생하셨습니다~
병합부탁드려요~

@chaiminwoo0223 chaiminwoo0223 merged commit 240449c into develop Dec 27, 2025
4 checks passed
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]: StudyLogDailyMission, DailyMission, Mission 기능 전반 Kotlin 마이그레이션

3 participants