Skip to content

A Gradle plugin to constrain a multi-module build dependency graph.

License

Notifications You must be signed in to change notification settings

gmazzo/gradle-module-kind-plugin

Repository files navigation

GitHub Maven Central Gradle Plugin Portal Build Status Coverage Users

Contributors

gradle-module-kind-plugin

A Gradle plugin to constrain a multi-module build dependency graph.

Meant to enforce an API/Implementation modularisation pattern in a multi-module monolith project: API/Implementation modularisation pattern

Note

Credits of the picture to this good reference

article Slaying the monolith: API/Implementation modularisation pattern in Android development

by Sean Coyle

Example of the failure when, for instance, implementation tries to depend on another implementation module: README-failure.png

Usage

Apply the plugin at the root project:

plugins {
  java
  id("io.github.gmazzo.modulekind") version "<latest>"
}

Then each subproject must be configured with as api or implementation:

moduleKind = "api" // or "implementation" or "monolith"

How it works

The plugin introduces a new io.github.gmazzo.modulekind attribute that:

  1. Is requested on key resolvable Configurations for known plugins (java and android)
  2. Decorates module's Outgoing Variants.
  3. Is used by an AttributeCompatibilityRule to determine if is a legal dependency for its consumer

It's recommended to read the Understanding Variant Selection chapter in Gradle's manual for a better understanding.

Configuration

By default, the plugin will provide the following compatibility table (which can be printed by running moduleKindConstraints task):

moduleKind api implementation monolith
api
implementation
monolith

These restrictions are fully configurable through the moduleKindConstraints DSL. The following is the equivalent configuration of the table above:

moduleKindConstraints {
  "implementation" compatibleWith "api"
  "monolith" compatibleWith "implementation"
  "monolith" compatibleWith "api" // redundant, since compatibilities are transitive
}

Or in groovy:

moduleKindConstraints {
  compatibility("implementation", "api")
  compatibility("monolith", "implementation")
  compatibility("monolith", "api") // redundant, since compatibilities are transitive
}

Note

Compatibles are transitive. So, if monolith can depend on implementation and implementation on api, then monolith can also depend on api.

Defining your own dependency constrains: domain objects use case

Like the demo project, imagine you want to have an extra deep in the 4th levels dependency graph where:

  • app is the monolith
  • implementation and api are the usual setup
  • api can also on domain modules, meant to share domain objects between apis
moduleKindConstraints {
  "api" compatibleWith "domain"
  "implementation" compatibleWith "api"
  "app" compatibleWith "implementation"
}

About

A Gradle plugin to constrain a multi-module build dependency graph.

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published

Contributors 3

  •  
  •  
  •  

Languages