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

Sorting and Reporting Your Dependencies with Gradle

Sorting and Reporting Your Dependencies with Gradle

All apps have dependencies, but what is the best way to manage and keep on top of them? This session takes a look at some simple steps, tools, and tricks to use Gradle to help us make dependency management far easier.

Starting with simple Gradle language features, we will also explore how to handle dependencies within more complex projects, dive into some useful Gradle plugins, and finally look into what the future of dependency management within Android may be.

This talk was part of Android Worldwide, July 27 2021

Ed George

July 27, 2021
Tweet

More Decks by Ed George

Other Decks in Technology

Transcript

  1. @Sp4ghettiCode - Android Worldwide, July 2021 Sorting and Reporting Your

    Dependencies with Gradle - Ed George
  2. @Sp4ghettiCode • Ed George • Dad to a Pomeranian 🐶

    • Senior Android Dev @ ASOS Find me on social: • @Sp4ghettiCode 🍝 • ed-george.github.io Who am I?
  3. @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
  4. @Sp4ghettiCode What will we learn! The Basics • What a

    dependency is • How we can define them within Gradle
  5. @Sp4ghettiCode What will we learn! Sorting • How to help

    manage your dependencies when scaling • What the future looks like 🔮
  6. @Sp4ghettiCode What will we learn! Reporting • How to keep

    on top of our dependencies • How to help report your dependencies to others
  7. @Sp4ghettiCode What is a dependency?!

  8. @Sp4ghettiCode - Any Developer “Reusable code in the form of

    libraries, modules or components.”
  9. @Sp4ghettiCode What is a dependency to an Android developer?!

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

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

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

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

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

    Group Name Version
  15. @Sp4ghettiCode What is a dependency? Example: ‘com.example:library:1.2.3’ Nice shorthand for:

    group: ‘com.example', name: 'library', version:‘1.2.3’
  16. @Sp4ghettiCode What is a dependency? dependencies { implementation project(“:my-module”) implementation

    files(‘folder/myDependency.jar’) implementation fileTree(dir: 'libs', include: [‘*.jar']) }
  17. @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)
  18. @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)
  19. @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 }
  20. @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' }
  21. @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” }
  22. @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” }
  23. @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” }
  24. @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' }
  25. @Sp4ghettiCode Bill of Materials BOMs readily available for: • Firebase

    • Kotlin • OkHTTP • Jackson • JUnit 5 • Not much else for Android (yet) 😢
  26. @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)
  27. @Sp4ghettiCode Mandatory Disclaimer: There’s 1000s of ways to do this!

    (But this is my favourite so far) ⚠
  28. @Sp4ghettiCode Creating a versions.gradle Part 1 // In Groovy, [:]

    refers to an empty map ext.deps = [:]
  29. @Sp4ghettiCode Creating a versions.gradle Part 1 ext.deps = [:] def

    versions = [:] def dependencies = [:]
  30. @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
  31. @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
  32. @Sp4ghettiCode But what if I want to import all the

    dependencies for X?
  33. @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
  34. @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
  35. @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
  36. @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
  37. @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 }
  38. @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 }
  39. @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 }
  40. @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)
  41. @Sp4ghettiCode Story Time 📚

  42. @Sp4ghettiCode - A Project Manager “I need you to present

    the app’s outdated dependencies and their latest version available”
  43. @Sp4ghettiCode - A Project Manager “…in a way the client

    can understand.”
  44. @Sp4ghettiCode Basic Reporting ./gradlew :module:dependencies • Outputs the dependencies used

    for all configurations • Shows dependency versions • Tree view
  45. @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
  46. @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
  47. @Sp4ghettiCode Basic Reporting ./gradlew :module:dependencies --scan

  48. @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
  49. @Sp4ghettiCode Dependency Insight Report ./gradlew :app:dependencyInsight --configuration debugCompileClasspath --dependency core-ktx

  50. @Sp4ghettiCode Dependency Insight Report implementation ('com.example:library:1.+') { because ‘we cannot

    migrate to v2 because…’ }
  51. @Sp4ghettiCode Dependency Insight Report ./gradlew :app:dependencyInsight --configuration debugCompileClasspath --dependency core-ktx

  52. @Sp4ghettiCode - A now slightly frustrated Project Manager “…in a

    way the client can understand.”
  53. @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 👀
  54. @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
  55. @Sp4ghettiCode (With Groovy’s HTML Builder) • DSL Style • Can

    be used to generate custom HTML page to report dependencies • Beginner Friendly! Custom Reporting
  56. @Sp4ghettiCode 😅 My first attempt… Example available @ ed-george.github.io/talks

  57. @Sp4ghettiCode 😅 My second attempt… (with Bootstrap)

  58. @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)
  59. @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
  60. @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…
  61. @Sp4ghettiCode EOF