Polygonal Architecture plug-in

The gradle/maven plugin which drives your architecture into the next level.

GitHub

What is Polygonal Architecture?

Well it’s not so complicated. Let’s image that you are going to build a building. To make this building good looking bricks needs to match with each other SOMEHOW, and this SOMEHOW is actually your polygon definition.

What is Polygon?

It’s a domain-level package which can communicate (match) with other polygons only by agreed rules. It does not matter if you are going to use triangles, hexagons, octagons, pentagons -> you can chose whatever your like

Why should I use it?

Because you wanna have clean architecture in your project.
Everyone was in a project where codes looks more like spaghetti dinner than a good quality code. This is really common problem, when after X months of development code base starts looking really bad. What can cause this problem? Mhmm :thinking: everyone is different, and it’s really rare that team members have agreed some common packaging/common architecture before they start to work on some new project. Whenever someone is going to implement a new service, or a new model object new package is just a side effect. It needs to happened that after a while, each package lives its own life.

This plug-in will help you to keep your architecture clean like a baby ass :joy:

Getting started | gradle

The plug-in (gradle) is served by plugins.gradle.org, you can find it here: Polygonal Architecture Gradle

plugins {
  id "pl.mk5.polygonal-architecture" version "X.Y.Z"
}

The next step is to tell the plugin where is a start point for your architecture. Two mandatory parameteres things are sources directory, and the base package.

polygonalArchitecture {
  sourcesDir = file('src/main/java')
  basePackage = 'org.example'
}

The last thing you need is your polygon definition. The simplest way is to create polygon.yml file, and add it to your resources location. The base element in polygon definition is a package. For instance, you can define how many public objects are allowed, or which types are allowed. By default, every visibility scope except package-private is denied, and all types are allowed.

Getting started | maven

The plug-in (maven) is served via bintray repository, so you need to use this repo:

<pluginRepositories>
    <pluginRepository>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
        <id>bintray-mk-5-maven</id>
        <name>bintray-plugins</name>
        <url>https://dl.bintray.com/mk-5/maven</url>
    </pluginRepository>
</pluginRepositories>

The basePackage parameter is required. It’s a start point for your architecture.

<build>
    <plugins>
        <plugin>
            <groupId>pl.mk5.polygonal</groupId>
            <artifactId>polygonal-architecture-maven-plugin</artifactId>
            <version>latest</version>
            <configuration>
                <basePackage>pl.mk5.polygonal.mvne2e</basePackage>
            </configuration>
        </plugin>
    </plugins>
</build>

Similar to gradle -> you need yours polygon definition. In maven architecture plugin you need to define your polygon in YML file.

More information about maven configuration can be found here: Maven polygonal architecture.

YML polygon definition

The polygon define could be in YML file. That option might be a little bit more straightforward if you’d like to keep configuration in separate files. The first step is to tell where do you keep polygon definition (by default plugin is looking in {resourcesDir}/polygon.yml)

polygonalArchitecture {
  sourcesDir = file('src/main/java')
  basePackage = 'org.example'
  polygonTemplate = file('src/main/resources/polygon.yml')
}

The YML definition has a little bit different schema. In Gradle DSL we are not able to use simple keywords like public or protected because there are reserved by Java. We don’t have such a restrictions in YML.

polygon:
  packagePrivate: -1
  types: ['interface', 'class', 'enum', 'data class']
  packages:
    dto:
      required: true 
      public: -1
      types: ['class']

More information about YML configuration can be found here: YML polygon definition.

Mixing YML and Gradle DSL

Mixing gradle DSL with yaml configuration is fine. The one rules here is that gradle DSL has higher precedence than yaml, so you can define the base polygon schema in yaml, and then overwrite some rules by gradle configuration.

Gradle DSL polygon definition

This is how the basic polygon definition might looks like:

polygonalArchitecture {
  sourcesDir = file('src/main/java')
  basePackage = 'org.example'
  
  polygon {
    packageDef {
      name ''  // root package
      packagePrivateScope = -1
    }
    packageDef {
      name 'dto'
      required = true
      publicScope = -1 // package-private is allowed here
      types = ['class']
    }
  }
}

Above polygon definition means that we allow only package-private object at polygon root package. Besides from that we define one package dto where only public classes are allowed. Project structure might looks as follow:

.
├── 📂 invoices (polygon)
|   ├── 📂 dto
|   |   └── 📄 Invoice.java
│   └── 📄 RepositoryUserFinder.java
├── 📂 users    (polygon)
|   ├── 📂 dto
|   |   └── 📄 User.java
│   └── 📄 UserFinder.java
└── 📄 DemoApplication.java

More information about Gradle DSL configuration can be found here: Gradle DSL polygon definition.

Maven plugin-in

The only way to define polygon for maven plugin is yml file. More information about maven configuration can be find here: Maven polygonal-architecture.

Examples

If you are interested in more polygons examples -> this is page for you: Polygons examples

Verify your polygons

Now we finally got to the point, how can we verify if our polygons are match? This simple task can do this for you:

$ ./gradlew verifyPolygons

In case of any unmatched polygon you will see this kind of error message:

Checking polygons for project demo
-- polygon droids is going to be checked
-- polygon universe is going to be checked

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':verifyPolygons'.
> 0 public scope objects are allowed in 'guns' package

Donate

I’m one person army, and put all my :heart: into a software. You know there’s no :dollar: by which love can be bought, so I’m not taking any donates - that’s it :wink: If you really would like to give me more power to create more features, the only thing you can do is to start my project at github.