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 Slide

  2. Non
    -
    goals

    View Slide

  3. Goals

    View Slide

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

    View Slide

  5. Gradle Refresher

    View Slide

  6. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing

    View Slide

  7. 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 Slide

  8. 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 Slide

  9. 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 Slide

  10. 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 Slide

  11. 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 Slide

  12. 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 Slide

  13. 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 Slide

  14. 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 Slide

  15. 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 Slide

  16. Tasks

    View Slide

  17. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing

    View Slide

  18. 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 Slide

  19. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing

    View Slide

  20. 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 Slide

  21. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing

    View Slide

  22. 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 Slide

  23. 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 Slide

  24. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing


    View Slide

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

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

    View Slide

  26. Conf
    i
    guration

    View Slide

  27. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing


    View Slide

  28. 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 Slide

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

    View Slide

  30. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing

    View Slide

  31. Incremental Compilation (IC)
    • Multiple kinds

    • Java – Gradle – JavaCompile

    • Kotlin – JB/Google – KotlinCompile*

    • kaptGenerateStubs*Kotlin

    • kapt*Kotlin

    • compile*Kotlin

    • compile*JavaWithKotlinC

    View Slide

  32. 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 Slide

  33. 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 Slide

  34. 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 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

    View Slide

  36. 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 Slide

  37. 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 Slide

  38. 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 Slide

  39. • Multiple kinds

    • Java – Gradle – JavaCompile

    • Kotlin – JB/Google – KotlinCompile*

    • kaptGenerateStubs*Kotlin

    • kapt*Kotlin

    • compile*Kotlin

    • compile*JavaWithKotlinC
    Incremental Compilation (IC) – Kotlin

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  48. 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  55. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing


    View Slide

  56. Daemons 😈
    Gradle Daemon Kotlin Daemon

    View Slide

  57. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing


    View Slide

  58. Annotation Processing
    javac/kapt KSP

    View Slide

  59. Annotation Processing
    • Non
    -
    incremental


    • Two types of incremental


    • ISOLATING (Dagger, Moshi, etc)


    • AGGREGATING (Glide)
    javac/kapt KSP

    View Slide

  60. Gradle Refresher
    • Tasks


    • Projects


    • Plugins


    • Conf
    i
    gurations


    • Conf
    i
    guration
    • Caching/Incremental
    Builds


    • Incremental
    Compilation (IC)


    • Daemons


    • Annotation Processing


    View Slide

  61. Things That Are Hurting Your Build

    View Slide

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

    View Slide

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

    View Slide

  64. Things That Are Hurting Your Build

    View Slide

  65. Annotation Processors

    View Slide

  66. Annotation Processors

    View Slide

  67. 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 Slide

  68. Frontend Backend
    AnalysisHandler IR Lowering
    Parse/PSI
    psi2ir

    View Slide

  69. Frontend
    Stub gen
    .java f
    i
    les

    View Slide

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

    View Slide

  71. 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 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 Slide

  73. 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 Slide

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

    View Slide

  75. 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 Slide

  76. 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 Slide

  77. kotlinc

    (Frontend only)
    KSP
    .kt


    f
    i
    les
    kotlinc

    (Frontend and Backend)
    compileKotlin
    .class f
    i
    les

    View Slide

  78. 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 Slide

  79. 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 Slide

  80. 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 Slide

  81. kotlinc

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


    View Slide

  82. buildSrc

    View Slide

  83. 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 Slide

  84. 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 Slide

  85. ./gradlew clean

    View Slide

  86. ./gradlew clean

    View Slide

  87. Cleaning does not f
    i
    x
    your build

    View Slide

  88. Don’t mix IDE and
    command line builds

    View Slide

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

    View Slide

  90. View Slide

  91. View Slide

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

    – Chet, certi
    fi
    ed Gradle expert™

    View Slide

  93. Move NDK projects to a
    separate repo

    View Slide

  94. Gradle API Surface Area

    View Slide

  95. 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 Slide

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

    View Slide

  97. 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 Slide

  98. Task Issues

    View Slide

  99. Identifying Task Issues

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  114. Corporate Bloatware

    View Slide

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

    View Slide

  116. 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 Slide

  117. Old tools!

    View Slide

  118. Old tools
    • JDK


    • We are on 17, moving to 18


    • Kotlin


    • Gradle


    • Gradle plugins


    • Compiler plugins


    • Literally anything on your buildscript classpath

    View Slide

  119. 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 Slide

  120. 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 Slide

  121. (CI only)

    View Slide

  122. Don’t merge main on CI
    builds

    View Slide

  123. Lint memory usage

    View Slide

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

    View Slide

  125. 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 Slide

  126. Jacoco

    View Slide

  127. Jacoco

    View Slide

  128. Things That Are Hurting
    Your Build

    View Slide

  129. Things That Will Improve
    Your Build

    View Slide

  130. Build caching
    org.gradle.caching=true

    View Slide

  131. 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 Slide

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

    View Slide

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


    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  137. Modularization

    View Slide

  138. Modularization 🔥

    View Slide

  139. Apple Silicon

    View Slide

  140. Non
    -
    transitive R classes

    View Slide

  141. 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 Slide

  142. 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 Slide

  143. Prefer JVM-only Projects

    View Slide

  144. 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 Slide

  145. 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 Slide

  146. Things That Will Improve
    Your Build

    View Slide

  147. Things That Will Keep
    Your Build Fast

    View Slide

  148. Gradle Enterprise

    View Slide

  149. 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 Slide

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

    View Slide

  151. Benchmarks

    View Slide

  152. Benchmarks

    View Slide

  153. Benchmarks

    View Slide

  154. Telemetry + Check
    -
    ins

    View Slide

  155. 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

  159. 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 Slide

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

    View Slide

  161. modules
    -
    graph
    -
    assert

    View Slide

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

    View Slide

  163. 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 Slide

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

    View Slide

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

    View Slide

  166. 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 Slide

  167. 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 Slide

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

    View Slide

  169. 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 Slide

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

    View Slide

  171. Future
    New Kotlin IC

    View Slide

  172. Future
    New Kotlin IC

    View Slide

  173. 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 Slide

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

    View Slide

  175. 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 Slide

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

    View Slide

  177. 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 Slide

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

    View Slide

  179. 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 Slide

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

    View Slide

  181. 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 Slide

  182. 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 Slide

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

    View Slide