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

KSP - Don't repeat yourself

Meike Felicia Hammer
November 20, 2023
31

KSP - Don't repeat yourself

KSP (Kotlin Symbol Processing) is an API for developing Kotlin compiler plugins. With KSP we can write annotation processors to reduce boilerplate code. Most of us use it, but few of us develop it. In this talk, we'll take a step-by-step look at how to create custom annotations with KSP in the Android development environment. We also look at how meaningful debugging is possible during development.

Meike Felicia Hammer

November 20, 2023
Tweet

Transcript

  1. Meike Felicia Hammer Android Lead @ams Senior Software Engineer Photo

    by Victor Rosario on Unsplash @feliciaf_aye
  2. DRY – DON’T REPEAT YOURSELF. DRY. Photos by Ganapathy Kumar

    and Sangharsh Lohakare on Unsplash REDUCE REPETITION IN INFORMATION USE ABSTRACTIONS WHICH ARE LESS LIKELY TO CHANGE USE DATA NORMALIZATION TO AVOID REDUNDANCY
  3. WET – WRITE EVERYTHING TWICE. WET. Photo by Tim Marshall

    on Unsplash A BACKRONYM AKA WRITE EVERY TIME AKA WE ENJOY TYPING AKA WASTE EVERYONE’S TIME
  4. AHA – AVOID HASTY ABSTRACTIONS. Photo by Pawel Czerwinski on

    Unsplash “OPTIMIZE FOR CHANGE FIRST, AVOID PREMATURE OPTIMIZATION” – Kent C. Dodds “PREFER DUPLICATION OVER THE WRONG ABSTRACTION” – Sandy Metz DON’T OVER ENGINEER
  5. KOTLIN SYMBOL PROCESSING KSP provides a simplified compiler plugin API

    that leverages the power of Kotlin, cause it’s recognizing Kotlin syntax. Keeping the learning curve at a minimum, cause it doesn't rely on extracting Java entities. Perfectly usable as a Kotlin Annotation Processing Tool. Photo by Vincentiu Solomon on Unsplash KSP
  6. METAPROGRAMMING A programming technique in which programs have the ability

    to treat other programs as their data. Meaning a program can be designed to read, generate, analyze or transform other programs. Allows us to minimize the number of lines of code. Photo by NASA on Unsplash
  7. Room Moshi RxHttp Kotshi Lyricist Lich SavedState Paris Auto Dagger

    SealedX DeeplinkDispatch Dagger Hilt Auto Factory WHO USES KSP ALREADY? gRPC Dekorator EasyAdapter Koin Annotations Glide Micronaut Epoxy Photo by Eric Hz on Unsplash
  8. Performance KSP is generally faster than kapt, making your build

    times quicker. Type Safety Directly deal with Kotlin's type system, making processors less error-prone. Integration with Kotlin Features Utilize features like extension functions, sealed classes, etc., directly. ADVANTAGES OVER TRADITIONAL ANNOTATION PROCESSORS Photo by Codioful (Formerly Gradienta) on Unsplash
  9. KotlinPoet is a Kotlin and Java API for generating .kt

    source files. Useful for doing things like annotation processing + interacting with metadata files (e.g. database schemas, protocol formats). Developed by the company square. Photo by Trust "Tru" Katsande on Unsplash KOTLIN POET Provides a nicer API for writing Kotlin source files. Making a great team when combined with KSP.
  10. Maintenance Nightmare • Multiple copies of similar or same code

    • lead to errors, inconsistencies, challenges in refactorings MOTIVATION Photo by Sangharsh Lohakare on Unsplash Redundancy in code • Repetition of code • Writing the same logic across different parts of the app • Time consuming
  11. Auto-Generating Data Mapper Code for API Responses (DTOs) and Domain

    Model Conversions Automatic Repository Pattern Implementation Generation Generating API Client Code from OpenAPI Specification Code Generation for Jetpack Compose Navigation Automating Event Tracking Code Generation in Mobile Apps USE CASES?
  12. A short step by step overview on using KSP &

    KotlinPoet in an Android Kotlin project. KSP & KOTLIN POET STEP BY STEP
  13. 3 Gradle modules - annotations Most simple module, which only

    requires Kotlin language configuration. annotations/ build.gradle.kts
  14. 3 Gradle modules - processor Most important module. Should depend

    on annotations module, KSP API and KotlinPoet artifacts. processor/ build.gradle.kts
  15. 3 Gradle modules - app App module is the consumer

    of our processor. The place where code generation can be seen in action. app/ build.gradle.kts
  16. Implement SymbolProcessorProvider interface. Responsible for instantiating the processor. INSTANTIATE PROCESSOR

    Arguments from SymbolProcessingEnvironment instance provided by KSP. • codeGenerator: creates files with the code generated by the processor. • logger: KSPLogger - provides logging for the processor. • options: Map<String, String> - a collection of key-value options passed to the processor.
  17. Register processor provider by adding fully qualified name in META-INF

    resource file. REGISTER PROCESSOR Resource file name must correctly reflect the package name.
  18. Create a custom @Class annotation. The processor will resolve all

    symbols annotated with it. CREATE ANNOTATION Path /annotations/src/main/kotlin/com/ams/annotation File GenerateTrackingEvent.kt
  19. Most primitive way of debugging: logging. Can’t use Log.d, Timber

    or Napier. Can use KSPLogger parameter passed into the Processor. LOGGING error - this will halt the compilation warn - this will be shown by default info - requires --info parameter provided to the compiler to be visible Photo by Jelena Ardila Vetrovec on Unsplash
  20. DEBUGGING Goals • Gradle task that invokes KSP processor should

    be executed. • KSP execution should happen in same JVM process which is being debugged. • Gradle should be waiting for debugger to attach. Photo by Jelena Ardila Vetrovec on Unsplash
  21. ALWAYS EXECUTE KSP TASK Gradle optimizes task execution • skipping

    unchanged tasks • possibly overlooking KSP updates Effective debugging • specify kspDebugKotlin • use Gradle 7's --rerun option to ensure execution (other tasks continue incrementally) Photo by Jelena Ardila Vetrovec on Unsplash
  22. ALWAYS EXECUTE KSP TASK - ALTERNATIVE Alternatively to ./gradlew :app:kspDebugKotlin

    --rerun run ./gradlew build --rerun-tasks (reruns all tasks). Slower than rerunning specific tasks. Photo by Jelena Ardila Vetrovec on Unsplash
  23. ENSURING SAME PROCESS By default, Kotlin runs KSP in a

    separate daemon process preventing debugging and breakpoints. To run KSP in the same process, set kotlin.compiler.execution.strategy to in-process. • Previously a system property (-D option) • Now a Gradle property in Kotlin 1.7+ (set with -P option or in gradle.properties) • System property option was removed in Kotlin 1.8 Photo by Jelena Ardila Vetrovec on Unsplash
  24. DEBUGGING - REMOTE CONFIG Now it should stop at breakpoints.

    Photo by Jelena Ardila Vetrovec on Unsplash
  25. Troubleshooting Debugging 1/2 Breakpoints not stopping Photo by Jelena Ardila

    Vetrovec on Unsplash If breakpoints aren't hit, verify: • Gradle project is refreshed • Kotlin compiler runs in the same process (- Pkotlin.compiler.execution.strategy=in-process) • the KSP task is executed, not just UP-TO-DATE (--rerun or — rerun-tasks)
  26. Troubleshooting Debugging 2/2 Address already in use Photo by Jelena

    Ardila Vetrovec on Unsplash ./gradlew —stop Alternatively identify the process using the port: lsof -i :5005. Gradle not waiting for debugger • ensure starting new instance each time (—no-daemon) • enable debugging (-Dorg.gradle.debug=true)
  27. Unit Testing of KSP Processors Ensuring the reliability of your

    code generation. Keeping Business Logic Separate Use KSP for boilerplate and structural code. Keep business logic manual to ensure clarity and maintainability. Documentation Auto-generating documentation based on KSP processing. BEST PRACTICES
  28. KSP offers a solution to reduce repetitive boilerplate code. KotlinPoet

    can help write .kt files content easier. KSP integrates seamlessly with Kotlin ecosystem, making it a go-to for Kotlin Android development. In combination it can significantly improve • Development speed • App consistency • Maintainability KEY TAKEAWAYS