pile·
백엔드·딜리셔스딜리셔스·

우당탕탕 Kotlin 전환기

딜리셔스가 Java 로 만든 프로젝트를 Kotlin 으로 전환한 기록이다. 차기 프로젝트에 Kotlin 을 쓰기로 정한 뒤 실무 경험을 쌓으려고 기존 프로젝트를 옮겼고, 전환 중 마주친 Java 와 Kotlin 혼용 구간의 문제들을 항목별로 정리했다.

핵심 포인트
  • 목표는 둘이었다. 실제 프로젝트 코드에 써서 Kotlin 에 익숙해지는 것과 팀 차원의 전환 경험을 쌓는 것이다.
  • 사전 준비로 Kotlin 과 Spring Boot 공식 문서, 다른 회사 전환 사례를 조사했다. Java util 패키지 대신 Kotlin 내장 라이브러리로 바꾸는 편이 좋다는 것도 그중 하나다.
  • IntelliJ 의 Show Kotlin Bytecode 와 Decompile 로 지금 Kotlin 코드가 Java 로 어떻게 되는지 확인하며 진행하면 에러를 잡기 쉽다.
  • 컴파일러 플러그인 둘이 필수다. no-arg 는 JPA Entity 초기화에 필요한 매개변수 없는 생성자를 만들어주고, all-open 은 기본이 final 인 클래스에 open 을 붙여 CGLIB 프록시 생성을 가능하게 한다.
  • 원래 전략은 Domain 과 Use case 를 먼저 옮기고 UI 와 Infra 를 나중에 옮기는 것이었지만 적용이 어려웠다.
상세 정리
  • 순수 Domain 이 바뀌면 그에 의존하는 Infra 변경이 따라와야 해서, 특정 Domain 영역과 그것을 의존하는 Service, Infra 를 동시에 고치는 방식으로 수정했다.
  • 병합 충돌을 줄이려고 각자 익숙한 패키지를 배타적으로 나눠 맡고 진행 상태를 볼 수 있는 장표를 만들었다.
  • Kotlin Migration 공유 문서를 만들어 전환 중 겪은 이슈와 알게 된 것을 정리했다. 같은 문제를 다른 팀원이 또 조사하는 시간을 줄이기 위해서다.
  • 이슈 1은 nullable 과 Optional 의 충돌이다. Java 에서 Optional 이던 타입을 Kotlin nullable 로 바꾸면 아직 전환되지 않은 Java 쪽에서 문제가 생긴다.
  • 이슈 2는 static 메서드다. IntelliJ 의 자동 변환은 companion object 로 바꿔놓는데, Java 에서 기존처럼 호출하려면 어노테이션이 필요하고 아니면 Companion 을 거쳐야 한다. 이미 전환된 Kotlin 을 고치기보다 전환 예정인 Java 를 바꾸는 쪽이 유리하다고 판단했다.
  • 이슈 3은 테스트다. Kotlin 클래스는 기본이 final 이라 Java 용 모킹 라이브러리로는 모킹이 안 된다. 이를 가능하게 해주는 도구가 필요하다.
  • 이슈 4는 Jackson 이다. Primary Constructor 안에서 프로퍼티를 선언하는 방식이 기본 생성자가 없다는 오류를 부르며, 별도 모듈로 해결한다.
  • 이슈 5는 인터페이스다. Java 인터페이스의 default 메서드와 Kotlin 인터페이스 구현 메서드는 바이트코드가 다르다. Kotlin 은 내부적으로 DefaultImpls 클래스를 만들어 구현한다.
  • 호환용 컴파일 옵션을 켜는 것은 지양했기에, CrudRepository 를 상속한 인터페이스를 스프링 컴포넌트로 선언하고 클래스에 주입하는 우회로 해결했다.
  • 가장 신경 쓴 부분은 Java 코드에 명시돼 있지 않은 null 가능성을 전부 확인하는 일이었다. API 요청과 외부 API 응답의 null 여부를 알아야 프로퍼티를 nullable 로 둘지 정할 수 있다.
  • 그래서 전환한다면 요청부터 Controller, Service, Domain, Infra, 외부 API 응답까지 수직으로 훑는 방식을 권한다.
  • Java 라이브러리에 붙은 nullability 어노테이션이 전환에 큰 도움이 되니 꼭 확인하라고 덧붙인다.
  • 얻은 것으로는 getter 가 사라져 프로퍼티에 점으로 접근해 실제 속성처럼 느껴진다는 점, 그리고 생성자 기본값과 이름 붙인 인자 덕에 여러 개의 생성자를 크게 줄일 수 있었다는 점을 꼽는다.
왜 읽나Java 프로젝트를 Kotlin 으로 옮기려는 백엔드 팀에게, 혼용 구간에서 반드시 만나는 다섯 가지 충돌과 전환 순서에 대한 권고를 정리해주는 기록.
딜리셔스
딜리셔스 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 백엔드·twilio-engTwilio Engineering·

    Programmable Messaging에서 Verify API로 마이그레이션하기

    Twilio의 Programmable Messaging API로 자체 OTP 솔루션을 운영하던 서비스가 Verify API로 전환하는 방법을 코드 예시와 함께 설명한다. Verify는 OTP 전송·검증을 위한 전용 API로, 전화번호 구매, 토큰 생성, DB 저장·만료 관리를 내부에서 처리해 개발자가 직접 구현할 코드를 크게 줄인다.

    요약 이어보기
    #authentication#twilio#sms+2
  2. 백엔드·포스타입포스타입·

    포스타입이 개인화 추천을 하는 방법 2부

    포스타입 백엔드 엔지니어가 벡터 기반 개인화 추천 시스템을 실제 운영하며 맞닥뜨린 성능 장애와 용량 문제를 해결한 과정을 담은 2부다. 수백만 개의 벡터 KNN 검색이 피크 시간대에 전체 Elasticsearch 검색 성능을 흔드는 문제부터 클러스터 OOM 사태까지, 쿼리 최적화와 인프라 분리 두 가지 경로로 근본 해결에 이른다.

    요약 이어보기
    #elasticsearch#vector-search#recommendation-system+2
  3. 백엔드·포스타입포스타입·

    포스타입이 개인화 추천을 하는 방법 1부

    포스타입이 태그 기반 추천의 한계를 극복하고 벡터 임베딩 기반 개인화 추천 시스템을 구축한 과정을 담은 1부다. 유사한 콘텐츠가 다른 용어를 쓰거나 동일한 태그가 전혀 다른 톤의 콘텐츠를 가리키는 문제를 임베딩 벡터로 해결하고, OpenSearch의 HNSW ANN 검색으로 수백만 벡터를 실시간 검색하는 시스템을 구축해 구매율 15% 향상을 달성했다.

    요약 이어보기
    #opensearch#vector-search#recommendation-system+2