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

Gradle build: The time is now

Gradle build: The time is now

Alexey Bykov

January 25, 2023
Tweet

More Decks by Alexey Bykov

Other Decks in Programming

Transcript

  1. GRADLE BUILD:
    The time is now
    Alexey Bykov

    View Slide

  2. 2
    Alexey Bykov
    Senior Software Engineer
    6 years
    Google Developer Expert
    @nonewsss

    View Slide

  3. Dad what's that dark place
    over there?

    View Slide

  4. Goals
    Feel comfortable about

    View Slide

  5. Goals
    Feel comfortable about
    Improve build time

    View Slide

  6. 6
    Build time. Why?

    View Slide

  7. 7 Such sample not applies to Reddit or any other company I may worked at
    Build time. Why?
    ~ 10 engineers
    ~ 12 m
    ~ 20 builds (daily)

    View Slide

  8. 8 Such sample not applies to Reddit or any other company I may worked at
    Build time. Why?
    ~ 1000 builds
    ~ 200 h
    Weekly
    ~ 10 engineers
    ~ 12 m
    ~ 20 builds (daily)

    View Slide

  9. 9
    ~ 200 h

    View Slide

  10. 10
    Gradle starter

    View Slide

  11. 11
    Gradle starter
    Tasks
    Plugins
    Projects
    Build Lifecycle
    Caching
    Properties

    View Slide

  12. 12
    Gradle starter
    Tasks
    Plugins
    Projects
    Build Lifecycle
    Caching
    Properties

    View Slide

  13. 13
    What is a build?

    View Slide

  14. 14
    Build
    Sequence of steps to transform

    source code to a final product
    Step Step Step binary
    Src

    View Slide

  15. 15
    Steps == Tasks
    Task Task Task binary
    Src

    View Slide

  16. 16
    Tasks can be asynchronous
    Task
    Task
    Task
    binary
    Src

    View Slide

  17. 17
    Input & output
    Task

    View Slide

  18. 18
    Input & output
    Task
    @Input
    @InputFiles
    Input

    View Slide

  19. 19
    Input & output
    Task
    @Input
    @TaskAction
    @InputFiles
    Input

    View Slide

  20. 20
    Input & output
    Task
    @Input
    @OutputDirectory
    @TaskAction
    @InputFiles
    Input
    Output

    View Slide

  21. 21
    JavaCompile
    Java Version
    Example

    View Slide

  22. 22
    Example
    JavaCompile
    Java Version
    Source code

    View Slide

  23. 23
    Example
    JavaCompile
    Java Version
    Source code
    Compiler args
    Class files

    View Slide

  24. 24
    Tasks can be dependant
    Task
    Task
    Task
    Input
    Output
    Output
    Output

    View Slide

  25. 25
    Tasks can be cacheable
    Task
    @CacheableTask
    Input Output

    View Slide

  26. 26
    Tasks can be cacheable
    Task
    Input Output
    Cache
    @CacheableTask

    View Slide

  27. 27
    Tasks labels

    View Slide

  28. 28
    BUILD SUCCESSFUL in 6m 49s


    7960 actionable tasks: 130 executed, 371 from cache, 7459 up-to-date


    Tasks labels

    View Slide

  29. 29
    BUILD SUCCESSFUL in 6m 49s


    7960 actionable tasks: 130 executed, 371 from cache, 7459 up-to-date


    Tasks labels

    View Slide

  30. 30
    UP-TO-DATE
    Incremental cache

    applied

    View Slide

  31. 31
    FROM CACHE
    Build cache applied

    View Slide

  32. 32
    SKIPPED
    Excluded explicitly

    or has predicate

    View Slide

  33. 33
    NO SOURCE
    Can’t be executed,

    as there is no code

    View Slide

  34. 34
    EXECUTED (NO LABEL)
    Task run its action

    View Slide

  35. 35
    Task sources
    — Build script (kts/groovy)
    — Build Src
    — External (like plugin)

    View Slide

  36. 36
    Gradle starter
    Tasks
    Plugins
    Projects
    Build Lifecycle
    Caching
    Properties

    View Slide

  37. 37
    Project
    — Main Gradle API
    — Set of the tasks
    — 1 to 1 dependency with build.gradle

    View Slide

  38. 38
    Gradle starter
    Tasks
    Plugins
    Projects
    Build Lifecycle
    Caching
    Properties

    View Slide

  39. 39
    Plugins
    — Configuration of settings and tasks

    View Slide

  40. 40
    Plugins
    — Configuration of settings and tasks
    — Example:
    * Android Gradle Plugin (AGP)
    * Kotlin Gradle Plugin (KGP)

    View Slide

  41. 41
    Gradle starter
    Tasks
    Plugins
    Projects
    Build Lifecycle
    Caching
    Properties

    View Slide

  42. 42
    Build Lifecycle
    1. Configuration
    What to do? (Configure tasks)

    View Slide

  43. 43
    1. Configuration
    What to do? (Configure tasks)
    Build Lifecycle
    2. Execution
    Tasks

    View Slide

  44. 44
    Gradle starter
    Tasks
    Plugins
    Projects
    Build Lifecycle
    Caching
    Properties

    View Slide

  45. Caching
    Gradle

    Daemon
    JVM process

    View Slide

  46. Caching
    Gradle

    Daemon
    JVM process
    * Long-running process

    View Slide

  47. Caching
    Gradle

    Daemon
    JVM process
    * Long-running process
    * Enabled by default

    View Slide

  48. Caching
    Gradle

    Daemon
    JVM process
    * Long-running process
    * Enabled by default
    * Not stable on the CI

    View Slide

  49. Caching
    Gradle

    Daemon
    JVM process
    * Long-running process
    * Enabled by default
    * Not stable on the CI
    org.gradle.daemon=false
    #gradle.properties

    View Slide

  50. Caching
    Gradle

    Daemon
    JVM process
    In memory

    View Slide

  51. Caching
    Configuration

    cache

    View Slide

  52. Caching
    Configuration

    cache
    * Experimental

    View Slide

  53. Caching
    Configuration

    cache
    * Experimental
    * project/.gradle/configuration-cache

    View Slide

  54. Caching
    Configuration

    cache
    * Experimental
    * project/.gradle/configuration-cache
    * Works based on input/output

    principle

    View Slide

  55. Caching
    Gradle

    Daemon
    JVM process
    Configuration

    cache
    In memory In project

    View Slide

  56. Caching
    Incremental

    cache

    View Slide

  57. Caching
    Incremental

    cache
    * Short-term cache

    View Slide

  58. Caching
    Incremental

    cache
    * Short-term cache
    * Stores in build folders

    View Slide

  59. Caching
    Incremental

    cache
    * Short-term cache
    * Can be easily invalidated
    * Stores in build folders

    View Slide

  60. Caching
    In memory In project
    Gradle

    Daemon
    JVM process
    Configuration

    cache
    Incremental

    cache

    View Slide

  61. Caching
    Build

    cache

    View Slide

  62. Caching
    Build

    cache
    * Long-term cache

    View Slide

  63. Caching
    Build

    cache
    * Long-term cache
    * ~.gradle/caches/build-cache1/

    View Slide

  64. Caching

    View Slide

  65. 65
    Example
    JavaCompile
    Java Version
    Source code
    Compiler args
    Class files

    View Slide

  66. 66
    Example
    $hash
    $hash
    $hash
    Java Version
    Source code
    Compiler args

    View Slide

  67. 67
    Example
    $hash
    $hash
    $hash
    CacheKey

    View Slide

  68. 68
    Example
    $hash
    $hash
    $hash
    CacheKey
    ffb08d41a85389bbbe6e8bbe480f0560

    View Slide

  69. Build cache

    View Slide

  70. 70
    Example
    $hash
    $hash
    $hash
    CacheKey
    Build

    cache

    View Slide

  71. 71
    Example
    $hash
    $hash
    $hash
    CacheKey
    Build

    cache

    View Slide

  72. 72
    Example
    $hash
    $hash
    $hash
    CacheKey
    Build

    cache
    JavaCompile
    Class files

    View Slide

  73. Build cache
    Each CacheKey in build-cache

    is a compressed byte-code

    View Slide

  74. Caching
    Local
    In memory In project Out project
    Gradle

    Daemon
    JVM process
    Configuration

    cache
    Incremental

    cache
    Build

    cache

    View Slide

  75. Caching
    Dependency

    cache

    View Slide

  76. Caching
    Dependency

    cache
    * .jars or *.aars

    View Slide

  77. Caching
    Dependency

    cache
    * .jars or *.aars
    ~./gradle/cache/modules-2

    View Slide

  78. Caching
    In memory In project Out project
    Gradle

    Daemon
    JVM process
    Configuration

    cache
    Incremental

    cache
    Build

    cache
    Dependency

    cache

    View Slide

  79. Caching
    Local
    In memory In project Out project
    Gradle

    Daemon
    JVM process
    Configuration

    cache
    Incremental

    cache
    Build

    cache
    Dependency

    cache

    View Slide

  80. Caching
    Local
    In memory In project Out project
    Gradle

    Daemon
    JVM process
    Configuration

    cache
    Incremental

    cache
    Build

    cache
    Dependency

    cache
    Remote

    View Slide

  81. Caching
    Local
    In memory In project Out project
    Gradle

    Daemon
    JVM process
    Configuration

    cache
    Incremental

    cache
    Build

    cache
    Dependency

    cache
    Build

    cache
    Remote

    View Slide

  82. Remote caching
    Build

    cache
    Stores on remote server

    View Slide

  83. Remote caching
    Build

    cache
    Stores on remote server
    Copies to the local cache

    View Slide

  84. Caching
    Local
    In memory In project Out project
    Gradle

    Daemon
    JVM process
    Configuration

    cache
    Incremental

    cache
    Build

    cache
    Dependency

    cache
    Build

    cache
    Remote

    View Slide

  85. Caching
    Local
    In memory In project Out project
    Gradle

    Daemon
    JVM process
    Configuration

    cache
    Incremental

    cache
    Build

    cache
    Dependency

    cache
    Build

    cache
    Proxy
    Remote

    View Slide

  86. Jitpack was down for


    ~2 days
    https://github.com/jitpack/jitpack.io/issues/5337

    View Slide

  87. Remote Caching
    Proxy
    Your own maven

    View Slide

  88. Remote Caching
    Proxy
    Your own maven
    Which syncs data

    View Slide

  89. Caching
    Local
    In memory In project Out project
    Gradle

    Daemon
    JVM process
    Configuration

    cache
    Incremental

    cache
    Build

    cache
    Dependency

    cache
    Build

    cache
    Proxy
    Remote

    View Slide

  90. 90
    Cache:Conslusion

    View Slide

  91. 91
    Incremental applied
    Incremental cache
    Input
    Action

    View Slide

  92. 92
    Incremental applied
    Incremental cache
    Input
    Action
    UP-TO-DATED

    View Slide

  93. 93
    Incremental applied
    Incremental cache
    Input
    Action

    View Slide

  94. 94
    Build cache applied
    Incremental cache
    Input
    Action
    Build Cache
    FROM-CACHE

    View Slide

  95. 95
    No cache
    Incremental cache
    Input
    Action
    Build Cache

    View Slide

  96. 96
    No cache
    Incremental cache
    Input
    Build Cache
    NO LABEL
    Action

    View Slide

  97. 97
    Gradle starter
    Tasks
    Plugins
    Projects
    Build Lifecycle
    Caching
    Properties

    View Slide

  98. 98
    Properties
    File to easily configure Gradle

    View Slide

  99. 99
    Properties
    File to easily configure Gradle
    Can be:
    ~./gradle.properties
    Project/gradle.properties

    View Slide

  100. 100
    Properties
    File to easily configure Gradle
    Can be:
    ~./gradle.properties
    Project/gradle.properties
    Gradle merge them

    View Slide

  101. 101
    Properties
    File to easily configure Gradle
    Can be:
    ~./gradle.properties
    Project/gradle.properties
    Gradle merge them
    Global > Local

    View Slide

  102. 102
    Measure!

    View Slide

  103. 103

    View Slide

  104. 104
    Measure!
    Locally?

    View Slide

  105. 105
    Measure!
    Locally?
    * Manually?
    * Automatically?

    View Slide

  106. 106
    Measure!
    Locally?
    * Manually?
    * Automatically?
    CI?

    View Slide

  107. 107
    Measure!
    Locally?
    * Manually?
    * Automatically?
    CI?
    * Incremental?

    View Slide

  108. 108
    Measure!
    Locally?
    * Manually?
    * Automatically?
    CI?
    * Incremental?
    * Clean build?

    View Slide

  109. 109
    Measure!
    Locally?
    * Manually?
    * Automatically?
    CI?
    * Incremental?
    * Clean build?
    Where to send?

    View Slide

  110. 110
    Measure!
    Locally?
    * Manually?
    * Automatically?
    CI?
    * Incremental?
    * Clean build?
    Where to send?
    HOW???

    View Slide

  111. 111
    1. Locally

    View Slide

  112. 112
    1. Locally
    ~ daily, on a laptop

    View Slide

  113. 113
    1. Locally
    ~ daily, on a laptop
    ~ incremental build

    View Slide

  114. 114
    1. Locally
    ~ daily, on a laptop
    ~ incremental build
    ~ incremental changes

    View Slide

  115. 115
    1. Locally
    ~ daily, on a laptop
    ~ incremental build
    ~ incremental changes
    ~ clean build

    View Slide

  116. 116
    1. Locally
    ~ daily, on a laptop
    ~ incremental build
    ~ incremental changes
    ~ clean build
    ~ configuration

    View Slide

  117. 117
    1. Locally
    ~ daily, on a laptop
    ~ incremental build
    ~ incremental changes
    ~ clean build
    ~ no external monitor
    ~ configuration

    View Slide

  118. 118
    1. Locally
    ~ daily, on a laptop
    ~ incremental build
    ~ incremental changes
    ~ clean build
    ~ no external monitor
    ~ no android studio
    ~ configuration

    View Slide

  119. 119
    1. Locally
    ~ daily, on a laptop
    ~ incremental build
    ~ incremental changes
    ~ clean build
    ~ no external monitor
    ~ no android studio
    ~ cli
    ~ configuration

    View Slide

  120. 120
    Collect automatically

    View Slide

  121. 121
    Collect automatically
    ~ Only if you have > 20 engineers

    View Slide

  122. 122
    Collect automatically
    ~ Only if you have > 20 engineers
    ~ Tool: Talailot
    https://github.com/cdsap/Talaiot

    View Slide

  123. 123
    2. CI

    View Slide

  124. 124
    2. CI
    Do it together with
    local measurement

    View Slide

  125. 125
    3. How?

    View Slide

  126. 126
    3. How?
    ~ Build Scan

    View Slide

  127. 127
    3. How?
    ~ Build Scan
    Most powerful
    Good visualisation
    Shares build outside

    View Slide

  128. 128
    3. How?

    View Slide

  129. 129
    3. How?
    ~ Build Scan
    ~ Gradle profiler

    View Slide

  130. 130
    Gradle profiler
    https://github.com/gradle/gradle-profiler
    ~ brew install gradle-profiler


    View Slide

  131. 131
    Scenario
    no_op {


    tasks = [“assembleDebug"]


    }


    #incremental

    View Slide

  132. 132
    Scenario
    #build cache
    clean_no_op {


    tasks = ["clean", "assembleDebug"]


    }


    no_op {


    tasks = [“assembleDebug"]


    }


    #incremental

    View Slide

  133. 133
    Scenario
    #build cache
    clean_no_op {


    tasks = ["clean", "assembleDebug"]


    }


    no_op {


    tasks = [“assembleDebug"]


    }


    #incremental
    incremental_changes {


    tasks = ["assembleDebug"]


    apply-abi-change-to = “sample/src/main/…TeamsViewModel.kt”


    }

    View Slide

  134. 134
    Scenario
    no_op {


    tasks = [“assembleDebug"]


    }


    clean_no_op {


    tasks = ["clean", "assembleDebug"]


    }


    incremental_changes {


    tasks = ["assembleDebug"]


    apply-abi-change-to = "sample/src/main/java/com/alexbykov/oknetwork/data/TeamsViewModel.kt"


    }
    #incremental
    #build cache
    #incremental changes

    View Slide

  135. 135
    Scenario
    gradle-profiler --benchmark \

    --scenario-file profiler-scenario

    View Slide

  136. 136
    Scenario
    gradle-profiler --benchmark \

    --scenario-file profiler-scenario \
    --measure-config-time

    View Slide

  137. 137
    Output

    View Slide

  138. 138
    CSV

    View Slide

  139. 139
    Configuration time

    View Slide

  140. 140
    After
    ~ Parse it

    View Slide

  141. 141
    After
    ~ Parse it
    ~ Send it to somewhere..

    View Slide

  142. 142
    Somewhere
    ~ Influx db

    View Slide

  143. 143
    Somewhere
    ~ Influx db
    ~ Elastic search

    View Slide

  144. 144
    Somewhere
    ~ Influx db
    ~ Elastic search
    ~ Graphite
    …… or…

    View Slide

  145. 145
    Google sheet

    View Slide

  146. 146
    Google sheet + Forms
    ~ Link sheet with forms

    View Slide

  147. 147
    Google sheet + Forms
    ~ Link sheet with forms
    ~ Know form ids and send
    shorturl.at/mzNOY

    View Slide

  148. 148
    Let’s improve!

    View Slide

  149. 149
    Disable Jetifier

    View Slide

  150. 150
    Disable Jetifier
    ~ appsupport -> androidx

    View Slide

  151. 151
    Disable Jetifier
    ~ appsupport -> androidx
    ~ ./gradlew checkJetifier

    View Slide

  152. 152
    gradle.properties
    android.enableJetifier=false


    View Slide

  153. 153
    Non-Transitive R
    classes

    View Slide

  154. 154
    Problem
    app
    feature1
    Feature3
    feature2

    View Slide

  155. 155
    Problem
    app
    feature1
    Feature3
    feature2
    R class
    R class
    R class
    R class

    View Slide

  156. 156
    Content merging
    app
    feature1
    Feature3
    feature2
    R class (app, f1,f2,f3)
    R class (f2, f3)
    R class (f2, f3)
    R class (f1)

    View Slide

  157. 157
    Non-transitive
    app
    feature1
    Feature3
    feature2 R class (f2)
    R class (f3)
    R class (app)
    R class (f1)

    View Slide

  158. 158
    Non-transitive
    ~ R.strings -> YourModule.R.strings


    ~ All resources


    View Slide

  159. 159
    gradle.properties
    android.nonTransitiveRClass=true


    shorturl.at/gK567

    View Slide

  160. 160
    Virtual file system

    View Slide

  161. 161
    Virtual file system
    shorturl.at/bzIJO
    org.gradle.vfs.watch=true

    View Slide

  162. 162
    Don’t use buildSrc folder

    View Slide

  163. 163
    ~ KTS & Dependency


    Most common use-case

    View Slide

  164. 164
    Problems
    ~ Incremental cache invalidated


    View Slide

  165. 165
    ~ Build cache invalidated


    Problems
    ~ Incremental cache invalidated


    shorturl.at/eruJM
    NO LABEL

    View Slide

  166. 166
    Version Catalog
    shorturl.at/oxY02

    View Slide

  167. 167
    Version Catalog
    ~ No cache issues

    View Slide

  168. 168
    Version Catalog
    ~ No cache issues
    ~ .toml file (can be standalone)

    View Slide

  169. 169
    Version Catalog
    ~ No cache issues
    ~ Bundling dependencies


    ~ .toml file (can be standalone)

    View Slide

  170. 170
    Version Catalog
    [versions]


    groovy = "3.0.5"


    checkstyle = "8.37"

    View Slide

  171. 171
    Version Catalog
    [libraries]


    groovy-core = { module = "org.codehaus.groovy:groovy", version.ref =
    "groovy" }


    groovy-json = { module = "org.codehaus.groovy:groovy-json",
    version.ref = "groovy" }
    [versions]


    groovy = "3.0.5"


    checkstyle = "8.37"

    View Slide

  172. 172
    Bundling
    [bundles]


    groovy = ["groovy-core", "groovy-json", "groovy-
    nio"]


    View Slide

  173. 173
    Bundling
    [bundles]


    groovy = ["groovy-core", "groovy-json", "groovy-nio"]


    implementation libs.groovy

    View Slide

  174. 174
    Focus plugin

    View Slide

  175. 175
    Focus plugin
    shorturl.at/hioEM
    ~ Allows to manage settings.gradle

    View Slide

  176. 176
    Focus plugin
    ~ Allows to manage settings.gradle
    ~ Mostly useful in monorepo
    shorturl.at/hioEM

    View Slide

  177. 177
    Java version

    View Slide

  178. 178
    Java version
    ~ Have Java 8? —> Java 11

    View Slide

  179. 179
    Java version
    ~ Have Java 8? —> Java 11
    ~ Have Java 11 —> A/B tests & experiments

    View Slide

  180. 180
    Tune gradle properties

    View Slide

  181. 181
    Tune gradle properties
    ~ Always do A/B tests with GC
    -XX:+UseParallelGC
    -XX:+UseG1GC (default)

    View Slide

  182. 182
    Tune gradle properties
    ~ Always do A/B tests with GC
    ~ A/B tests with heap size
    org.gradle.jvmargs=-Xmx..G
    kotlin.daemon.jvmargs=-Xmx..g

    View Slide

  183. 183
    Tune gradle properties
    ~ Always do A/B tests with GC
    ~ A/B tests with heap size
    ~ Choose proper one for you
    1. Kotlin daemon > Gradle Daemon
    2. Kotlin daemon < Gradle Daemon
    3. Kotlin daemon == Gradle Daemon

    View Slide

  184. 184
    Some ideas to test
    android.disableAutomaticComponentCreation=true


    android.defaults.buildfeatures.buildconfig=false


    android.defaults.buildfeatures.aidl=false


    android.defaults.buildfeatures.renderscript=false


    android.defaults.buildfeatures.resvalues=false


    android.defaults.buildfeatures.shaders=false

    View Slide

  185. 185
    Never apply new
    properties without
    testing!

    View Slide

  186. 186
    kapt —> KSP

    View Slide

  187. 187
    kapt —> KSP
    ~25%
    No stubs generation

    View Slide

  188. 188
    KSP Support
    ~ Room
    ~ Moshi
    ~ Glide
    ~ Hilt
    ~ Dagger2
    ~ Anvil

    View Slide

  189. 189
    Hilt problem

    View Slide

  190. 190
    Hilt problem
    ~ Works based on subcomponents
    ~ Subcomponents generates

    in parent component

    View Slide

  191. 191
    Modularisation

    View Slide

  192. 192
    Modularisation
    ~ api/impl

    View Slide

  193. 193
    Modularisation
    ~ api/impl
    ~ Restrict merging to app module

    View Slide

  194. 194
    https://github.com/danger/danger
    Danger!

    View Slide

  195. 195
    Parallel

    View Slide

  196. 196
    Parallel
    org.gradle.parallel=true

    View Slide

  197. 197
    Parallel
    org.gradle.parallel=true
    Workers count == CPU cores

    View Slide

  198. 198
    Apply configuration
    cache

    View Slide

  199. 199
    Configuration cache
    org.gradle.unsafe.configuration-cache=true


    org.gradle.unsafe.configuration-cache-problems=warn
    shorturl.at/buUVZ

    View Slide

  200. 200
    Configuration time
    3 minutes
    ~10 seconds
    Before After

    View Slide

  201. 201
    Project isolation (future)

    View Slide

  202. 202
    Project isolation (future)
    shorturl.at/gyJRV
    org.gradle.unsafe.isolated-projects=true

    View Slide

  203. 203
    Build Cache

    View Slide

  204. 204
    Build Cache
    org.gradle.caching=true

    View Slide

  205. 205
    Remote build cache
    shorturl.at/LQT17

    View Slide

  206. 206
    Remote build cache
    Remote Build

    cache
    Local machine
    Mr CI

    View Slide

  207. 207
    Remote build cache
    Remote Build

    cache
    Local machine
    Mr CI
    Read/W
    rite

    View Slide

  208. 208
    Remote build cache
    Remote Build

    cache
    Local machine
    Mr CI
    Read/W
    rite
    Read

    View Slide

  209. Preventing cache misses
    ~ shorturl.at/CMWZ7
    ~ shorturl.at/EMNSU
    ~ shorturl.at/vY389

    View Slide

  210. Build cache—fix plugin
    shorturl.at/ckls3

    View Slide

  211. 211
    Gradle doctor plugin
    shorturl.at/abBOS

    View Slide

  212. 212
    Gradle best practices
    shorturl.at/cjEQX

    View Slide

  213. 213
    Other
    ~ Extract native to libraries
    ~ Don’t use flavors and build variants
    ~ Always test an impact before merging
    ~ Use latest tools
    ~ Keep things under control

    View Slide

  214. 214
    Gradle enterprise
    https://gradle.com/roi-calculator/

    View Slide

  215. 215
    Official guides
    shorturl.at/dfhw2
    shorturl.at/EGKQ4

    View Slide

  216. 216
    Build time with all of this
    ~12 minutes
    ~2 minutes
    Before After

    View Slide

  217. 217
    Learn Gradle
    https://gradle.com/training/
    ~ Trainings:
    https://blog.gradle.org/how-gradle-works-1
    ~ Gradle blog:
    ~ Jendrik Johannes: https://www.youtube.com/@jjohannes

    View Slide

  218. 218
    Slides
    @nonewsss

    View Slide