Couchbase Kotlin SDK 버전 1.0의 GA 릴리스를 발표하게 되어 기쁘게 생각합니다. 사실 정말 기쁩니다. 이 프로젝트는 사랑의 노동이었습니다. 수십 년 동안 Java로 작업해 온 저에게 새로운 애정 어린 언어가 생겼습니다.

이 글에서는 Kotlin에 대한 몇 가지 좋은 점을 설명한 다음 Couchbase Kotlin SDK를 사용하여 Capella 서비스형 데이터베이스에 연결하는 방법을 보여드리겠습니다. 마지막으로 SDK의 공용 API를 형성한 몇 가지 디자인 결정을 공유하겠습니다. 특히 자체 Kotlin 라이브러리의 API를 설계하고 계신다면 마지막 부분까지 끝까지 지켜봐 주시기 바랍니다.

왜 Kotlin인가?

Kotlin은 JVM에서 비동기 프로그래밍에 대한 생각을 바꿨습니다. Kotlin의 코루틴과 일시 중단 함수는 반응형 프로그래밍이 확장성을 위해 가독성 코드를 희생할 필요가 없는 더 나은 무언가를 위한 디딤돌이 될 수 있다는 증거입니다. Kotlin은 고성능 비동기 코드를 작성하는 더 나은 방법이 있다는 것을 보여 주었으며, 우리는 Project Loom의 섬유와 연속성을 기다릴 필요가 없습니다.

카펠라 + Kotlin

카우치베이스 카펠라 는 Couchbase Server용 서비스형 데이터베이스(DBaaS)입니다. 견고한 기술이며, 몇 주 전에 무료 평가판에 가입했을 때 그 과정은 전혀 고통스럽지 않았습니다.

Capella 평가판 클러스터가 있고 허용 목록에 IP를 추가했으며 사전 설치된 데이터베이스 사용자를 생성했다고 가정해 보겠습니다. 여행 샘플 버킷에 연결합니다. Kotlin SDK를 사용하여 클러스터에 연결하는 방법은 다음과 같습니다: 

클러스터 개체가 있으면 N1QL 쿼리를 실행할 수 있습니다:

또는 컬렉션에 대한 참조를 얻고 특정 문서를 읽으세요:

이 예제의 전체 버전은 다음 문서에 포함되어 있습니다. Kotlin SDK 설명서와 함께 여러 가지 다른 기능을 제공합니다.

SDK API 설계 결정

이 글의 나머지 부분에서는 Couchbase Kotlin SDK의 공용 API를 설계하면서 내린 결정에 대한 몇 가지 메모를 공유하고자 합니다. 경우에 따라서는 Kotlin SDK를 이전 버전인 Java SDK와 비교하기도 할 것입니다.

확장 프로그램과 독립 SDK

Couchbase Kotlin SDK는 동일한 core-io 라이브러리를 Java SDK로 사용하지만 Java SDK에 의존하지 않습니다.

거부된 대안

Java SDK에서 클래스에 대한 확장 함수를 제공하는 방식으로 Kotlin을 지원하는 것을 고려했습니다. 안타깝게도 Java SDK에 대해 내린 일부 설계 결정이 Kotlin에 잘 적용되지 않아 확장 함수만으로는 보완할 수 없었습니다.

Java SDK에 단순히 위임하는 완전한 네이티브 Kotlin API 래퍼를 제공하는 것도 고려했지만, 모든 클래스의 버전이 두 가지(Kotlin용, Java용)가 있으면 사용자에게 혼란을 줄 수 있다는 점을 우려했습니다.

정지 또는 파산!

Kotlin SDK는 차단 API를 제공하지 않으며, 네트워크 I/O를 수행하는 메서드는 모두 일시 중단 함수.

거부된 대안

클러스터, 버킷, 범위, 컬렉션 등에 "차단" 변형을 추가하는 것을 고려했지만, 이는 사용자가 일시 중단 함수에 대한 호출을 다음과 같이 래핑하는 것만으로도 매우 적은 노력으로 직접 수행할 수 있는 것으로 보입니다. 실행 차단.

선택적 매개 변수

Java에는 선택적 매개변수가 없으므로 Couchbase Java SDK는 빌더 패턴을 사용하여 구성된 "옵션 블록"으로 매개변수를 에뮬레이트합니다. 

