Giter Site home page Giter Site logo

modules-graph-assert's Introduction

Module Graph Assert

A Gradle plugin that helps keep your module graph healthy and lean.

Build Gradle Plugin

example_graph

Why the module dependency structure matters

  • Build speeds can be very dependent on the structure of your module graph.
  • Modules separate logical units and enforce proper dependencies.
  • The module graph can silently degenerate into a list-like structure.
  • Breaking problematic module dependencies can be very difficult, it is cheaper to prevent them.
  • If not enforced, undesirable module dependencies will appear. Murphy's law of dependencies: "Whatever they can access, they will access."

What we can enforce

  • The plugin provides a simple way for defining rules, which will be verified with the task assertModuleGraph as part of the check task.
  • Match module names using regular expressions.
  • Define the only allowed dependencies between modules
    • allowed = [':feature-one -> :feature-[a-z-:]*', ':.* -> :core', ':feature.* -> :lib.*'] define rules by using regex -> regex signature.
    • Dependency, which will not match any of those rules will fail the assertion.
  • restricted [':feature-[a-z]* -X> :forbidden-to-depend-on'] helps us to define custom rules by using regex -X> regex signature.
  • maxHeight = 4 can verify that the height of the modules tree with a root in the module will not exceed 4. Tree height is a good metric to prevent module tree degeneration into a list.

Usage

Apply the plugin to a module, which dependencies graph you want to assert.

plugins {
  id "com.jraska.module.graph.assertion" version "2.2.0"
}

You can run ./gradlew assertModuleGraph to execute configured checks or ./gradlew check where assertModuleGraph will be included.

Configuration

Rules are applied on the Gradle module and its api and implementation dependencies by default. Typically you would want to apply this in your final app module, however configuration for any module is possible. Example

moduleGraphAssert {
  maxHeight = 4
  allowed = [':.* -> :core', ':feature.* -> :lib.*'] // regex to match module names
  restricted = [':feature-[a-z]* -X> :forbidden-to-depend-on'] // regex to match module names
  configurations = ['api', 'implementation'] // Dependency configurations to look. ['api', 'implementation'] is the default
}

Module name alias

  • You don't have to rely on module names and set a property ext.moduleNameAssertAlias = "ThisWillBeAssertedOn"
  • This can be set on any module and the allowed/restricted rules would use the alias instead of module name for asserting.
  • This is useful for example if you want to use "module types" where each module has a type regardless the name and you want to manage only dependnecies of different types.
  • It is recommended to use either module names or moduleNameAssertAlias everywhere. Mixing both is not recommended.
  • Example of module rules you could implement for a flat module graph:

`

  • Each module would have set ext.moduleNameAssertAlias = "Api|Implementation|App"
  • Module rules example for such case: allowed = ['Implementation -> Api', 'App -> Implementation', 'App -> Api']
  • In case you want to migrate to this structure incrementally, you can set a separate module type like ext.moduleNameAssertAlias = "NeedsMigration" and setting
allowed = [
  'Implementation -> Api', 
  'App -> Implementation', 
  'App -> Api', 
  'NeedsMigration -> .*', 
  '.* -> NeedsMigration'
]
  • "NeedsMigration" modules can be then tackled one by one to move them into Implementation or Api type. Example of app with this structure can be seen here.

Graphviz Graph Export

  • Visualising the graph could be useful to help find your dependency issues, therefore a helper generateModulesGraphvizText task is included.
  • This generates a graph of dependent modules when the plugin is applied.
  • The longest path of the project is in red.
  • If you utilise Configuration on demand Gradle feature, please use --no-configure-on-demand flag along the generateModulesGraphvizText task.
  • You can set the modules.graph.of.module parameter if you are only interested in a sub-graph of the module graph.
./gradlew generateModulesGraphvizText -Pmodules.graph.of.module=:feature-one
  • Adding the parameter modules.graph.output.gv saves the graphViz file to the specified path
./gradlew generateModulesGraphvizText -Pmodules.graph.output.gv=all_modules

Graph statistics

  • Executing the task generateModulesGraphStatistics prints the information about the graph.
  • Statistics printed: Modules Count, Edges Count, Height and Longest Path
  • Parameter -Pmodules.graph.of.module is supported as well.
./gradlew generateModulesGraphStatistics -Pmodules.graph.of.module=:feature-one

Contributing

Please feel free to create PR or issue with any suggestions or ideas. No special format required, just common sense.

Debugging

Setting up a composite build:

This case is helpful when you need to debug in a real project. Composite builds are consumed directly without publishing a snapshot version.
This is done already in example project, but you can do the same in any other project:

settings.gradle:

includeBuild("path/to/modules-graph-assert")

Root build.gradle:

plugins {
  id('com.jraska.module.graph.assertion')
}

modules-graph-assert's People

Contributors

jraska avatar dependabot[bot] avatar lordcodes avatar dafi avatar eugene-krivobokov avatar zacsweers avatar dependabot-preview[bot] avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.