Polygonal Architecture plug-in

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

GitHub Examples

What is Polygonal Architecture?

Well it’s not so complicated. Let’s image that you are going to build a building. In order to build a good-looking building using bricks, all bricks needs to match with each other in some way. This ‘some way’ is actually your polygon definition.

What is Polygon?

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

Why should I use it?

Because you wanna have clean architecture in your project.
Everyone was in a project where code-base looks more like spaghetti dinner than a good quality code. This is a really common problem. Typically, after N months of development source code starts looking awful. What could be a potential reason of that 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. Even if they did agreed … those rules are simple disappearing after a while. Developers are creating new packages just as a side effect of creating a model, or a service. That leads to a really messy thing … 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 "io.polygonal" version "X.Y.Z"
}

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

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

The last thing you need too add 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 accepted, 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>io.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 is pretty simple. It goes like this:

polygon:
  packagePrivate: -1
  types: ['interface', 'class', 'enum', 'data class']
  packages:
    dto:
      required: true 
      public: -1
      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 follows:

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

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 in groovy dsl:

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']
    }
  }
}

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 invalid 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: that can buy love, so I’m not taking any donates :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.