Slide 1

Slide 1 text

@Sp4ghettiCode - Android Worldwide, July 2021 Sorting and Reporting Your Dependencies with Gradle - Ed George

Slide 2

Slide 2 text

@Sp4ghettiCode • Ed George • Dad to a Pomeranian 🐶 • Senior Android Dev @ ASOS Find me on social: • @Sp4ghettiCode 🍝 • ed-george.github.io Who am I?

Slide 3

Slide 3 text

@Sp4ghettiCode What this talk is/isn’t! • IS a dive into ‘better’ dependency management with Gradle • IS a look into exciting new/upcoming Gradle features • IS my first ever talk 😅🎉 • IS NOT a ‘comprehensive guide’ on Gradle or Kotlin DSL • IS NOT showcasing the only ways to sort / report your dependencies

Slide 4

Slide 4 text

@Sp4ghettiCode What will we learn! The Basics • What a dependency is • How we can define them within Gradle

Slide 5

Slide 5 text

@Sp4ghettiCode What will we learn! Sorting • How to help manage your dependencies when scaling • What the future looks like 🔮

Slide 6

Slide 6 text

@Sp4ghettiCode What will we learn! Reporting • How to keep on top of our dependencies • How to help report your dependencies to others

Slide 7

Slide 7 text

@Sp4ghettiCode What is a dependency?!

Slide 8

Slide 8 text

@Sp4ghettiCode - Any Developer “Reusable code in the form of libraries, modules or components.”

Slide 9

Slide 9 text

@Sp4ghettiCode What is a dependency to an Android developer?!

Slide 10

Slide 10 text

@Sp4ghettiCode What is a dependency? dependencies { implementation 'com.example:library:1.2.3' }

Slide 11

Slide 11 text

@Sp4ghettiCode What is a dependency? dependencies { implementation 'com.example:library:1.2.3' }

Slide 12

Slide 12 text

@Sp4ghettiCode What is a dependency? dependencies { implementation 'com.example:library:1.2.3' }

Slide 13

Slide 13 text

@Sp4ghettiCode What is a dependency? dependencies { implementation 'com.example:library:1.2.3' }

Slide 14

Slide 14 text

@Sp4ghettiCode What is a dependency? dependencies { implementation 'com.example:library:1.2.3' } Group Name Version

Slide 15

Slide 15 text

@Sp4ghettiCode What is a dependency? Example: ‘com.example:library:1.2.3’ Nice shorthand for: group: ‘com.example', name: 'library', version:‘1.2.3’

Slide 16

Slide 16 text

