[프로젝트 회고] 유저와 이메일 도메인 Kotlin 마이그레이션

들어가며

프로그래머스 데브코스 팀 프로젝트에서 유저와 이메일 도메인을 Kotlin으로 마이그레이션하는 작업을 진행했다.

처음에는 “Java 코드를 Kotlin 문법으로 바꾸면 되는 것 아닐까?”라고 생각했다.
하지만 실제로 해보니 단순 변환보다 더 중요한 것은 Kotlin의 null 처리 방식, 테스트 스타일, 의존성 설정, 기존 Spring 코드와의 호환성을 이해하는 것이었다.

이번 글은 유저/이메일 도메인을 Kotlin으로 옮기며 배운 점을 정리한 기록이다.

왜 Kotlin으로 바꾸었나

프로젝트에서 Kotlin을 사용해보는 목적은 단순히 새로운 언어를 써보는 데 있지 않았다.

Kotlin은 Java와 잘 호환되면서도 null 안정성, 간결한 문법, data class, 확장 함수 같은 장점이 있다.
Spring Boot에서도 Kotlin을 사용할 수 있기 때문에 백엔드 코드의 표현력을 높일 수 있다고 생각했다.

특히 유저와 이메일 도메인은 인증 흐름과 연결되어 있어 테스트와 예외 처리가 중요했다.
이 영역을 Kotlin으로 옮기면서 코드의 안정성과 가독성을 함께 개선해보고 싶었다.

Java식 null 처리에서 Kotlin식 null 처리로

마이그레이션하며 가장 먼저 체감한 차이는 null 처리였다.

Java에서는 null 가능성이 있는 값을 개발자가 조심해서 다뤄야 한다.
반면 Kotlin은 타입 자체에 null 가능성이 드러난다.

1
2
val email: String
val nickname: String?

이렇게 타입에 nullable 여부가 드러나니, 어떤 값이 반드시 있어야 하고 어떤 값은 없을 수 있는지 더 명확해졌다.

물론 처음에는 컴파일 에러가 많이 났다.
하지만 그 에러들이 귀찮은 방해라기보다는, 런타임에 터질 수 있는 문제를 미리 알려주는 신호처럼 느껴졌다.

특히 유저 조회, 이메일 인증, 토큰 관련 값처럼 null이 생기면 위험한 영역에서는 Kotlin의 타입 시스템이 도움이 되었다.

테스트 구조 정리

마이그레이션과 함께 테스트도 정리했다.

Service는 단위 테스트 중심으로, Controller는 통합 테스트 중심으로 가져가려고 했다.

그 이유는 다음과 같았다.

  • Service는 비즈니스 로직과 예외 처리를 빠르게 검증해야 한다.
  • Controller는 요청/응답, Validation, Security Filter와의 연결을 확인해야 한다.

Kotlin 테스트를 작성하면서 Gradle 설정이나 Mock 관련 설정에서 막히는 부분도 있었다.
PR에 “Gradle을 봐주세요”라고 남길 정도로 처음에는 설정이 익숙하지 않았다.

하지만 이 과정에서 테스트 환경을 직접 맞추는 경험을 할 수 있었다.

인증 흐름과 연결된 마이그레이션

유저와 이메일 도메인은 JWT 인증과도 연결되어 있었다.

예를 들어 이메일 인증이 완료된 유저만 로그인할 수 있어야 하고, 로그인 성공 후 토큰 발급 흐름이 이어져야 한다.
따라서 단순히 도메인 파일만 Kotlin으로 바꾸는 것이 아니라, 인증 서비스와 필터, 테스트 코드까지 함께 확인해야 했다.

이 과정에서 다음 작업들이 이어졌다.

  • 유저 도메인 Kotlin 마이그레이션
  • 이메일 도메인 Kotlin 마이그레이션
  • JwtTokenizer 테스트
  • RefreshToken 재발급 흐름 확인
  • /api/refresh 필터 예외 처리
  • 불필요한 주석과 import 정리

마이그레이션은 언어 변경 작업이지만, 실제로는 주변 코드와의 연결을 모두 확인해야 하는 작업이었다.

인덱스와 Validator 리팩토링

이후에는 유저 관련 조회 성능과 Validator 구조도 정리했다.

각 Entity에서 where 조건에 자주 사용되는 컬럼에 index를 추가했고, MemberValidator에서 꼭 전체 객체를 가져올 필요가 없는 경우에는 존재 여부만 확인하도록 리팩토링했다.

처음에는 습관적으로 Entity를 조회해 검증했지만, 생각해보면 단순 존재 여부만 필요한 경우 전체 객체를 가져오는 것은 낭비일 수 있다.

이런 작은 개선들이 쌓이면 서비스 전체의 효율이 좋아진다.

배운 점

이번 작업에서 가장 크게 배운 것은 Kotlin은 문법만 바꾸는 작업이 아니라는 점이었다.

Kotlin을 제대로 쓰려면 null 안정성, 불변성, 테스트 방식, Spring과의 호환성을 함께 이해해야 했다.

또한 마이그레이션은 기존 동작을 깨뜨리지 않는 것이 가장 중요했다.
기능을 새로 만드는 것보다, 이미 돌아가는 기능을 유지하면서 구조를 바꾸는 일이 더 조심스러웠다.

그래서 테스트의 중요성도 더 크게 느꼈다.
테스트가 있으면 바꿀 수 있고, 테스트가 없으면 바꾸는 것이 무서워진다.

마무리

유저와 이메일 도메인 Kotlin 마이그레이션은 나에게 언어 전환 이상의 경험이었다.

Kotlin의 장점을 느끼기도 했고, Spring 프로젝트에서 언어를 섞어 사용할 때 고려할 점도 배웠다.
무엇보다 기존 기능을 유지하면서 구조를 개선하는 리팩토링의 어려움을 알게 되었다.

앞으로 Kotlin을 다시 사용하게 된다면, 단순히 짧은 문법에 집중하기보다 타입 안정성과 테스트 가능한 구조를 더 의식해서 작성해보고 싶다.

Leave a comment