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

Gradle, je t’aime: moi non plus.

David
April 19, 2019

Gradle, je t’aime: moi non plus.

Un outil de build de qualité est essentiel dans un projet IT. On attend de lui qu’il soit rapide, facile à configurer et qu’il se fasse oublier le reste du temps. Même si l’écosystème Java utilise encore fortement Maven, Gradle est une alternative à considérer, particulièrement avec les dernières fonctionnalités apportées.

Pourquoi avoir choisi Gradle ? Quelles sont les fonctionnalités de l’outil qui nous satisfont le plus ? Quelles sont nos bonnes pratiques ? Quelles sont les problèmes que nous avons rencontrés ? Comment nos builds sont maintenant organisés avec cet outil ?

Cette session répondra à ces questions et vous aidera à choisir votre prochain outil de build.

Devoxx France 2019 - 19 Avril 2019

David

April 19, 2019
Tweet

More Decks by David

Other Decks in Programming

Transcript

  1. Gradle, je t’aime, 

    … moi non plus
    @JeremMartinez - @dwursteisen

    View Slide

  2. View Slide

  3. David Wursteisen
    Jeremie Martinez

    View Slide

  4. Satisfait de
    votre banque ?

    View Slide

  5. Une banque
    pour entreprise

    View Slide

  6. Nous construisons notre propre
    CBS.

    View Slide

  7. Nous construisons notre propre
    Core Banking System.

    View Slide

  8. Data
    Payments
    Backend
    Core

    View Slide

  9. Data
    Payments
    Backend
    Core
    Created
    Deposited
    Withdraw
    Withdraw
    Closed
    WRITE
    Event store
    Reporting
    Accounting
    Regulators
    Data sciences
    GDPR
    Users
    Transfers
    Customers
    Collections
    Cards
    KYC
    Limit controller

    View Slide

  10. Un outil de build est comme une
    banque. On ne choisit pas le meilleur
    mais le moins pire.
    Un outil de build est comme une
    banque. On ne choisit pas le meilleur
    mais le moins pire.

    View Slide

  11. Choix de l’outil de build : 2017
    Choix de l’outil de build : 2017

    View Slide

  12. Bazel Buck

    View Slide

  13. Construction
    incrementale
    DSL en Groovy
    Dynamisme
    du produit

    View Slide

  14. Système à base de tâche.

    View Slide

  15. Tâche
    Entrée Sortie

    View Slide

  16. Assemble

    View Slide

  17. Jar Assemble

    View Slide

  18. Compile Jar Assemble

    View Slide

  19. Compile Jar Assemble

    View Slide

  20. Compile Jar Assemble
    Compile
    [ Up-to-date ] [ Up-to-date ] [ Up-to-date ]
    Jar Assemble

    View Slide

  21. On ne construit que le
    nécessaire.
    On ne construit que le
    nécessaire.

    View Slide

  22. Développeur
    Mainteneur de scripts
    Build master
    1
    2
    3

    View Slide

  23. Développeur
    Mainteneur de scripts
    Build master
    1

    View Slide

  24. Support IDE.

    View Slide

  25. View Slide

  26. View Slide

  27. View Slide

  28. View Slide

  29. View Slide

  30. Gradle Wrapper.

    View Slide

  31. View Slide

  32. distributionBase=GRADLE_USER_HOME
    distributionPath=wrapper/dists
    zipStoreBase=GRADLE_USER_HOME
    zipStorePath=wrapper/dists
    distributionUrl=https://services.gradle.org/distributions/gradle-5.3-bin.zip

    View Slide

  33. distributionBase=GRADLE_USER_HOME
    distributionPath=wrapper/dists
    zipStoreBase=GRADLE_USER_HOME
    zipStorePath=wrapper/dists
    distributionUrl=https://services.gradle.org/distributions/gradle-5.3-bin.zip

    View Slide

  34. distributionBase=GRADLE_USER_HOME
    distributionPath=wrapper/dists
    zipStoreBase=GRADLE_USER_HOME
    zipStorePath=wrapper/dists
    distributionUrl=https://internal/gradle/gradle/gradle/5.3/gradle-5.3-bin.zip

    View Slide

  35. distributionBase=GRADLE_USER_HOME
    distributionPath=wrapper/dists
    zipStoreBase=GRADLE_USER_HOME
    zipStorePath=wrapper/dists
    distributionUrl=https://internal/gradle/gradle/gradle/5.3/gradle-5.3-bin.zip
    distributionSha256Sum=53b71812f18cdb2777e9f1b2a0f2038683907c90bdc406bc6

    View Slide

  36. distributionBase=GRADLE_USER_HOME
    distributionPath=wrapper/dists
    zipStoreBase=GRADLE_USER_HOME
    zipStorePath=wrapper/dists
    distributionUrl=https://internal/gradle/gradle/gradle/5.3/gradle-5.3-bin.zip
    distributionSha256Sum=53b71812f18cdb2777e9f1b2a0f2038683907c90bdc406bc6

    View Slide

  37. distributionhttps://internal/gradle/gradle/gradle/5.3/gradle-5.3-bin.zip
    distributionSha256Sum=53b71812f18cdb2777e9f1b2a0f2038683907c90bdc406bc6
    Ne sont pas des variables
    d’environment valides !

    View Slide

  38. View Slide

  39. 4 Go =

    View Slide

  40. Gestion des dépendances

    View Slide

  41. src
    main
    module
    kotlin
    test
    kotlin
    resources
    custom
    kotlin

    View Slide

  42. dependencies {
    }

    View Slide

  43. dependencies {
    compile("io.swagger:swagger-annotations:1.5.0")
    }

    View Slide

  44. dependencies {
    compile("io.swagger:swagger-annotations:1.5.0")
    compile(group = "io.swagger", name = "swagger-annotations", version = "1.5.0")
    }

    View Slide

  45. dependencies {
    compile("io.swagger:swagger-annotations:1.5.0")
    compile(group = "io.swagger", name = "swagger-annotations", version = "1.5.0")
    compile(project(":otherProject"))
    }

    View Slide

  46. dependencies {
    compile("io.swagger:swagger-annotations:1.5.0")
    compile(group = "io.swagger", name = "swagger-annotations", version = "1.5.0")
    compile(project(":otherProject"))
    testCompile("io.mockk:mockk:1.9.3")
    }

    View Slide

  47. dependencies {
    compile("io.swagger:swagger-annotations:1.5.0")
    compile(group = "io.swagger", name = "swagger-annotations", version = "1.5.0")
    compile(project(":otherProject"))
    testCompile("io.mockk:mockk:1.9.3")
    customCompile("org.codehaus.janino:janino:2.5.16")
    }

    View Slide

  48. customCompile("org.codehaus.janino:janino:2.5.16")
    sourceSet
    configuration

    View Slide

  49. compile("org.codehaus.janino:janino:2.5.16")
    compileOnly("org.codehaus.janino:janino:2.5.16")
    runtime("org.codehaus.janino:janino:2.5.16")
    annotationProcessor("org.codehaus.janino:janino:2.5.16")

    View Slide

  50. compile("org.codehaus.janino:janino:2.5.16")
    compileOnly("org.codehaus.janino:janino:2.5.16")
    runtime("org.codehaus.janino:janino:2.5.16")
    annotationProcessor("org.codehaus.janino:janino:2.5.16")

    View Slide

  51. compile("org.codehaus.janino:janino:2.5.16")
    compileOnly("org.codehaus.janino:janino:2.5.16")
    runtime("org.codehaus.janino:janino:2.5.16")
    annotationProcessor("org.codehaus.janino:janino:2.5.16")
    runtimeOnly("org.codehaus.janino:janino:2.5.16")
    api("org.codehaus.janino:janino:2.5.16")
    implementation("org.codehaus.janino:janino:2.5.16")

    View Slide

  52. runtimeOnly("org.codehaus.janino:janino:2.5.16")
    api("org.codehaus.janino:janino:2.5.16")
    implementation("org.codehaus.janino:janino:2.5.16")

    View Slide

  53. mailer-service
    mailer-api amazing-mail
    com.lib.mailer.api
    com.lib.mailer.impl
    MailerService
    MailerApi
    webapp
    fr.amazing.client
    ClientMail

    View Slide

  54. mailer-service
    mailer-api amazing-mail
    com.lib.mailer.api
    com.lib.mailer.impl
    MailerService
    MailerApi
    webapp
    fr.amazing.client
    ClientMail
    compilation
    compilation
    compilation
    est visible
    est visible
    implementation
    implementation
    api

    View Slide

  55. Repositories.

    View Slide

  56. repositories {
    }

    View Slide

  57. repositories {
    mavenCentral()
    }

    View Slide

  58. repositories {
    mavenCentral()
    jcenter()
    google()
    }

    View Slide

  59. repositories {
    mavenCentral()
    jcenter()
    google()
    maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/") }
    }

    View Slide

  60. repositories {
    mavenCentral()
    jcenter()
    google()
    maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/") }
    maven {
    url = uri("https://internal")
    content {
    includeGroupByRegex("com\\.mycompany.*")
    }
    }
    }
    Selection des
    dépendances

    View Slide

  61. repositories {
    mavenCentral()
    jcenter()
    google()
    maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/") }
    maven {
    url = uri("https://internal")
    content {
    includeGroupByRegex("com\\.mycompany.*")
    }
    }
    ivy { url = uri("https://oss.sonatype.org/content/repositories/releases/") }
    flatDir { dirs("libs") }
    }

    View Slide

  62. repositories {
    mavenCentral()
    jcenter()
    google()
    maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/") }
    maven {
    url = uri("https://internal")
    content {
    includeGroupByRegex("com\\.mycompany.*")
    }
    }
    ivy { url = uri("https://oss.sonatype.org/content/repositories/releases/") }
    flatDir { dirs("libs") }
    mavenLocal()
    }
    Devrait être inutile

    View Slide

  63. projectA projectB
    mavenLocal
    publishToMavenLocal
    Dépend de…

    View Slide

  64. Composite Build.

    View Slide

  65. projectA projectB
    compositeBuild
    includeBuild(…)

    View Slide

  66. projectA projectB
    dependencySource
    gitRepository(https://github.com/…)
    version = branch/tag

    View Slide

  67. mailer 1.0.0 Master dev/feature
    superProject
    otherProject
    projectZ

    View Slide

  68. mailer 1.0.0 Master dev/feature
    superProject OK
    otherProject OK
    projectZ OK

    View Slide

  69. mailer 1.0.0 master
    superProject OK OK
    otherProject OK OK
    projectZ OK KO
    Dependency sources

    View Slide

  70. mailer 1.0.0 master dev/feature
    superProject OK OK KO
    otherProject OK OK OK
    projectZ OK KO OK
    Dependency sources Dependency sources

    View Slide

  71. Performance.

    View Slide

  72. View Slide

  73. org.gradle.caching=true
    org.gradle.configureondemand=true
    org.gradle.jvmargs=-Xmx2048M -Xms2048M
    org.gradle.parallel=true
    Réutilisation des résultats de build
    Execution des tâches en parallèle
    Utilisation d’un maximum de mémoire
    Configuration uniquement des
    tâches nécessaires

    View Slide

  74. View Slide

  75. Daemon Gradle 5.1.1
    Daemon Gradle 4.10

    View Slide

  76. View Slide

  77. View Slide

  78. Simplicité
    d’utilisation
    Performance
    Fonctionnalités

    View Slide

  79. Développeur
    Mainteneur de scripts
    Build master
    2

    View Slide

  80. Data
    Payments
    Backend
    Core
    Created
    Deposited
    Withdraw
    Withdraw
    Closed
    WRITE
    Event store
    Reporting
    Accounting
    Regulators
    Data sciences
    GDPR
    Users
    Transfers
    Customers
    Collections
    Cards
    KYC
    Limit controller

    View Slide

  81. Data
    Payments Backend
    Reporting
    Accounting
    Regulators
    Data sciences
    GDPR
    Users
    Transfers
    Customers
    Collections
    Cards
    KYC
    Limit controller

    View Slide

  82. Backend
    GDPR
    Users
    Customers
    KYC
    Limit controller
    kotlin
    nexus
    release
    lint
    Configuration

    View Slide

  83. Plugin interne.

    View Slide

  84. apply(plugin = "com.your.company.commons")

    View Slide

  85. View Slide

  86. Configurer une seule fois,
    Exécuter partout.

    View Slide

  87. buildSrc.

    View Slide

  88. View Slide

  89. View Slide

  90. View Slide

  91. View Slide

  92. src
    main
    buildSrc
    kotlin
    myProject

    View Slide

  93. open class MyExtension(var yourName: String = "not defined!")

    View Slide

  94. open class MyExtension(var yourName: String = "not defined!")
    class MyPlugin : Plugin {
    override fun apply(project: Project) {
    }
    }

    View Slide

  95. open class MyExtension(var yourName: String = "not defined!")
    class MyPlugin : Plugin {
    override fun apply(project: Project) {
    val exts = project.extensions.create("myPlugin", MyExtension::class)
    }
    }

    View Slide

  96. open class MyExtension(var yourName: String = "not defined!")
    class MyPlugin : Plugin {
    override fun apply(project: Project) {
    val exts = project.extensions.create("myPlugin", MyExtension::class)
    project.task("myTask") {
    doLast {
    println("hello ${exts.yourName}")
    }
    }
    }
    }

    View Slide

  97. apply()
    configure {
    yourName = "Devoxx France"
    }

    View Slide

  98. View Slide

  99. DSL.

    View Slide

  100. Groovy DSL.

    View Slide

  101. sourceSets {
    }
    Groovy

    View Slide

  102. sourceSets {
    integrationTest {
    }
    }
    DSL Dynamique
    Groovy

    View Slide

  103. View Slide

  104. Type
    safety
    IDE Support
    Navigation
    Refactoring

    View Slide

  105. sourceSets {
    integrationTest {
    }
    }
    Groovy

    View Slide

  106. sourceSets.create("integrationTest") {

    }
    Kotlin

    View Slide

  107. View Slide

  108. View Slide

  109. View Slide

  110. idea {
    project {
    settings {
    runConfigurations {
    "Start Application"(Application) {
    // …
    }
    }
    }
    }
    }
    Groovy

    View Slide

  111. idea {
    project {
    this as ExtensionAware
    configure {
    this as ExtensionAware
    configure> {
    // cast to PolymorphicDomainObjectContainer to access the create method used bellow.
    @Suppress("UnstableApiUsage")
    this as PolymorphicDomainObjectContainer
    create("Start Application", Application::class) {
    // …
    }
    }
    }
    }
    }



    Kotlin

    View Slide

  112. « Un langage pour
    les gouverner tous. »

    View Slide

  113. Migration vers Kotlin DSL.

    View Slide

  114. object Versions {
    val assertj = "3.10.0"
    val junit = "4.12"
    val mockito = "2.19.1"
    val mockito_kotlin = "1.6.0"
    val postgres = "42.2.4"
    val prometheus = "0.6.0"
    val springboot = "2.1.3.RELEASE"
    val swagger = "1.5.20"
    }

    View Slide

  115. object TestDeps {
    val assertj = "org.assertj:assertj-core:${Versions.assertj}"
    val junit = "junit:junit:${Versions.junit}"
    val mockito = "org.mockito:mockito-core:${Versions.mockito}"
    }

    View Slide

  116. dependencies {
    testImplementation(TestDeps.assertj)
    testImplementation(TestDeps.junit)
    testImplementation(TestDeps.mockito)
    }

    View Slide

  117. 1. Doublez vos quotes.

    View Slide

  118. allprojects {
    group = 'com.margo.backend'
    version = '1.0'
    }
    Groovy

    View Slide

  119. allprojects {
    group = 'com.margo.backend'
    version = '1.0'
    }
    Groovy

    View Slide

  120. allprojects {
    group = "com.margo.backend"
    version = "1.0"
    }
    Kotlin

    View Slide

  121. 2. Explicitez vos assignations.

    View Slide

  122. repositories {
    maven { url 'https://plugins.gradle.org/m2/' }
    }
    Groovy

    View Slide

  123. repositories {
    maven { url = uri("https://plugins.gradle.org/m2/") }
    }
    Kotlin

    View Slide

  124. dependencies {
    compile project(":service")
    }
    Groovy

    View Slide

  125. dependencies {
    compile(project(":service"))
    }
    Kotlin

    View Slide

  126. val commit by extra { Git.commit() }
    Kotlin

    View Slide

  127. object Git {
    fun commit() = Runtime.getRuntime()
    .exec("git rev-parse --short HEAD")
    .inputStream.bufferedReader()
    .readText()
    }
    buildSrc

    View Slide

  128. 3. Fichier par fichier.

    View Slide

  129. web
    buildSrc
    src
    build.gradle
    settings.gradle
    build.gradle
    src
    build.gradle

    View Slide

  130. build.gradle.kts
    web
    buildSrc
    src
    settings.gradle
    build.gradle
    src
    build.gradle

    View Slide

  131. settings.gradle.kts
    build.gradle.kts
    web
    buildSrc
    src
    build.gradle
    src
    build.gradle

    View Slide

  132. build.gradle.kts
    settings.gradle.kts
    build.gradle.kts
    web
    buildSrc
    src
    src
    build.gradle

    View Slide

  133. web
    buildSrc
    src
    build.gradle.kts
    settings.gradle.kts
    build.gradle.kts
    src
    build.gradle.kts

    View Slide

  134. Quelques difficultés.

    View Slide

  135. 1. Documentation.

    View Slide

  136. View Slide

  137. 2. Exemples.

    View Slide

  138. View Slide

  139. View Slide

  140. 3. Utilisation avancée.

    View Slide

  141. processResources {
    filesMatching('**/*.properties') {
    expand(project.properties)
    }
    }
    Groovy

    View Slide

  142. tasks
    .withType(ProcessResources::class)
    .named("processResources")
    .configure {
    filesMatching("**/*.properties") {
    expand(project.properties)
    }
    }
    Kotlin

    View Slide

  143. tasks
    .withType(ProcessResources::class)
    .named("processResources")
    .configure {
    filesMatching("**/*.properties") {
    expand(project.properties)
    }
    }
    Kotlin

    View Slide

  144. tasks
    .withType(ProcessResources::class)
    .named("processResources")
    .configure {
    filesMatching("**/*.properties") {
    expand(project.properties)
    }
    }
    Kotlin

    View Slide

  145. tasks
    .withType(ProcessResources::class)
    .named("processResources")
    .configure {
    filesMatching("**/*.properties") {
    expand(project.properties)
    }
    }
    Kotlin

    View Slide

  146. tasks
    .withType(ProcessResources::class)
    .named("processResources")
    .configure {
    filesMatching("**/*.properties") {
    expand(project.properties)
    }
    }
    Kotlin

    View Slide

  147. tasks
    .withType(ProcessResources::class)
    .named("processResources")
    .configure {
    filesMatching("**/*.properties") {
    expand(project.properties)
    }
    }
    Kotlin

    View Slide

  148. 4. Migration du plugin interne.

    View Slide

  149. Si c’était à refaire ?

    View Slide

  150. buildSrc
    Performance Plugin interne
    IDE Support

    View Slide

  151. Prochaines étapes.
    Consommation
    mémoire
    Build cache

    View Slide

  152. Questions ?

    View Slide