@Sp4ghettiCode What is a dependency? dependencies { implementation project(“:my-module”) implementation files(‘folder/myDependency.jar’) implementation fileTree(dir: 'libs', include: [‘*.jar']) }

Slide 17

Slide 17 text

@Sp4ghettiCode The common problems we face • Versioning inconsistencies • Non-centralised dependencies • Moving to a modular codebase • Out-of-date dependencies (and the ones I hope to help you fix)

Slide 18

Slide 18 text

@Sp4ghettiCode The common problems we face • Versioning inconsistencies • Non-centralised dependencies • Moving to a modular codebase • Out-of-date dependencies (and the ones I hope to help you fix)

Slide 19

Slide 19 text

@Sp4ghettiCode Versioning inconsistencies dependencies { implementation ‘com.example:foo:1.2.3' implementation ‘com.example:bar:1.2.3' implementation ‘com.example:baz:1.2.3' implementation ‘com.example:etc:1.2.3’ … etc }

Slide 20

Slide 20 text

@Sp4ghettiCode Versioning inconsistencies dependencies { implementation ‘com.example:foo:1.2.3' implementation ‘com.example:bar:1.2.3' implementation ‘com.example:baz:1.2.3' implementation ‘com.example:etc:1.2.3' }

Slide 21

Slide 21 text

@Sp4ghettiCode The humble extra properties block ext { libVersion = ‘1.2.3’ } dependencies { implementation “com.example:foo:$libVersion” implementation “com.example:bar:$libVersion” implementation “com.example:baz:$libVersion” implementation “com.example:etc:$libVersion” }

Slide 22

Slide 22 text

@Sp4ghettiCode The humble extra properties block ext { libVersion = ‘1.2.3’ } dependencies { implementation “com.example:foo:$libVersion” implementation “com.example:bar:$libVersion” implementation “com.example:baz:$libVersion” implementation “com.example:etc:$libVersion” }

Slide 23

Slide 23 text

@Sp4ghettiCode The humble extra properties block ext { libVersion = ‘1.2.3’ } dependencies { implementation “com.example:foo:$libVersion” implementation “com.example:bar:$libVersion” implementation “com.example:baz:$libVersion” implementation “com.example:etc:$libVersion” }

Slide 24

Slide 24 text

@Sp4ghettiCode Bill of Materials dependencies { implementation platform('com.google.firebase:firebase-bom:28.3.0') No more need for explicit versions! implementation 'com.google.firebase:firebase-auth' implementation 'com.google.firebase:firebase-firestore' }

Slide 25

Slide 25 text

@Sp4ghettiCode Bill of Materials BOMs readily available for: • Firebase • Kotlin • OkHTTP • Jackson • JUnit 5 • Not much else for Android (yet) 😢

Slide 26

Slide 26 text

@Sp4ghettiCode The common problems we face • Versioning inconsistencies • Non-centralised dependencies • Moving to a modular codebase • Out-of-date dependencies (and the ones I hope to help you fix)

Slide 27

Slide 27 text

@Sp4ghettiCode Mandatory Disclaimer: There’s 1000s of ways to do this! (But this is my favourite so far) ⚠

Slide 28

Slide 28 text

@Sp4ghettiCode Creating a versions.gradle Part 1 // In Groovy, [:] refers to an empty map ext.deps = [:]

Slide 29

Slide 29 text

@Sp4ghettiCode Creating a versions.gradle Part 1 ext.deps = [:] def versions = [:] def dependencies = [:]

Slide 30

Slide 30 text

@Sp4ghettiCode Creating a versions.gradle Part 1 def androidx_version = [:] androidx_version.appcompat = '1.0.2' versions.androidx = androidx_version def androidx_deps = [:] androidx_deps.appcompat = "androidx.appcompat:appcompat:$versions.androidx.appcompat" dependencies.androidx = androidx_deps … ext.deps = dependencies ext.versions = versions

Slide 31

Slide 31 text

@Sp4ghettiCode Creating a versions.gradle Part 1 apply from: "$rootProject.rootDir/versions.gradle" dependencies { implementation deps.androidx.appcompat implementation deps.androidx.ktx_core … } app/build.gradle

Slide 32

Slide 32 text

@Sp4ghettiCode But what if I want to import all the dependencies for X?

Slide 33

Slide 33 text

@Sp4ghettiCode Creating a versions.gradle Part 2 def Group(Closure closure) { closure.delegate = dependencies return closure } delegate refers to a third-party object where methods calls & properties are resolved versions.gradle

Slide 34

Slide 34 text

@Sp4ghettiCode Creating a versions.gradle Part 2 ext { androidx = Group { // Previously defined deps implementation deps.androidx.appcompat implementation deps.androidx.ktx_core implementation deps.androidx.ktx_fragment … } … } versions.gradle

Slide 35

Slide 35 text

@Sp4ghettiCode Creating a versions.gradle Part 2 ext { androidx = Group { implementation deps.androidx.appcompat … } kotlin = Group { implementation deps.kotlin.core … } … } dependencies { androidx() kotlin() … } versions.gradle app/build.gradle

Slide 36

Slide 36 text

@Sp4ghettiCode Version Catalogs 🆕 Available from Gradle 7.0+ (April 2021) • Provides centralised dependency configuration • Generates type-safe accessors • Requires VERSION_CATALOGS feature preview to be enabled

Slide 37

Slide 37 text

@Sp4ghettiCode Version Catalogs - Gradle dependencyResolutionManagement { versionCatalogs { libs { version('okHttp', ‘4.9.1’) alias(‘okhttp-core’).to(‘com.squareup.okhttp3’, ‘okhttp').versionRef('okHttp') } } } settings.gradle app/build.gradle dependencies { implementation libs.okhttp.core }

Slide 38

Slide 38 text

@Sp4ghettiCode Version Catalogs - TOML [versions] okhttp = “4.9.1” [libraries] okhttp-core = { module = “com.squareup.okhttp3:okhttp”, version.ref = "okhttp" } gradle/libs.versions.toml app/build.gradle dependencies { implementation libs.okhttp.core }

Slide 39

Slide 39 text

@Sp4ghettiCode Version Catalogs - Bundles [versions] okhttp = “4.9.1” [libraries] okhttp-core = { module = “com.squareup.okhttp3:okhttp”, version.ref = "okhttp" } okhttp-ws = { module = “com.squareup.okhttp3:okhttp-ws“, version.ref = “okhttp" } [bundles] okhttp = ["okhttp-core", “okhttp-ws"] gradle/libs.versions.toml app/build.gradle dependencies { implementation libs.bundles.okhttp }

Slide 40

Slide 40 text

@Sp4ghettiCode The common problems we face • Versioning inconsistencies • Non-centralised dependencies • Moving to a modular codebase • Out-of-date dependencies (and the ones I hope to help you fix)

Slide 41

Slide 41 text

@Sp4ghettiCode Story Time 📚

Slide 42

Slide 42 text

@Sp4ghettiCode - A Project Manager “I need you to present the app’s outdated dependencies and their latest version available”

Slide 43

Slide 43 text

@Sp4ghettiCode - A Project Manager “…in a way the client can understand.”

Slide 44

Slide 44 text

@Sp4ghettiCode Basic Reporting ./gradlew :module:dependencies • Outputs the dependencies used for all configurations • Shows dependency versions • Tree view

Slide 45

Slide 45 text

@Sp4ghettiCode Basic Reporting debugAndroidTestCompileClasspath +--- androidx.test.ext:junit:1.1.2 | +--- junit:junit:4.12 | | \--- org.hamcrest:hamcrest-core:1.3 | +--- androidx.test:core:1.3.0 | | +--- androidx.annotation:annotation:1.0.0 -> 1.2.0 | | +--- androidx.test:monitor:1.3.0 | | | \--- androidx.annotation:annotation:1.0.0 -> 1.2.0 | | \--- androidx.lifecycle:lifecycle-common:2.0.0 -> 2.3.1 | | \--- androidx.annotation:annotation:1.1.0 -> 1.2.0 | +--- androidx.test:monitor:1.3.0 (*) | \--- androidx.annotation:annotation:1.0.0 -> 1.2.0 | … ./gradlew :module:dependencies

Slide 46

Slide 46 text

@Sp4ghettiCode Basic Reporting debugAndroidTestCompileClasspath +--- androidx.test.ext:junit:1.1.2 | +--- junit:junit:4.12 | | \--- org.hamcrest:hamcrest-core:1.3 | +--- androidx.test:core:1.3.0 | | +--- androidx.annotation:annotation:1.0.0 -> 1.2.0 | | +--- androidx.test:monitor:1.3.0 | | | \--- androidx.annotation:annotation:1.0.0 -> 1.2.0 | | \--- androidx.lifecycle:lifecycle-common:2.0.0 -> 2.3.1 | | \--- androidx.annotation:annotation:1.1.0 -> 1.2.0 | +--- androidx.test:monitor:1.3.0 (*) | \--- androidx.annotation:annotation:1.0.0 -> 1.2.0 | … ./gradlew :module:dependencies

Slide 47

Slide 47 text

@Sp4ghettiCode Basic Reporting ./gradlew :module:dependencies --scan

Slide 48

Slide 48 text

@Sp4ghettiCode Dependency Insight Report ./gradlew :module:dependencyInsight --configuration myConf --dependency myDep • Gives further diagnostics on how a dependency is used • Shows dependency version constraints • Requires configuration and dependency flags

Slide 49

Slide 49 text

@Sp4ghettiCode Dependency Insight Report ./gradlew :app:dependencyInsight --configuration debugCompileClasspath --dependency core-ktx

Slide 50

Slide 50 text

@Sp4ghettiCode Dependency Insight Report implementation ('com.example:library:1.+') { because ‘we cannot migrate to v2 because…’ }

Slide 51

Slide 51 text

@Sp4ghettiCode Dependency Insight Report ./gradlew :app:dependencyInsight --configuration debugCompileClasspath --dependency core-ktx

Slide 52

Slide 52 text

@Sp4ghettiCode - A now slightly frustrated Project Manager “…in a way the client can understand.”

Slide 53

Slide 53 text

@Sp4ghettiCode Gradle Version Plugin github.com/ben-manes/gradle-versions-plugin • Generates a Gradle task ‘dependencyUpdates’ • Displays a report of the project dependencies that are up-to-date / out-of-date • ‘Default’ reports in HTML, XML and JSON • Allows for custom reporting 👀

Slide 54

Slide 54 text

@Sp4ghettiCode Example Output The following dependencies have later milestone versions: - androidx.appcompat:appcompat [1.0.2 -> 1.3.0-alpha01] https://developer.android.com/jetpack/androidx - androidx.core:core-ktx [1.0.2 -> 1.5.0-alpha01] https://developer.android.com/jetpack/androidx [...] 
 ./gradlew dependencyUpdates

Slide 55

Slide 55 text

@Sp4ghettiCode (With Groovy’s HTML Builder) • DSL Style • Can be used to generate custom HTML page to report dependencies • Beginner Friendly! Custom Reporting

Slide 56

Slide 56 text

@Sp4ghettiCode 😅 My first attempt… Example available @ ed-george.github.io/talks

Slide 57

Slide 57 text

@Sp4ghettiCode 😅 My second attempt… (with Bootstrap)

Slide 58

Slide 58 text

@Sp4ghettiCode The common problems we face • Versioning inconsistencies • Non-centralised dependencies • Moving to a modular codebase • Out-of-date dependencies (and the ones I hope to help you fix)

Slide 59

Slide 59 text

@Sp4ghettiCode TL;DR • When possible, centralise + generalise your dependencies • Consider Version Catalogs in future • Use dependency insight tasks for more info • Reporting can be made easier using Gradle Version Plugin

Slide 60

Slide 60 text

@Sp4ghettiCode Thanks for watching! • Find me on Twitter @Sp4ghettiCode • More resources and links at ed-george.github.io/talks • Please do reach out if you have any cool ways of managing dependencies • Questions and Answers to follow…

Slide 61

Slide 61 text

@Sp4ghettiCode EOF