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

Improve Build Times in Less Time

Improve Build Times in Less Time

Build times are never as fast as we want but there is a lot you can do to improve them today without being a Gradle domain expert or buying everyone new computers! In this talk we'll cover a number of different tools, patterns, and common pitfalls to avoid for improving your build times quickly and take your (team's) developer productivity to the next level.

Zac Sweers

April 26, 2022
Tweet

More Decks by Zac Sweers

Other Decks in Programming

Transcript

  1. Zac Sweers – Slack – @ZacSweers
    Improve Build Times in
    Less Time
    https://speakerdeck.com/zacsweers/improve-build-times-in-less-time

    View full-size slide

  2. Goals
    https://twitter.com/inyaki_mwc/status/1486091593295695874?s=20&t=RgLHt1bWRcyLXp1oL4qL8A

    View full-size slide

  3. Gradle Refresher

    View full-size slide

  4. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing

    View full-size slide

  5. Tasks
    @CacheableTask
    abstract class PrintMessageTask : DefaultTask() {
    @get:Input
    abstract val inputMessage: Property
    @get:OutputFile
    abstract val outputFile: RegularFileProperty
    @TaskAction
    fun run() {
    val message = inputMessage.get()
    println(message)
    outputFile.asFile.get().writeText(message)
    }
    }

    View full-size slide

  6. Tasks
    • Inputs and outputs
    @CacheableTask
    abstract class PrintMessageTask : DefaultTask() {
    @get:Input
    abstract val inputMessage: Property
    @get:OutputFile
    abstract val outputFile: RegularFileProperty
    @TaskAction
    fun run() {
    val message = inputMessage.get()
    println(message)
    outputFile.asFile.get().writeText(message)
    }
    }

    View full-size slide

  7. Tasks
    • Inputs and outputs

    • Parallelizable
    @CacheableTask
    abstract class PrintMessageTask : DefaultTask() {
    @get:Input
    abstract val inputMessage: Property
    @get:OutputFile
    abstract val outputFile: RegularFileProperty
    @TaskAction
    fun run() {
    val message = inputMessage.get()
    println(message)
    outputFile.asFile.get().writeText(message)
    }
    }

    View full-size slide

  8. Tasks
    • Inputs and outputs

    • Parallelizable

    • Task action
    @CacheableTask
    abstract class PrintMessageTask : DefaultTask() {
    @get:Input
    abstract val inputMessage: Property
    @get:OutputFile
    abstract val outputFile: RegularFileProperty
    @TaskAction
    fun run() {
    val message = inputMessage.get()
    println(message)
    outputFile.asFile.get().writeText(message)
    }
    }

    View full-size slide

  9. Tasks
    • Inputs and outputs

    • Parallelizable

    • Task action

    • Cacheability
    @CacheableTask
    abstract class PrintMessageTask : DefaultTask() {
    @get:Input
    abstract val inputMessage: Property
    @get:OutputFile
    abstract val outputFile: RegularFileProperty
    @TaskAction
    fun run() {
    val message = inputMessage.get()
    println(message)
    outputFile.asFile.get().writeText(message)
    }
    }

    View full-size slide

  10. Tasks
    • Inputs and outputs

    • Parallelizable

    • Task action

    • Cacheability
    @CacheableTask
    abstract class PrintMessageTask : DefaultTask() {
    @get:Input
    abstract val inputMessage: Property
    @get:OutputFile
    abstract val outputFile: RegularFileProperty
    @TaskAction
    fun run() {
    val message = inputMessage.get()
    println(message)
    outputFile.asFile.get().writeText(message)
    }
    }

    View full-size slide

  11. Tasks
    • Inputs and outputs

    • Parallelizable

    • Task action

    • Cacheability

    • Con
    fi
    gured at con
    fi
    guration-time

    • Should be lazy!
    project.tasks.register("printMessage") {
    inputMessage.set("Hello World!")
    outputFile.set(
    project.layout.buildDirectory.
    fi
    le(
    "outputs/logs/message.txt"))
    }

    View full-size slide

  12. Tasks
    • Inputs and outputs

    • Parallelizable

    • Task action

    • Cacheability

    • Con
    fi
    gured at con
    fi
    guration-time

    • Should be lazy!
    @CacheableTask
    abstract class PrintMessageTask : DefaultTask() {
    @get:Input
    abstract val inputMessage: Property
    @get:OutputFile
    abstract val outputFile: RegularFileProperty
    @TaskAction
    fun run() {
    val message = inputMessage.get()
    println(message)
    outputFile.asFile.get().writeText(message)
    }
    }

    View full-size slide

  13. Tasks
    • Inputs and outputs

    • Parallelizable

    • Task action

    • Cacheability

    • Con
    fi
    gured at con
    fi
    guration-time

    • Should be lazy!

    • Some common types (SourceTask,
    CompileTask, etc)
    @CacheableTask
    abstract class PrintMessageTask : DefaultTask() {
    @get:Input
    abstract val inputMessage: Property
    @get:OutputFile
    abstract val outputFile: RegularFileProperty
    @TaskAction
    fun run() {
    val message = inputMessage.get()
    println(message)
    outputFile.asFile.get().writeText(message)
    }
    }

    View full-size slide

  14. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing

    View full-size slide

  15. Projects
    • Projects contain a set of tasks

    • Also contain things like source
    sets

    • Can have subprojects

    • Every directory in between is
    technically a project

    • Can have plugins applied to
    them

    View full-size slide

  16. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing

    View full-size slide

  17. Plugins
    • Reusable implementations of gradle logic

    • Well known examples

    • Android Gradle Plugin (AGP)

    • Kotlin Gradle Plugin (KGP)

    • Many 1st-party plugins

    • Ours too! github.com/slackhq/slack-gradle-plugin
    plugins {
    kotlin("jvm")
    id("com.android.library")
    `java-platform`
    }

    View full-size slide

  18. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing

    View full-size slide

  19. Conf
    i
    gurations
    • Essentially named
    fi
    le collections

    • “implementation”, “api”, etc
    dependencies {
    implementation("com.squareup.moshi:moshi:1.13.0")
    testImplementation("junit:junit:4.13")
    }

    View full-size slide

  20. Conf
    i
    gurations
    • Essentially named
    fi
    le collections

    • “implementation”, “api”, etc
    dependencies {
    implementation("com.squareup.moshi:moshi:1.13.0")
    testImplementation("junit:junit:4.13")
    }

    View full-size slide

  21. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing


    View full-size slide

  22. Conf
    i
    guration
    • Don’t confuse it with
    con
    fi
    gurations

    • The time spent from “go” to
    tasks actually executing

    View full-size slide

  23. Conf
    i
    guration

    View full-size slide

  24. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing


    View full-size slide

  25. Caching/Incremental Builds
    • Multiple kinds

    • build dir

    • Build cache

    • Local/Remote

    • Con
    fi
    guration cache

    • GRADLE_USER_HOME

    • Not Studio caches
    https://www.liutikas.net/2022/04/19/Caches-Everywhere.html

    View full-size slide

  26. Wiping Studio caches
    does not f
    i
    x your build

    View full-size slide

  27. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing

    View full-size slide

  28. Incremental Compilation (IC)
    • Multiple kinds

    • Java – Gradle – JavaCompile

    • Kotlin – JB/Google – KotlinCompile*

    • kaptGenerateStubs*Kotlin

    • kapt*Kotlin

    • compile*Kotlin

    • compile*JavaWithKotlinC

    View full-size slide

  29. Incremental Compilation (IC) – Java
    • Compilation avoidance

    • “Can we not run?”

    • ABI-based

    • Incremental Compilation

    • “Can we only recompile a subset?”
    https://blog.gradle.org/incremental-compiler-avoidance
    :project-a
    :project-b

    View full-size slide

  30. Incremental Compilation (IC) – Java
    • Compilation avoidance

    • “Can we not run?”

    • ABI-based

    • Incremental Compilation

    • “Can we only recompile a subset?”
    https://blog.gradle.org/incremental-compiler-avoidance
    :project-a
    :project-b

    View full-size slide

  31. Incremental Compilation (IC) – Java
    • Compilation avoidance

    • “Can we not run?”

    • ABI-based

    • Incremental Compilation

    • “Can we only recompile a subset?”
    https://blog.gradle.org/incremental-compiler-avoidance
    :project-a
    :project-b

    View full-size slide

  32. Incremental Compilation (IC) – Kotlin
    • Incremental only for now, no avoidance

    • Coming soon though!

    • Depends on producer-side IC data

    • This makes it tricky

    View full-size slide

  33. Incremental Compilation (IC) – Kotlin
    • Incremental only for now, no avoidance

    • Coming soon though!

    • Depends on producer-side IC data

    • This makes it tricky
    :project-a
    :project-b

    View full-size slide

  34. Incremental Compilation (IC) – Kotlin
    • Incremental only for now, no avoidance

    • Coming soon though!

    • Depends on producer-side IC data

    • This makes it tricky
    :project-a
    :project-b

    produces
    consumes

    View full-size slide

  35. Incremental Compilation (IC) – Kotlin
    • Incremental only for now, no avoidance

    • Coming soon though!

    • Depends on producer-side IC data

    • This makes it tricky
    :project-a
    :project-b

    produces
    consumes

    View full-size slide

  36. • Multiple kinds

    • Java – Gradle – JavaCompile

    • Kotlin – JB/Google – KotlinCompile*

    • kaptGenerateStubs*Kotlin

    • kapt*Kotlin

    • compile*Kotlin

    • compile*JavaWithKotlinC
    Incremental Compilation (IC) – Kotlin

    View full-size slide

  37. kaptGenerateStubs*Kotlin
    kapt*Kotlin
    compile*Kotlin compile*JavaWithKotlinC
    Incremental Compilation (IC) – Kotlin

    View full-size slide

  38. kaptGenerateStubs*Kotlin
    kapt*Kotlin
    compile*Kotlin compile*JavaWithKotlinC
    Incremental Compilation (IC) – Kotlin

    View full-size slide

  39. kaptGenerateStubs*Kotlin
    kapt*Kotlin
    compile*Kotlin compile*JavaWithKotlinC
    Incremental Compilation (IC) – Kotlin

    View full-size slide

  40. kaptGenerateStubs*Kotlin
    kapt*Kotlin
    compile*Kotlin compile*JavaWithKotlinC
    Incremental Compilation (IC) – Kotlin

    View full-size slide

  41. kaptGenerateStubs*Kotlin
    kapt*Kotlin
    compile*Kotlin compile*JavaWithKotlinC
    Incremental Compilation (IC) – Kotlin

    View full-size slide

  42. compile*Kotlin
    Incremental Compilation (IC) – Kotlin

    View full-size slide

  43. compile*Kotlin
    Incremental Compilation (IC) – Kotlin
    KotlinCompile

    View full-size slide

  44. compile*Kotlin
    Incremental Compilation (IC) – Kotlin
    KotlinCompile
    kotlinc

    View full-size slide

  45. Incremental Compilation (IC) – Kotlin
    kotlinc
    Frontend Backend
    AnalysisHandler IR Lowering
    https://medium.com/google-developer-experts/crash-course-on-the-
    kotlin-compiler-1-frontend-parsing-phase-9898490d922b
    Parse/PSI
    psi2ir

    View full-size slide

  46. Incremental Compilation (IC) – Kotlin
    Frontend Backend
    AnalysisHandler IR Lowering
    Parse/PSI
    psi2ir
    kaptGenerateStubs*Kotlin
    kapt*Kotlin
    compile*Kotlin compile*JavaWithKotlinC

    View full-size slide

  47. Incremental Compilation (IC) – Kotlin
    Frontend Backend
    AnalysisHandler IR Lowering
    Parse/PSI
    psi2ir
    kaptGenerateStubs*Kotlin
    kapt*Kotlin
    compile*Kotlin compile*JavaWithKotlinC

    View full-size slide

  48. Incremental Compilation (IC) – Kotlin
    Frontend Backend
    AnalysisHandler IR Lowering
    Parse/PSI
    psi2ir
    kaptGenerateStubs*Kotlin
    kapt*Kotlin
    compile*Kotlin compile*JavaWithKotlinC

    View full-size slide

  49. Incremental Compilation (IC) – Kotlin
    Frontend Backend
    AnalysisHandler IR Lowering
    Parse/PSI
    psi2ir
    kaptGenerateStubs*Kotlin
    kapt*Kotlin
    compile*Kotlin compile*JavaWithKotlinC

    View full-size slide

  50. Incremental Compilation (IC) – Kotlin
    kaptGenerateStubs*Kotlin
    kapt*Kotlin
    compile*Kotlin compile*JavaWithKotlinC
    Frontend Backend
    AnalysisHandler IR Lowering
    Parse/PSI
    psi2ir

    View full-size slide

  51. Incremental Compilation (IC) – Kotlin
    Frontend Backend
    AnalysisHandler IR Lowering
    Parse/PSI
    psi2ir
    kaptGenerateStubs*Kotlin
    kapt*Kotlin
    compile*Kotlin compile*JavaWithKotlinC

    View full-size slide

  52. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing


    View full-size slide

  53. Daemons 😈
    Gradle Daemon Kotlin Daemon

    View full-size slide

  54. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing


    View full-size slide

  55. Annotation Processing
    javac/kapt KSP

    View full-size slide

  56. Annotation Processing
    • Non
    -
    incremental


    • Two types of incremental


    • ISOLATING (Dagger, Moshi, etc)


    • AGGREGATING (Glide)
    javac/kapt KSP

    View full-size slide

  57. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing


    View full-size slide

  58. Things That Are Hurting Your Build

    View full-size slide

  59. Things That Are Hurting Your Build
    Things That Will Improve Your Build

    View full-size slide

  60. Things That Are Hurting Your Build
    Things That Will Improve Your Build
    Things That Will Keep Your Build
    Fast

    View full-size slide

  61. Things That Are Hurting Your Build

    View full-size slide

  62. Annotation Processors

    View full-size slide

  63. Annotation Processors

    View full-size slide

  64. Kapt
    • Minimum 3 compilation tasks


    • 4 if you generate/have Java sources (hi, Dagger!)


    • Brittle to classpath changes


    • Disables new FIR


    • Keeps appearing in later problems as a multiplier

    View full-size slide

  65. Frontend Backend
    AnalysisHandler IR Lowering
    Parse/PSI
    psi2ir

    View full-size slide

  66. Frontend
    Stub gen
    .java f
    i
    les

    View full-size slide

  67. kotlinc Frontend
    Stub gen
    .java f
    i
    les
    Kapt (javac)
    Kapt
    .java/.kt f
    i
    les

    View full-size slide

  68. kotlinc

    (Frontend only)
    Stub gen
    .java f
    i
    les
    Kapt (javac)
    Kapt
    .java/.kt f
    i
    les
    kotlinc

    (Frontend and Backend)
    compileKotlin
    .class f
    i
    les

    View full-size slide

  69. kotlinc

    (Frontend only)
    Stub gen
    .java f
    i
    les
    Kapt (javac)
    Kapt
    .java/.kt


    f
    i
    les
    kotlinc

    (Frontend and Backend)
    compileKotlin
    .class f
    i
    les
    javac
    compileJava
    More

    .class f
    i
    les

    View full-size slide

  70. kotlinc

    (Frontend only)
    Stub gen
    .java f
    i
    les
    Kapt (javac)
    Kapt
    .java/.kt


    f
    i
    les
    kotlinc

    (Frontend and Backend)
    compileKotlin
    .class f
    i
    les
    javac
    compileJava
    More

    .class f
    i
    les

    View full-size slide

  71. KSP
    https://github.com/google/ksp

    View full-size slide

  72. kotlinc

    (Frontend only)
    Stub gen
    .java f
    i
    les
    Kapt (javac)
    Kapt
    .java/.kt


    f
    i
    les
    kotlinc

    (Frontend and Backend)
    compileKotlin
    .class f
    i
    les
    javac
    compileJava
    More

    .class f
    i
    les

    View full-size slide

  73. kotlinc

    (Frontend only)
    KSP
    .java/.kt


    f
    i
    les
    javac
    javaCompile
    More .class


    f
    i
    les
    kotlinc

    (Frontend and Backend)
    compileKotlin
    .class f
    i
    les

    View full-size slide

  74. kotlinc

    (Frontend only)
    KSP
    .kt


    f
    i
    les
    kotlinc

    (Frontend and Backend)
    compileKotlin
    .class f
    i
    les

    View full-size slide

  75. kotlinc

    (Frontend and Backend)
    compileKotlin
    .class f
    i
    les
    all
    -
    open


    Kotlinx
    -
    serialization


    parcelize


    moshi


    etc.
    https://blog.bnorm.dev/writing-your-second-compiler-
    plugin-part-1

    View full-size slide

  76. kotlinc

    (Frontend only)
    Stub gen
    .java f
    i
    les
    Kapt (javac)
    Kapt
    .java/.kt


    f
    i
    les
    kotlinc

    (Frontend and Backend)
    compileKotlin
    .class f
    i
    les
    javac
    compileJava
    More

    .class f
    i
    les

    View full-size slide

  77. kotlinc

    (Frontend only)
    Stub gen
    .java f
    i
    les
    Kapt (javac)
    Kapt
    .java/.kt


    f
    i
    les
    kotlinc

    (Frontend and Backend)
    compileKotlin
    .class f
    i
    les
    javac
    compileJava
    More

    .class f
    i
    les
    https://github.com/square/anvil


    View full-size slide

  78. kotlinc

    (Frontend and Backend)
    compileKotlin
    .class f
    i
    les
    Anvil runs here
    https://github.com/square/anvil


    View full-size slide

  79. buildSrc
    • Regularly invalidates buildscript classpath


    • It’s like occasionally having
    - -
    rerun
    -
    tasks


    • What’s the alternative?


    • Version catalogs for deps


    • Separate repo + artifactory for plugins

    View full-size slide

  80. buildSrc
    • What about live testing?


    • Use included builds
    if ("slack.plugin.internal.localPath" in extra.properties) {
    val path = (extra["slack.plugin.internal.localPath"] as String)
    includeBuild(path) {
    dependencySubstitution {
    substitute(module("slack.internal.gradle:slack-plugin-internal"))
    .using(project(":slack-plugin-internal"))
    }
    }
    }

    View full-size slide

  81. ./gradlew clean

    View full-size slide

  82. ./gradlew clean

    View full-size slide

  83. Cleaning does not f
    i
    x
    your build

    View full-size slide

  84. Don’t mix IDE and
    command line builds

    View full-size slide

  85. Don’t mix IDE and
    command line builds
    https://issuetracker.google.com/
    issues/164145066

    View full-size slide

  86. “What do you think you’d produce if you were hammered?”

    – Chet, certi
    fi
    ed Gradle expert™

    View full-size slide

  87. Move NDK projects to a
    separate repo

    View full-size slide

  88. Gradle API Surface Area

    View full-size slide

  89. Gradle API Surface Area
    con
    fi
    gurations.all {
    }
    extensions.get(...)
    tasks.getByName(...)
    var property: String
    con
    fi
    gurations.con
    fi
    gureEach {
    // Lazy!
    }
    extensions.con
    fi
    gure(...) {
    // Lazy!
    }
    tasks.named(...) {
    // Lazy!
    }
    val property: Property
    http://autonomousapps.com/blog/rules-for-
    gradle-plugin-authors.html

    View full-size slide

  90. Incremental Compilation
    Issues
    https://www.zacsweers.dev/
    optimizing-your-kotlin-build/

    View full-size slide

  91. Incremental Compilation Issues
    • Pure Java projects break IC on every project that depends on them
    (directly or transitively)


    • Java
    -
    only, resources
    -
    only, etc


    • Workaround: add a Kotlin f
    i
    le


    • KT-30980 KT-38622


    • Code gen tools generating non
    -
    deterministic outputs


    • Resource ABI changes break IC (KT-40772)


    • Cleaning https://www.zacsweers.dev/
    optimizing-your-kotlin-build/

    View full-size slide

  92. Identifying Task Issues

    View full-size slide

  93. Identifying Task Issues
    ./gradlew :app:assembleDebug
    Build 1

    View full-size slide

  94. Identifying Task Issues
    ./gradlew :app:assembleDebug
    Build 1 Build 2

    View full-size slide

  95. Identifying Task Issues
    ./gradlew :app:assembleDebug
    Build 1 Build 2

    View full-size slide

  96. Identifying Task Issues
    ./gradlew :app:assembleDebug
    Build 1 Build 2

    View full-size slide

  97. Identifying Task Issues
    ./gradlew :app:assembleDebug
    Build 1 Build 2

    View full-size slide

  98. Identifying Task Issues
    ./gradlew :app:assembleDebug
    Build 1 Build 2

    View full-size slide

  99. Identifying Task Issues
    ./gradlew :app:assembleDebug
    Build 1 Build 2

    View full-size slide

  100. Identifying Task Issues
    ./gradlew :app:assembleDebug
    Build 1 Build 2

    View full-size slide

  101. Identifying Caching
    Issues
    ./gradlew :app:assembleDebug
    Build 1 Build 2

    View full-size slide

  102. Identifying Caching
    Issues
    ./gradlew clean
    Build 1 Build 2

    View full-size slide

  103. Identifying Caching
    Issues
    ./gradlew :app:assembleDebug
    Build 1 Build 2

    View full-size slide

  104. Identifying Caching
    Issues
    ./gradlew :app:assembleDebug
    Build 1 Build 2

    View full-size slide

  105. Identifying Caching
    Issues
    ./gradlew :app:assembleDebug
    Build 1 Build 2
    🗂 Di
    ff
    erent directory

    View full-size slide

  106. Identifying Caching
    Issues
    ./gradlew :app:assembleDebug
    Build 1 Build 2
    ☁ CI

    View full-size slide

  107. Corporate Bloatware

    View full-size slide

  108. Literally bugs
    https://www.zacsweers.dev/
    optimizing-your-kotlin-build/

    View full-size slide

  109. Literally bugs
    • Kotlin build cache entries often break incremental
    compilation. KT-34862


    • Gradle AbstractCompile tasks (i.e. KotlinCompile) are
    sensitive to classpath jar ordering. gradle/gradle#15626


    • Error
    -
    prone freeCompilerArgs use. KT-41985
    https://www.zacsweers.dev/
    optimizing-your-kotlin-build/

    View full-size slide

  110. Old tools
    • JDK


    • We are on 17, moving to 18


    • Kotlin


    • Gradle


    • Gradle plugins


    • Compiler plugins


    • Literally anything on your buildscript classpath

    View full-size slide

  111. Tune GCs
    org.gradle.jvmargs=... -XX:+UseG1GC \
    -XX:+UnlockExperimentalVMOptions \
    -XX:G1NewSizePercent=67 \
    -XX:G1MaxNewSizePercent=67
    https://github.com/slackhq/slack-gradle-plugin/blob/main/slack-
    plugin/src/main/kotlin/slack/gradle/tasks/BootstrapTask.kt

    View full-size slide

  112. Tune Daemons
    org.gradle.jvmargs=... -Xms2g -Xmx8g
    kotlin.daemon.jvmargs=... -Xms6g -Xmx24g
    https://github.com/slackhq/slack-gradle-plugin/blob/main/slack-
    plugin/src/main/kotlin/slack/gradle/tasks/BootstrapTask.kt

    View full-size slide

  113. Don’t merge main on CI
    builds

    View full-size slide

  114. Lint memory usage

    View full-size slide

  115. Lint memory usage
    org.gradle.jvmargs=... -XX:MaxMetaspaceSize=1g

    View full-size slide

  116. Tune Daemons
    org.gradle.jvmargs=... -Xms24g -Xmx24g
    kotlin.daemon.jvmargs=... -Xms4g -Xmx4g
    https://github.com/slackhq/slack-gradle-plugin/blob/main/slack-
    plugin/src/main/kotlin/slack/gradle/tasks/BootstrapTask.kt

    View full-size slide

  117. Things That Are Hurting
    Your Build

    View full-size slide

  118. Things That Will Improve
    Your Build

    View full-size slide

  119. Build caching
    org.gradle.caching=true

    View full-size slide

  120. Remote Build


    caching
    buildCache {
    local {
    isEnabled = true
    }
    remote {
    isEnabled = !gradle.startParameter.isOf
    fl
    ine
    setUrl(“…”)
    // only write to cache from build server
    isPush = isCi
    credentials {
    username = ...
    password = ...
    }
    }
    }

    View full-size slide

  121. android
    -
    cache
    -
    f
    i
    x
    -
    gradle
    -
    plugin
    https://github.com/gradle/android-cache-
    fi
    x-gradle-plugin

    View full-size slide

  122. Virtual File System (VFS)
    org.gradle.vfs.watch=true
    https://blog.gradle.org/introducing-
    fi
    le-
    system-watching


    View full-size slide

  123. Conf
    i
    guration Caching
    org.gradle.unsafe.con
    fi
    guration-cache=true
    https://blog.gradle.org/introducing-
    con
    fi
    guration-caching

    View full-size slide

  124. Focus
    https://github.com/dropbox/focus
    ./gradlew :my-feature:sample:focus

    View full-size slide

  125. Single
    -
    variant Libraries
    androidComponents {
    beforeVariants(selector().withBuildType("debug")) { builder ->
    builder.enable = false
    }
    }

    View full-size slide

  126. Modularization

    View full-size slide

  127. Modularization 🔥

    View full-size slide

  128. Apple Silicon

    View full-size slide

  129. Non
    -
    transitive R classes

    View full-size slide

  130. Non
    -
    transitive R classes
    • 5.5MB or 8.5% of Slack APK size


    • 14% incremental build time improvement w/ layout change


    • import slack.l10n.R as L10nR

    View full-size slide

  131. Disable Android Features
    # Build features that are disabled by default in all projects
    android.defaults.buildfeatures.aidl=false
    android.defaults.buildfeatures.buildcon
    fi
    g=false
    android.defaults.buildfeatures.renderscript=false
    android.defaults.buildfeatures.resvalues=false
    android.defaults.buildfeatures.shaders=false

    View full-size slide

  132. Prefer JVM-only Projects

    View full-size slide

  133. Make A Platform Plugin
    import slack.gradle.Platforms
    plugins {
    id("slack.base")
    `java-platform`
    }
    val catalog = extensions.
    fi
    ndByType()
    ?.
    fi
    nd("libs")
    ?: error("Could not
    fi
    nd libs catalog!")
    Platforms.applyFromCatalog(project, catalog.get())
    https://github.com/slackhq/slack-gradle-plugin/blob/main/slack-
    plugin/src/main/kotlin/slack/gradle/Platforms.kt

    View full-size slide

  134. Other Things
    • Remove jetif
    i
    er (use `checkJetif
    i
    er` task in AGP 7.1)


    • api/impl projects


    • api/impl conf
    i
    gurations don’t avoid compilations, just
    control visibility



    View full-size slide

  135. Things That Will Improve
    Your Build

    View full-size slide

  136. Things That Will Keep
    Your Build Fast

    View full-size slide

  137. Gradle Enterprise

    View full-size slide

  138. Gradle Enterprise
    • Remote build cache


    • Build scans


    • Compare builds


    • Trends/insight/visualization


    • Export API


    • Critical path


    • Tags/custom values


    • Debugging (everyone has a scan ready)

    View full-size slide

  139. Benchmarks
    https://github.com/gradle/gradle-pro
    fi
    ler

    View full-size slide

  140. Telemetry + Check
    -
    ins

    View full-size slide

  141. Telemetry
    • Local vs CI (GE tag)


    • System arch (rolling out M1 Macs)


    • Thermals


    • https:
    / /
    github.com/slackhq/slack
    -
    gradle
    -
    plugin/blob/main/slack
    -
    plugin/src/main/kotlin/slack/gradle/util/ThermalsWatcher.kt


    • VCS state


    • Env info (OS, version, etc)

    View full-size slide

  142. Gradle
    -
    doctor
    https://runningcode.github.io/gradle-doctor/

    View full-size slide

  143. TaskUpToDateValidator
    https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-main/buildSrc/
    private/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt

    View full-size slide

  144. modules
    -
    graph
    -
    assert
    https://github.com/jraska/modules-graph-assert

    View full-size slide

  145. modules
    -
    graph
    -
    assert
    https://github.com/jraska/modules-graph-assert
    moduleGraphAssert {
    maxHeight = 4
    allowed = [':.* -> :core', ':feature.* -> :lib.*'] // regex to match module names
    restricted = [':feature-[a-z]* -X> :forbidden-to-depend-on'] // regex to match module names
    con
    fi
    gurations = ['api', 'implementation'] // Dependency confs to look.
    }

    View full-size slide

  146. modules
    -
    graph
    -
    assert
    https://github.com/jraska/modules-graph-assert

    View full-size slide

  147. modules
    -
    graph
    -
    assert

    View full-size slide

  148. dependency
    -
    analysis
    -
    android
    -
    gradle
    -
    plugin
    https://github.com/autonomousapps/dependency-analysis-android-gradle-plugin

    View full-size slide

  149. dependency
    -
    analysis
    -
    android
    -
    gradle
    -
    plugin
    https://github.com/slackhq/slack-gradle-plugin/blob/main/slack-plugin/src/main/
    kotlin/slack/dependencyrake/DependencyRake.kt
    /**
    * Task that consumes the generated advice report json generated by `AdviceTask`
    * and applies its advice to the project build
    fi
    le. This is usually not run
    * directly, but rather added as a
    fi
    nalizer to the `AdviceTask` it reads from.
    */
    class RakeDependencies(...) : AbstractPostProcessingTask() {
    // ...
    }

    View full-size slide

  150. https://github.com/slackhq/slack-gradle-plugin/blob/main/slack-plugin/src/main/
    kotlin/slack/dependencyrake/DependencyRake.kt

    View full-size slide

  151. https://github.com/slackhq/slack-gradle-plugin
    Convention Plugins

    View full-size slide

  152. https://github.com/slackhq/slack-gradle-plugin
    Convention Plugins
    plugins {
    id("com.android.library")
    kotlin("android")
    id("com.squareup.anvil")
    }
    android {
    namespace = "slack.libraries.emoji.api"
    compileSdk = 31
    defaultCon
    fi
    g {
    minSdk = 26
    }
    buildTypes {
    debug {
    matchingFallbacks.add("release")
    }
    }
    compileOptions {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
    }
    }
    androidComponents {
    beforeVariants { builder ->
    if (builder.buildType == "debug") {
    builder.enable = false
    } else {
    builder.enableAndroidTest = hasProperty("slack.libraryWithAndroidTest")
    }
    }
    }
    anvil {
    generateFactories = true
    }
    dependencies {
    compileOnly(libs.dagger.dagger)
    implementation(projects.libraries.emoji.data)
    implementation(projects.libraries.foundation.slackCommons.android)
    implementation(projects.libraries.imageLoading)
    implementation(projects.libraries.model)
    implementation(projects.libraries.telemetry.telemetryPublic)
    implementation(libs.rxJava.java3)
    }

    View full-size slide

  153. https://github.com/slackhq/slack-gradle-plugin
    Convention Plugins
    plugins {
    id("slack.base")
    id("com.android.library")
    kotlin("android")
    }
    slack {
    features {
    dagger()
    }
    }
    dependencies {
    implementation(projects.libraries.emoji.data)
    implementation(projects.libraries.foundation.slackCommons.android)
    implementation(projects.libraries.imageLoading)
    implementation(projects.libraries.model)
    implementation(projects.libraries.telemetry.telemetryPublic)
    implementation(libs.rxJava.java3)
    }

    View full-size slide

  154. Future
    https://slack.engineering/shadow-jobs/

    View full-size slide

  155. Future
    New Kotlin IC
    • Consumer
    -
    side IC based on classpath snapshot


    • Unstable preview available in 1.6.20, targeting 1.7


    • Solves many producer
    -
    side issues (Java projects,
    caching, etc)


    • True compilation avoidance in some cases (
    ! !
    )
    kotlin.incremental.useClasspathSnapshot=true
    https://youtrack.jetbrains.com/issue/KT-45777

    View full-size slide

  156. Future
    New Kotlin IC
    https://youtrack.jetbrains.com/issue/
    KT-45777#focus=Comments-27-6004789.0-0

    View full-size slide

  157. Future
    New Kotlin IC

    View full-size slide

  158. Future
    New Kotlin IC

    View full-size slide

  159. Future
    K2 Compiler
    • New Kotlin compiler frontend (aka FIR)


    • Promises 2-4x build speed improvements


    • Preview coming in 1.7
    https://blog.jetbrains.com/kotlin/2021/10/the-road-to-the-k2-compiler/

    View full-size slide

  160. Future
    Conf
    i
    guration Caching
    org.gradle.unsafe.con
    fi
    guration-cache=true
    https://blog.gradle.org/introducing-
    con
    fi
    guration-caching

    View full-size slide

  161. Future
    Gradle Project Isolation
    • Conf
    i
    guration cache pt. 2


    • True project isolation, will allow parallel
    conf
    i
    guration and tooling model creation (aka Studio
    sync)


    • WIP. TL;DR don’t use allprojects/subprojects
    https://gradle.github.io/con
    fi
    guration-cache/#project_isolation
    systemProp.org.gradle.unsafe.isolated-projects=true

    View full-size slide

  162. –You, an upstanding citizen
    “How can I help?”

    View full-size slide

  163. How can I help?
    • Report bugs!


    • Open source your build stuff


    • Test/prepare for new features


    • Use modern APIs


    • Make your own convention plugin


    • File feature requests
    *

    View full-size slide

  164. –You, an upstanding citizen
    “What should I do today?”

    View full-size slide

  165. What should I do today?
    • Audit deprecated/eager APIs


    • Update your tools (JDK, Gradle, Kotlin, etc)


    • Swap KSP for kapt where possible


    • Single
    -
    variant libraries


    • Disable android features by default


    • Fix java
    -
    only projects breaking IC


    • Dependency analysis to remove unused deps

    View full-size slide

  166. –You, a future upstanding citizen
    “What should I do tomorrow?”

    View full-size slide

  167. What should I do tomorrow?
    • Learn some Gradle


    • Reduce/remove Kapt


    • Create gradle
    -
    prof
    i
    ler
    scenarios


    • Modularization


    • Gradle Enterprise


    • Apple Silicon
    • Incorporate new tools prep
    in planning


    • OSS your stuff

    View full-size slide

  168. People to follow for more!
    • Tony Robalik – @AutonomousApps – https:
    / /
    dev.to/autonomousapps


    • Aurimas Liutikas – @_aurimas – https:
    / / w w w
    .liutikas.net/blog
    -
    posts


    • Iñaki Villar – @inyaki_mwc


    • Ryan Harter – @rharter – http:
    / /
    ryanharter.com/


    • Xavier Ducrohet – @droidxav – https:
    / /
    developer.android.com/reference/tools/gradle
    -
    api


    • “Xav says read the docs and stop touching internal APIs”


    • Ivan Gavrilovic – @gavra0


    • Cesar Puerta – @CesarDielo


    • Nelson Osacky – @nellyspageli – https:
    / /
    osacky.com/


    • Jendrik Johannes – @jeoj – youtube.com/c/onepieceSoftware – github.com/jjohannes

    View full-size slide

  169. Zac Sweers – Slack – @ZacSweers
    Improve Build Times in
    Less Time

    View full-size slide