Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

Non - goals

Slide 3

Slide 3 text

Goals

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

Gradle Refresher

Slide 6

Slide 6 text

Gradle Refresher • Tasks • Projects • Plugins • Conf i gurations • Conf i guration • Caching/Incremental Builds • Incremental Compilation (IC) • Daemons • Annotation Processing

Slide 7

Slide 7 text

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) } }

Slide 8

Slide 8 text

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) } }

Slide 9

Slide 9 text

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) } }

Slide 10

Slide 10 text

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) } }

Slide 11

Slide 11 text

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) } }

Slide 12

Slide 12 text

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) } }

Slide 13

Slide 13 text

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")) }

Slide 14

Slide 14 text

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) } }

Slide 15

Slide 15 text

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) } }

Slide 16

Slide 16 text

Tasks

Slide 17

Slide 17 text

Gradle Refresher • Tasks • Projects • Plugins • Conf i gurations • Conf i guration • Caching/Incremental Builds • Incremental Compilation (IC) • Daemons • Annotation Processing

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

Gradle Refresher • Tasks • Projects • Plugins • Conf i gurations • Conf i guration • Caching/Incremental Builds • Incremental Compilation (IC) • Daemons • Annotation Processing

Slide 20

Slide 20 text

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` }

Slide 21

Slide 21 text

Gradle Refresher • Tasks • Projects • Plugins • Conf i gurations • Conf i guration • Caching/Incremental Builds • Incremental Compilation (IC) • Daemons • Annotation Processing

Slide 22

Slide 22 text

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") }

Slide 23

Slide 23 text

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") }

Slide 24

Slide 24 text

Gradle Refresher • Tasks • Projects • Plugins • Conf i gurations • Conf i guration • Caching/Incremental Builds • Incremental Compilation (IC) • Daemons • Annotation Processing

Slide 25

Slide 25 text

Conf i guration • Don’t confuse it with con fi gurations • The time spent from “go” to tasks actually executing

Slide 26

Slide 26 text

Conf i guration

Slide 27

Slide 27 text

Gradle Refresher • Tasks • Projects • Plugins • Conf i gurations • Conf i guration • Caching/Incremental Builds • Incremental Compilation (IC) • Daemons • Annotation Processing

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Wiping Studio caches does not f i x your build

Slide 30

Slide 30 text

Gradle Refresher • Tasks • Projects • Plugins • Conf i gurations • Conf i guration • Caching/Incremental Builds • Incremental Compilation (IC) • Daemons • Annotation Processing

Slide 31

Slide 31 text

Incremental Compilation (IC) • Multiple kinds • Java – Gradle – JavaCompile • Kotlin – JB/Google – KotlinCompile* • kaptGenerateStubs*Kotlin • kapt*Kotlin • compile*Kotlin • compile*JavaWithKotlinC

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

Incremental Compilation (IC) – Kotlin • Incremental only for now, no avoidance • Coming soon though! • Depends on producer-side IC data • This makes it tricky

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

• Multiple kinds • Java – Gradle – JavaCompile • Kotlin – JB/Google – KotlinCompile* • kaptGenerateStubs*Kotlin • kapt*Kotlin • compile*Kotlin • compile*JavaWithKotlinC Incremental Compilation (IC) – Kotlin

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

compile*Kotlin Incremental Compilation (IC) – Kotlin

Slide 46

Slide 46 text

compile*Kotlin Incremental Compilation (IC) – Kotlin KotlinCompile

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

Gradle Refresher • Tasks • Projects • Plugins • Conf i gurations • Conf i guration • Caching/Incremental Builds • Incremental Compilation (IC) • Daemons • Annotation Processing

Slide 56

Slide 56 text

Daemons 😈 Gradle Daemon Kotlin Daemon

Slide 57

Slide 57 text

Gradle Refresher • Tasks • Projects • Plugins • Conf i gurations • Conf i guration • Caching/Incremental Builds • Incremental Compilation (IC) • Daemons • Annotation Processing

Slide 58

Slide 58 text

Annotation Processing javac/kapt KSP

Slide 59

Slide 59 text

Annotation Processing • Non - incremental • Two types of incremental • ISOLATING (Dagger, Moshi, etc) • AGGREGATING (Glide) javac/kapt KSP

Slide 60

Slide 60 text

Gradle Refresher • Tasks • Projects • Plugins • Conf i gurations • Conf i guration • Caching/Incremental Builds • Incremental Compilation (IC) • Daemons • Annotation Processing

Slide 61

Slide 61 text

Things That Are Hurting Your Build

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

Things That Are Hurting Your Build

Slide 65

Slide 65 text

Annotation Processors

Slide 66

Slide 66 text

Annotation Processors

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

Frontend Backend AnalysisHandler IR Lowering Parse/PSI psi2ir

Slide 69

Slide 69 text

Frontend Stub gen .java f i les

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

kotlinc 
 (Frontend only) KSP .kt f i les kotlinc 
 (Frontend and Backend) compileKotlin .class f i les

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

buildSrc

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

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")) } } }

Slide 85

Slide 85 text

./gradlew clean

Slide 86

Slide 86 text

./gradlew clean

Slide 87

Slide 87 text

Cleaning does not f i x your build

Slide 88

Slide 88 text

Don’t mix IDE and command line builds

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

No content

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

“What do you think you’d produce if you were hammered?”
 – Chet, certi fi ed Gradle expert™

Slide 93

Slide 93 text

Move NDK projects to a separate repo

Slide 94

Slide 94 text

Gradle API Surface Area

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

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

Slide 97

Slide 97 text

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/

Slide 98

Slide 98 text

Task Issues

Slide 99

Slide 99 text

Identifying Task Issues

Slide 100

Slide 100 text

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

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

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

Slide 103

Slide 103 text

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

Slide 104

Slide 104 text

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

Slide 105

Slide 105 text

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

Slide 106

Slide 106 text

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

Slide 107

Slide 107 text

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

Slide 108

Slide 108 text

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

Slide 109

Slide 109 text

Identifying Caching Issues ./gradlew clean Build 1 Build 2

Slide 110

Slide 110 text

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

Slide 111

Slide 111 text

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

Slide 112

Slide 112 text

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

Slide 113

Slide 113 text

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

Slide 114

Slide 114 text

Corporate Bloatware

Slide 115

Slide 115 text

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

Slide 116

Slide 116 text

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/

Slide 117

Slide 117 text

Old tools!

Slide 118

Slide 118 text

Old tools • JDK • We are on 17, moving to 18 • Kotlin • Gradle • Gradle plugins • Compiler plugins • Literally anything on your buildscript classpath

Slide 119

Slide 119 text

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

Slide 120

Slide 120 text

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

Slide 121

Slide 121 text

(CI only)

Slide 122

Slide 122 text

Don’t merge main on CI builds

Slide 123

Slide 123 text

Lint memory usage

Slide 124

Slide 124 text

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

Slide 125

Slide 125 text

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

Slide 126

Slide 126 text

Jacoco

Slide 127

Slide 127 text

Jacoco

Slide 128

Slide 128 text

Things That Are Hurting Your Build

Slide 129

Slide 129 text

Things That Will Improve Your Build

Slide 130

Slide 130 text

Build caching org.gradle.caching=true

Slide 131

Slide 131 text

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 = ... } } }

Slide 132

Slide 132 text

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

Slide 133

Slide 133 text

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

Slide 134

Slide 134 text

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

Slide 135

Slide 135 text

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

Slide 136

Slide 136 text

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

Slide 137

Slide 137 text

Modularization

Slide 138

Slide 138 text

Modularization 🔥

Slide 139

Slide 139 text

Apple Silicon

Slide 140

Slide 140 text

Non - transitive R classes

Slide 141

Slide 141 text

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

Slide 142

Slide 142 text

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

Slide 143

Slide 143 text

Prefer JVM-only Projects

Slide 144

Slide 144 text

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

Slide 145

Slide 145 text

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 •

Slide 146

Slide 146 text

Things That Will Improve Your Build

Slide 147

Slide 147 text

Things That Will Keep Your Build Fast

Slide 148

Slide 148 text

Gradle Enterprise

Slide 149

Slide 149 text

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)

Slide 150

Slide 150 text

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

Slide 151

Slide 151 text

Benchmarks

Slide 152

Slide 152 text

Benchmarks

Slide 153

Slide 153 text

Benchmarks

Slide 154

Slide 154 text

Telemetry + Check - ins

Slide 155

Slide 155 text

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)

Slide 156

Slide 156 text

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

Slide 157

Slide 157 text

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

Slide 158

Slide 158 text

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

Slide 159

Slide 159 text

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

Slide 160

Slide 160 text

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

Slide 161

Slide 161 text

modules - graph - assert

Slide 162

Slide 162 text

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

Slide 163

Slide 163 text

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() { // ... }

Slide 164

Slide 164 text

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

Slide 165

Slide 165 text

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

Slide 166

Slide 166 text

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) }

Slide 167

Slide 167 text

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) }

Slide 168

Slide 168 text

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

Slide 169

Slide 169 text

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

Slide 170

Slide 170 text

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

Slide 171

Slide 171 text

Future New Kotlin IC

Slide 172

Slide 172 text

Future New Kotlin IC

Slide 173

Slide 173 text

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/

Slide 174

Slide 174 text

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

Slide 175

Slide 175 text

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

Slide 176

Slide 176 text

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

Slide 177

Slide 177 text

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 *

Slide 178

Slide 178 text

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

Slide 179

Slide 179 text

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

Slide 180

Slide 180 text

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

Slide 181

Slide 181 text

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

Slide 182

Slide 182 text

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

Slide 183

Slide 183 text

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