Hinter der Magie von Gradle und Kotlin

KKON Warm-up 2021 / Jendrik Johannes, Gradle

What is Gradle?

  • Gradle Build Tool

    • Open Source (APL)

    • for Java, Groovy, Kotlin, Scala, …​

    • Developed by Gradle GmbH/Inc. with many community contributions

What is Gradle?

  • Gradle Enterprise

    • Works with multiple Built Tools: Gradle Build Tool, Maven, …​

    • Build Insights, Caching, Performance Analysis, Flaky Test Detection, …​

    • Developed by Gradle GmbH/Inc.

  • Public Build Scans for Gradle builds: scans.gradle.com

What’s special about Gradle Build Tool?

  • Can be used to write imperative scripts

    • like Ant, but with a proper programming language

  • Can be used to model your software

    • like Maven, but with a richer and more extensible model

  • Many Gradle builds today are a mix of both

    • Its strength is its weakness: spaghetti code build scripts are common :(

Perspective on Gradle in this talk

  • Look at Gradle as a tool to model your software

  • Let Gradle read that model to build your software



This is how you should look at Gradle!

Sample Architecture

overview reduced

Defining Components as Gradle Builds

How do you control Gradle?

  • You write "build scripts", which should be models of your software

  • Use Gradle Groovy DSL (Domain Specific Language)

  • Or Gradle Kotlin DSL (Domain Specific Language)



Gradle runs on the JVM and compiles to JVM bytecode. Other JVM language can also be used to control Gradle.

How does Gradle work?

  • A set of core systems which are language-agnostic

    • Execution engine, dependency management, caching, …​

  • Everything else is a Plugin

    • Core plugins: Java, Groovy, Scala, …​

    • Community plugins: Kotlin (by JetBrains), Android (by Google), …​

    • Your own plugins as part of your software!

Defining Components as Gradle Builds

plain components

Demo #1

We define each component in an independent Gradle build

─ server-application
  └── settings.gradle.kts

─ user-feature
  └── settings.gradle.kts

─ domain-model
  └── settings.gradle.kts

Component: User Feature

user feature 1
─ user-feature
  ├── data
  │   └─ build.gradle.kts
  │      | plugins { id("java-library") } // generic type (core plugin)
  │      | java    { ... }                // inidvidual configuration
  │      | ...
  │
  ├── table
  │   └─ build.gradle.kts
  │      | plugins { id("java-library") } // generic type (core plugin)
  │      | java    { ... }                // inidvidual configuration
  │      | ...
  │
  └── settings.gradle.kts
      | include("data", "ui")              // inner component structure

Organising Build Configuration in a Build Logic Component

Adding a Build Logic Component

arch component 10

Demo #2 - We add a separate component (Gradle build) for build logic

- build-logic
  └── settings.gradle.kts

- server-application
  └── settings.gradle.kts

- user-feature
  └── settings.gradle.kts

- domain-model
  └── settings.gradle.kts

Component: User Feature

user feature 2
─ user-feature
  ├── data
  │   └── build.gradle.kts
  │       | plugins { id("com.example.java-library") }  // project type
  │
  ├── ui
  │   └── build.gradle.kts
  │       | plugins { id("com.example.kotlin-library") } // project type
  │
  └── settings.gradle.kts
      | includeBuild("../build-logic")  // location of a source component
      | repositories { mavenCentral() } // location of binary components
      | include("data", "ui")           // inner structure

Component: Build Logic

build logic
─ build-logic
  ├── java-library
  │   └── build.gradle.kts
  │       | plugins { `kotlin-dsl` } // project type for Gradle plugins
  │
  ├── kotlin-library
  │   └── build.gradle.kts
  │       | plugins { `kotlin-dsl` } // project type for Gradle plugins
  │
  ├── spring-boot-application
  │   └── ...
  │
  └── settings.gradle.kts
      | repositories { gradlePluginPortal() } // location binary components
      | include("java-library", "kotlin-library", .. // inner structure

Composing a Product from Components

Composing a Product from Components

product

Demo #3 - We add dependencies between our components

- build-logic
  └── settings.gradle.kts

- server-application
  └── settings.gradle.kts

- user-feature
  └── settings.gradle.kts

- domain-model
  └── settings.gradle.kts

Component: User Feature

user feature 3
─ user-feature
  ├── data
  │   └── build.gradle.kts
  │       | plugins { id("com.example.java-library") } // project type
  │       | dependencies { api("com.example.myproduct:release") }
  │
  ├── ui
  │   └── build.gradle.kts
  │       | plugins { id("com.example.java-library") } // project type
  │       | dependencies { ... }
  │
  └── settings.gradle.kts
      | includeBuild("../build-logic")  // location of a source component
      | includeBuild("../domain-model") // location of a source component
      | repositories { mavenCentral() } // location of binary components
      | include("data", "ui")           // inner structure

Working with your Gradle builds

Gradle tasks

  • Gradle knows inputs and outputs

  • If output of a task is the input of another, there is a dependency

  • Incremental - a task only executes if input/output changes

  • Build cache - Outputs can be retrieved from (remote) cache

Demo #4

Exploring: task execution, incremental builds, build cache, custom tasks

Custom tasks

  • An abstract class extending DefaultTask

  • Written in Java, Scala, Groovy, Kotlin

  • Properties as annotated abstract getter methods (getPropertyName())

  • Each task has an action implemented in a @TaskAction method

Summary

  • Look at Gradle as a tool to model your software

  • Treat each component in your architecture as a separate Gradle build

  • Treat build configuration and customization as separate components

Try this at home!


Chat more about Gradle and Kotlin?