다음 예제에서는 위드엑스피리 는 기본값이 false인 선택적 부울 매개변수입니다. 코드 스니펫은 개발자가 참을 대신 전달하려는 호출 사이트를 보여줍니다.

Java:

Kotlin SDK는 기본 매개 변수에 대한 Kotlin의 기본 지원을 활용합니다:

Kotlin:

거부된 대안

Kotlin에서도 메서드별 옵션 블록을 사용하는 것을 고려했는데, 이는 다음과 같은 모습이었을 것입니다:

이는 사용자에게는 투박하고 SDK 개발자에게는 유지 관리가 어렵다는 이유로 거부되었습니다(모든 메소드에 공통된 새로운 옵션을 추가하는 것이 미치는 영향을 고려하세요).

옵션으로 람다/미니 SSL을 사용하는 것도 고려했는데, 이는 다음과 같은 모습이었을 것입니다:

바이너리 호환성(새로운 옵션 매개변수가 추가되어도 메서드 서명이 변경되지 않음)이 뛰어나기 때문에 거부된 대안 중 가장 매력적이었습니다. 또한 "Kotlin과 같은 느낌"이었습니다. 거부된 이유는 다음과 같습니다:

    • IDE 코드 완성 기능은 메서드 매개변수와 동일한 수준의 DSL에 대한 지침을 제공하지 않았습니다(시간이 지나면 개선될 가능성이 높지만).
    • 최종 람다 매개변수는 다른 용도로 남겨두고 싶었습니다.

공통 매개 변수

일부 선택적 매개변수는 Couchbase SDK API의 여러 메서드에 공통적으로 사용됩니다. 예를 들면 시간 초과 기간, 재시도 전략, 추적 범위 등이 있습니다.

Java에서 이러한 공통 옵션은 모든 메서드별 옵션 블록이 확장하는 CommonOptions 베이스 클래스의 속성으로, 사용자에게는 다른 매개변수와 다를 바 없이 보입니다:

Java:

Kotlin에서는 기본 매개 변수의 편리함과 유지 관리 및 바이너리 호환성을 위한 실용적인 양보의 균형을 맞추는 다른 접근 방식을 취합니다. 공통 매개 변수는 다음과 같은 옵션 블록으로 표시됩니다. 공통 옵션. 메서드는 기본값이 a인 선택적 매개 변수를 허용합니다. 공통 옵션 인스턴스가 기본 옵션을 나타냅니다. 기본값을 재정의하는 방법은 다음과 같습니다:

Kotlin:

거부된 대안

이와 같이 일반적인 옵션을 일반 매개변수로 취급하는 것을 고려했습니다:

사용자 입장에서는 분명 편리하겠지만, 공통 매개변수를 추가하거나 제거하려면 코드 베이스의 거의 모든 공용 메서드의 서명을 변경해야 하고, 바이너리 호환성을 유지하는 것이 상당히 번거로워지기 때문에 이 방법은 채택되지 못했습니다. 코드 생성을 통해 이 프로세스를 자동화하는 방법도 검토했지만, 그 복잡성이 그 가치보다 더 큰 것 같았습니다.

결국, 저희는 공통 옵션 클래스를 일반적인 옵션과 관련된 유지 관리 문제를 격리하기 위한 일종의 API 격벽으로 사용하세요.

바이너리 호환성

공통 및 선택적 매개변수에 대한 이러한 결정은 바이너리 호환성에 다음과 같은 영향을 미칩니다:

메서드에 선택적 매개변수를 추가하면 해당 메서드에 대해서만 바이너리 호환성이 깨집니다. 이전 서명이 있는 메서드를 추가하고 다음과 같이 주석을 달아 호환성을 복원할 수 있습니다. 사용 중단됨(수준=HIDDEN). 결론은 유지 관리 영향이 단일 메서드로 격리되고 호환성 유지를 위한 코드 변경도 마찬가지로 범위가 제한된다는 것입니다.

공통 매개 변수를 추가하면 이진 호환성이 깨집니다. 공통 옵션 클래스에 추가해야 합니다. 이전 서명이 있는 생성자를 추가하고 다음과 같이 주석을 달아 호환성을 복원할 수 있습니다. 사용 중단됨(수준=HIDDEN). 중요한 것은 메서드의 서명을 변경할 필요가 없다는 것입니다. 공통 옵션 를 매개변수로 지정할 수 있습니다.

상호 배타적 매개 변수

