Upgrade to Pro — share decks privately, control downloads, hide ads and more …

APIs: How Hard Can They Be?

APIs: How Hard Can They Be?

Talk by Aurimas Liutikas and Alan Viverette at KotlinConf 2025

Avatar for Aurimas Liutikas

Aurimas Liutikas

May 22, 2025
Tweet

More Decks by Aurimas Liutikas

Other Decks in Technology

Transcript

  1. APIs: How Hard Can They Be? Alan Viverette Aurimas Liutikas

    reddit.com/u/alanviverette androiddev.social/@aurimas
  2. Who are we? Alan 14 years at Google 12 years

    on Android 10 years on Android API Council Aurimas 13 years at Google 10 years on Android 8 years on Android API Council
  3. For all developers Public APIs • Public documentation • Strong

    compatibility guarantees • High quality bar
  4. For early adopters Experimental APIs • Public documentation • No

    compatibility guarantees • Intended to become stable public APIs
  5. For internal use only Restricted APIs • No public documentation

    • Minimal compatibility guarantees • Similar to private or internal
  6. • Does this still work as documented? • Does a

    comprehensive set of tests still pass? Contract compatibility
  7. Contract compatibility /** * Returns the sum of [a] and

    [b]. */ fun add(a: Int, b: Int) = a + b
  8. Contract compatibility /** * Returns the sum of [a] and

    [b]. */ fun add(a: Int, b: Int) = 0 🙁
  9. Binary compatibility /** * Returns the sum of [a] and

    [b]. */ fun add(a: Int, b: Int) = a + b
  10. Binary compatibility /** * Returns the sum of [a] and

    [b]. */ fun add(a: Int, b: Int) = a + b
  11. Binary compatibility // My library code val sum = add(first,

    second) com.myorg.mylibrary:1.1.0 release-v1.1.0.jar com.alanv.fancymath:2.0.0 depends on 🙄
  12. Renaming a File (before) $ javap Example1Kt.class public final class

    org.example.Example1Kt { public static final void myMethod(); }
  13. Renaming a File (after) $ javap Example1NewKt.class public final class

    org.example.Example1NewKt { public static final void myMethod(); }
  14. Renaming a File $ javap Example1NewKt.class public final class org.example.Example1NewKt

    { public static final void myMethod(); } source compatibility binary compatibility contract compatibility Kotlin users ✅ 💥 💥 Java users 💥 💥 💥
  15. Adding a Constructor $ javap Example2.class public final class org.example.Example2

    { public org.example.Example2(java.lang.String); } source compatibility binary compatibility contract compatibility Kotlin users 💥 💥 💥 Java users 💥 💥 💥
  16. Adding a New Default Method source compatibility binary compatibility contract

    compatibility Kotlin users ❓ ✅ ❓ Java users ❓ ✅ ❓
  17. Changing parameter type $ javap -c User.class public final class

    org.example.user.User { public final void makeCall(); Code: ... 7: ldc #16 // String Aurimas 9: invokevirtual #20 // Method org/example/Example4.myMethod:(Ljava/lang/String;)V }
  18. Changing parameter type $ javap -c User.class public final class

    org.example.user.User { public final void makeCall(); Code: ... 7: ldc #16 // String Aurimas 9: invokevirtual #20 // Method org/example/Example4.myMethod:(Ljava/lang/String;)V } source compatibility binary compatibility contract compatibility Kotlin users ✅ 💥 ✅ Java users ✅ 💥 ✅
  19. What Went Wrong? APIs marked with @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) APIs used cross

    library groups (androidx.room using androidx.sqlite) User upgraded androidx.sqlite without upgrading androidx.room
  20. Kotlin-stdlib extension function package kotlin.collections public fun <T> MutableList<T>.removeLast(): T

    = if (isEmpty()) throw NoSuchElementException("List is empty.") else removeAt(lastIndex)
  21. $ javap -c RemoveLastUser.class --release 17 7: invokestatic #28 //

    Method kotlin/collections/CollectionsKt.removeLast:(Ljava/util/List ;)Ljava/lang/Object; --release 21 7: invokeinterface #28, 1 // InterfaceMethod java/util/List.removeLast:()Ljava/lang/Object;
  22. Android SDK API 34  API 34 device ✅ It

    works using java.util.List.removeLast()
  23. Android SDK API 34  API 33 device 💥 Crash

    as java.util.List.removeLast() doesnʼt exist
  24. Metalava • API management command-line tool • Apache 2.0 •

    Origins in Android OS project • Owned by Google
  25. Metalava BCV Input source binary Supports JVM / Android ✅

    ✅ Supports Kotlin Native ❌ ✅ Identity Comparison ✅ ✅ Compatibility Checks ✅ ❌ API linting ✅ ❌
  26. Example Metalava Usage java -cp all/metalava.jar com.android.tools.metalava.Driver --format=v4 --source-path /path/to/resources:/path/to/kotlin

    --classpath /path/to/android.jar:/path/to/kotlin-stdlib-2.1.0.jar --api lib/build/current.txt
  27. Example Metalava Usage java -cp all/metalava.jar com.android.tools.metalava.Driver --format=v4 --source-path /path/to/resources:/path/to/kotlin

    --classpath /path/to/android.jar:/path/to/kotlin-stdlib-2.1.0.jar --api lib/build/current.txt
  28. package org.example class Example4 { fun myMethod(text: String) { }

    } // Signature format: 4.0 package org.example { public final class Example1 { ctor public Example1(); method public void myMethod(String text); } }
  29. package org.example class Example4 { fun myMethod(text: String) { }

    } // Signature format: 4.0 package org.example { public final class Example1 { ctor public Example1(); method public void myMethod(String text); } }
  30. Example Metalava Usage java -cp all/metalava.jar com.android.tools.metalava.Driver --format=v4 --source-path /path/to/resources:/path/to/kotlin

    --classpath /path/to/android.jar:/path/to/kotlin-stdlib-2.1.0.jar --check-compatibility:api:released lib/1.1.0.txt
  31. Metalava BCV Input source binary Supports JVM / Android ✅

    ✅ Supports Kotlin Native ❌ ✅ Identity Comparison ✅ ✅ Compatibility Checks ✅ ❌ API linting ✅ ❌
  32. ./gradlew apiDump public final class org/example/Example4 { public fun <init>

    ()V public final fun myMethod (Ljava/lang/String;)V }
  33. ./gradlew apiCheck public final class org/example/Example4 { public fun <init>

    ()V - public final fun myMethod (Ljava/lang/String;)V + public final fun myMethod (Ljava/lang/CharSequence;)V }
  34. BCV • Support for compatibility comparing for Kotlin native (klib)

    targets • Different rules than JVM • Rules are still evolving • Not published (plan to upstream)
  35. Local development • Write and review design doc • Implement

    changes • Validate APIs • Upload commit with Relnote: stanza Local development • Write and review design doc • Implement changes • Validate APIs • Upload commit with Relnote: stanza Code review • Validate APIs as a presubmit check • Review for API2 approval bit • Resolve feedback • Merge commit
  36. Code review • Validate APIs as a presubmit check •

    Review for API2 approval bit • Resolve feedback • Merge commit Local development • Write and review design doc • Implement changes • Validate APIs • Upload commit with Relnote: stanza Local development • Write and review design doc • Implement changes • Validate APIs • Upload commit with Relnote: stanza Code review • Validate APIs as a presubmit check • Review for API2 approval bit • Resolve feedback • Merge commit Post-merge • CI files review bug • Spot-check APIs in group review • Respond to feedback • Schedule release
  37. Post-merge • CI files review bug • Spot-check APIs in

    group review • Respond to feedback • Schedule release Local development • Write and review design doc • Implement changes • Validate APIs • Upload commit with Relnote: stanza Code review • Validate APIs as a presubmit check • Review for API2 approval bit • Resolve feedback • Merge commit Release • Validate all APIs have approved • Review release notes • Publish API docs and release notes
  38. Release • Validate all APIs have approved • Review release

    notes • Publish API docs and release notes Local development • Write and review design doc • Implement changes • Validate APIs • Upload commit with Relnote: stanza Code review • Validate APIs as a presubmit check • Review for API2 approval bit • Resolve feedback • Merge commit Post-merge • CI files review bug • Spot-check APIs in group review • Respond to feedback • Schedule release
  39. Manual review scales linearly. Please rename this to setOnClickListener No,

    this should addClickCallback What about setOnClickCallback? Hey, I’m ready for review! R
  40. Developers donʼt like to commit. com.myorg + mylibrary + 1.0.0-alpha01

    + 1.0.0-alpha02 + 1.0.0-alpha03 + 1.0.0-alpha04 + 1.0.0-alpha05 + 1.0.0-alpha06 + 1.0.0-alpha07 + 1.0.0-alpha08 + 1.0.0-alpha09 + 1.0.0-alpha10 + 1.0.0-alpha11