때로는 메서드에 매개변수 값을 지정하는 두 가지 방법이 있을 수 있습니다. 예를 들어, 몇몇 메서드는 만료 인수로 지정할 수 있으며 기간 또는 즉시. Java API에서는 이 코드를 작성하는 데 방해가 되는 것은 없습니다:

만료를 지정하는 이 두 가지 방법은 상호 배타적이지만 Java를 사용하면 코드를 작성할 수 있습니다. 유효성 검사가 필요한 경우 런타임에 수행해야 합니다. (이 특정 예제에서는 두 번째로 호출하는 만료 이전 호출에서 설정한 값을 덮어씁니다).

Kotlin에서 업서트 메서드에는 다음과 같은 단일 만료 매개 변수가 있습니다. 만료에서 만료 는 봉인된 클래스입니다:

또는

이 패턴은 API 전체에 적용되며, 상호 배타적인 옵션은 항상 값을 지정하는 다양한 방법을 나타내는 봉인된 클래스의 인스턴스를 취하는 단일 매개변수로 표현됩니다.

스트리밍 결과

Couchbase 쿼리, 분석, 보기 및 전체 텍스트 검색 서비스는 모두 매우 큰 결과 집합을 반환할 수 있습니다. 힙을 소진하지 않고 이러한 결과를 효율적으로 처리하기 위해 이러한 서비스의 쿼리 메서드는 결과를 Kotlin Flow로 반환합니다.

두 가지를 제공합니다. 실행 확장 메서드를 사용할 수 있습니다. 한 메서드는 전체 결과 집합을 반환하기 전에 결과 행을 메모리에 버퍼링합니다(결과 집합이 작다고 알려진 경우에만 사용). 다른 방법은 사용자가 서버에서 수신한 각 결과 행에 적용할 람다를 제공할 수 있습니다. 두 버전 모두 core-io 라이브러리가 제공하는 역압/흐름 제어를 활용합니다.

거부된 대안

저희는 프로젝트 리액터 플럭스/모노 오브젝트가 사용하는 core-io 라이브러리를 사용했지만 코루틴을 맛본 후에는 Reactor를 전혀 그리워하지 않게 되었고, 대부분의 사용자도 같은 생각을 할 것이라고 믿습니다.

DSL과 계층적 빌더 비교

Couchbase SDK에는 별도의 카테고리로 그룹화된 많은 구성 옵션이 있습니다. JVM SDK의 경우 이러한 옵션은 클러스터 환경. Java에서 이러한 옵션은 클러스터 환경 빌더를 사용하세요. 다음은 압축, DNS SRV 및 키/값 서비스 차단기를 비활성화하는 Java의 예제입니다:

Kotlin API는 Kotlin의 DSL 지원을 활용하여 다음과 동일한 구성을 표현할 수 있습니다:

또한 Kotlin API를 사용하면 연결 메서드를 사용하여 인라인으로 환경을 구성할 수 있습니다:

DSL보다 기존 클러스터 환경 빌더를 선호하는 사용자는 원하는 경우 계속 빌더를 사용할 수 있습니다.

거부된 대안

DSL 대신 데이터 클래스를 사용할 수도 있었을 것입니다:

그것도 괜찮았지만 DSL이 더 간결하고 Kotlin의 강점을 더 잘 살린 것 같습니다.

요약

저희는 Couchbase Kotlin SDK의 공용 API를 설계하는 데 많은 신중한 고민을 했습니다. 모든 것을 제대로 구현했다고 장담할 수는 없지만, 결과물이 Kotlin 관용구 및 모범 사례를 존중하는 것처럼 느껴지길 바랍니다.

Capella DBaaS를 사용하든 자체 Couchbase Server 클러스터를 관리하든 관계없이 마침내 프로덕션 환경에서 사용할 수 있는 Couchbase Kotlin SDK가 준비되었습니다. 다음과 같이 주석 처리되지 않은 모든 항목 휘발성 또는 커밋되지 않음 가 이제 공식적으로 안정적인 공개 API의 일부가 되었습니다. 거대한 감사합니다! 는 그 과정에서 피드백을 공유해 주신 커뮤니티의 모든 분들께 감사의 마음을 전합니다.

작성자

게시자 데이비드 노트

David Nault는 Couchbase에서 코드를 작성하며 SDK 및 커넥터 팀에서 일하고 있습니다.

댓글 남기기