Scaffolding of Clean Architecture
Gradle plugin to create a java and kotlin application based on Clean Architecture following our best practices!
Plugin Implementation
To use the plugin you need Gradle version 7.6.1 or later, to start add the following section into your build.gradle file.
plugins {
id "co.com.bancolombia.cleanArchitecture" version "3.6.1"
}
Or if is a new project execute this script in the root directory of your project.
echo "plugins {
id \"co.com.bancolombia.cleanArchitecture\" version \"3.6.1\"
}" > build.gradle
To use the plugin you need Gradle version 6.9 or later, to start add the following section into your build.gradle.kts file.
plugins {
id("co.com.bancolombia.cleanArchitecture") version "3.6.1"
}
Or if is a new project execute this script in the root directory of your project.
echo "plugins {
id(\"co.com.bancolombia.cleanArchitecture\") version \"3.6.1\"
}" > build.gradle.kts
Tasks
The Scaffolding Clean Architecture plugin will allow you run 8 tasks:
Generate Project
The cleanArchitecture | ca
task will generate a clean architecture structure in your project, this task has four optional parameters; package
, type
, name
and coverage
.
If you run this task on an existing project it will override the main.gradle
, build.gradle
and gradle.properties
files.
-
package
= <package.we.need>
: You can specify the main or default package of your project.Default Value = co.com.bancolombia
-
type
= <imperative | reactive>
: With this parameter the task will generate a POO project.Default Value = reactive
-
name
= NameProject
: This parameter is going to specify the name of the project.Default Value = cleanArchitecture
-
coverage
= <jacoco | cobertura>
: This parameter is going to specify the coverage tool for the project.Default Value = jacoco
-
lombok
= <true | false>
: Specify if you want to use this plugin .Default Value = true
-
metrics
= <true | false>
: Specify if you want to enable this feature with micrometer .Default Value = true
-
language
= <JAVA | KOTLIN>
: Specify if you want to use this plugin .Default Value = JAVA
-
javaVersion
= <VERSION_1_8 | VERSION_11 | VERSION_17>
: Java version .Default Value = VERSION_17
gradle cleanArchitecture --package=co.com.bancolombia --type=reactive --name=NameProject --coverage=jacoco --lombok=true
gradle ca --package=co.com.bancolombia --type=reactive --name=NameProject --coverage=jacoco --lombok=true
The structure will look like this for java:
๐ฆNameProject
โฃ ๐applications
โ โ ๐app-service
โ โ โฃ ๐src
โ โ โ โฃ ๐main
โ โ โ โ โฃ ๐java
โ โ โ โ โ โ ๐[package]
โ โ โ โ โ โ โฃ ๐config
โ โ โ โ โ โ โ โ ๐[configs and beans]
โ โ โ โ โ โ โ ๐MainApplication.java
โ โ โ โ โ ๐resources
โ โ โ โ โ โฃ ๐[properties]
โ โ โ โ ๐test
โ โ โ โ โ ๐java
โ โ โ โ โ โ ๐[package]
โ โ โ ๐build.gradle
โฃ ๐deployment
โ โฃ ๐[Dockerfile, Pipelines as a code]
โฃ ๐domain
โ โฃ ๐model
โ โ โฃ ๐src
โ โ โ โฃ ๐main
โ โ โ โ โ ๐java
โ โ โ โ โ โ ๐[package]
โ โ โ โ ๐test
โ โ โ โ โ ๐java
โ โ โ โ โ โ ๐[package]
โ โ โ ๐build.gradle
โ โ ๐usecase
โ โ โฃ ๐src
โ โ โ โฃ ๐main
โ โ โ โ โ ๐java
โ โ โ โ โ โ ๐[package]
โ โ โ โ ๐test
โ โ โ โ โ ๐java
โ โ โ โ โ โ ๐[package]
โ โ โ โ โ โ โ ๐usecase
โ โ โ ๐build.gradle
โฃ ๐infrastructure
โ โฃ ๐driven-adapters
โ โฃ ๐entry-points
โ โ ๐helpers
โฃ ๐.gitignore
โฃ ๐build.gradle
โฃ ๐gradle.properties
โฃ ๐lombok.config
โฃ ๐main.gradle
โฃ ๐README.md
โ ๐settings.gradle
The structure will look like this for kotlin:
๐ฆNameProject
โฃ ๐applications
โ โ ๐app-service
โ โ โฃ ๐src
โ โ โ โฃ ๐main
โ โ โ โ โฃ ๐kotlin
โ โ โ โ โ โ ๐[package]
โ โ โ โ โ โ โฃ ๐config
โ โ โ โ โ โ โ โ ๐[configs and beans]
โ โ โ โ โ โ โ ๐MainApplication.kt
โ โ โ โ โ ๐resources
โ โ โ โ โ โฃ ๐[properties]
โ โ โ โ ๐test
โ โ โ โ โ ๐kotlin
โ โ โ โ โ โ ๐[package]
โ โ โ ๐build.gradle.kts
โฃ ๐deployment
โ โฃ ๐[Dockerfile, Pipelines as a code]
โฃ ๐domain
โ โฃ ๐model
โ โ โฃ ๐src
โ โ โ โฃ ๐main
โ โ โ โ โ ๐kotlin
โ โ โ โ โ โ ๐[package]
โ โ โ โ ๐test
โ โ โ โ โ ๐kotlin
โ โ โ โ โ โ ๐[package]
โ โ โ ๐build.gradle.kts
โ โ ๐usecase
โ โ โฃ ๐src
โ โ โ โฃ ๐main
โ โ โ โ โ ๐kotlin
โ โ โ โ โ โ ๐[package]
โ โ โ โ ๐test
โ โ โ โ โ ๐kotlin
โ โ โ โ โ โ ๐[package]
โ โ โ โ โ โ โ ๐usecase
โ โ โ ๐build.gradle.kts
โฃ ๐infrastructure
โ โฃ ๐driven-adapters
โ โฃ ๐entry-points
โ โ ๐helpers
โฃ ๐.gitignore
โฃ ๐build.gradle.kts
โฃ ๐gradle.properties
โฃ ๐lombok.config
โฃ ๐README.md
โ ๐settings.gradle.kts
Generate Model for Java and Kotlin
The generateModel | gm
task will generate a class and interface in model layer, this task has one required parameter name
.
gradle generateModel --name=[modelName]
gradle gm --name [modelName]
This task will generate something like that:
๐ฆdomain
โฃ ๐model
โ โฃ ๐src
โ โ โฃ ๐main
โ โ โ โ ๐java
โ โ โ โ โ ๐[package]
โ โ โ โ โ โ ๐model
โ โ โ โ โ โ โฃ ๐gateways
โ โ โ โ โ โ โ โ ๐ModelRepository.java
โ โ โ โ โ โ โ ๐Model.java
โ โ โ ๐test
โ โ โ โ ๐java
โ โ โ โ โ ๐[package]
โ โ โ โ โ โ ๐model
โ โ ๐build.gradle
This task will generate something like that for kotlin:
๐ฆdomain
โฃ ๐model
โ โฃ ๐src
โ โ โฃ ๐main
โ โ โ โ ๐kotlin
โ โ โ โ โ ๐[package]
โ โ โ โ โ โ ๐model
โ โ โ โ โ โ โฃ ๐gateways
โ โ โ โ โ โ โ โ ๐ModelRepository.kt
โ โ โ โ โ โ โ ๐Model.kt
โ โ โ ๐test
โ โ โ โ ๐kotlin
โ โ โ โ โ ๐[package]
โ โ โ โ โ โ ๐model
โ โ ๐build.gradle.kts
Generate Use Case for Java and Kotlin
The generateUseCase | guc
task will generate a class in model layer, this task has one required parameter name
.
gradle generateUseCase --name=[useCaseName]
gradle guc --name [useCaseName]
This task will generate something like that:
๐ฆdomain
โ ๐usecase
โ โฃ ๐src
โ โ โฃ ๐main
โ โ โ โ ๐java
โ โ โ โ โ ๐[package]
โ โ โ โ โ โ ๐usecase
โ โ โ โ โ โ โ ๐business
โ โ โ โ โ โ โ โ ๐BusinessUseCase.java
โ โ โ ๐test
โ โ โ โ ๐java
โ โ โ โ โ ๐[package]
โ โ โ โ โ โ ๐usecase
โ โ โ โ โ โ โ ๐business
โ โ ๐build.gradle
This task will generate something like that for kotlin:
๐ฆdomain
โ ๐usecase
โ โฃ ๐src
โ โ โฃ ๐main
โ โ โ โ ๐kotlin
โ โ โ โ โ ๐[package]
โ โ โ โ โ โ ๐usecase
โ โ โ โ โ โ โ ๐business
โ โ โ โ โ โ โ โ ๐BusinessUseCase.kt
โ โ โ ๐test
โ โ โ โ ๐kotlin
โ โ โ โ โ ๐[package]
โ โ โ โ โ โ ๐usecase
โ โ โ โ โ โ โ ๐business
โ โ ๐build.gradle.kts
Generate Driven Adapter
The generateDrivenAdapter | gda
task will generate a module in Infrastructure layer, this task has one required parameter type
.
Whether you'll use generic one also parameter name
is required.
gradle generateDrivenAdapter --type=[drivenAdapterType]
gradle gda --type [drivenAdapterType]
Reference for drivenAdapterType | Name | Additional Options | Java | Kotlin |
---|---|---|---|---|
generic | Empty Driven Adapter | --name [name] | โ | โ |
jpa | JPA Repository | --secret [true-false] | โ | โ |
mongodb | Mongo Repository | --secret [true-false] | โ | โ |
asynceventbus | Async Event Bus | โ | โ | |
restconsumer | Rest Client Consumer | --url [url] | โ | โ |
redis | Redis | --mode [template-repository] --secret [true-false] | โ | โ |
rsocket | RSocket Requester | โ | โ | |
r2dbc | R2dbc Postgresql Client | โ | โ | |
kms | AWS Key Management Service | โ | โ | |
secrets | Secrets Manager Bancolombia | โ | โ | |
s3 | AWS Simple Storage Service | โ | โ | |
mq | JMS MQ Client to send messages | โ | โ | |
ktor | HTTP client for kotlin | โ | โ | |
dynamodb | Dynamo DB adapter | โ | โ | |
sqs | SQS message sender | โ | โ |
This task will generate something like that:
๐ฆinfrastructure
โฃ ๐driven-adapters
โ โ ๐jpa-repository
โ โ โฃ ๐src
โ โ โ โฃ ๐main
โ โ โ โ โ ๐java
โ โ โ โ โ โ ๐[package]
โ โ โ โ โ โ โ ๐jpa
โ โ โ โ โ โ โ โฃ ๐config
โ โ โ โ โ โ โ โ โ ๐DBSecret.java
โ โ โ โ โ โ โ โฃ ๐helper
โ โ โ โ โ โ โ โ โ ๐AdapterOperations.java
โ โ โ โ โ โ โ โฃ ๐JPARepository.java
โ โ โ โ โ โ โ โ ๐JPARepositoryAdapter.java
โ โ โ โ ๐test
โ โ โ โ โ ๐java
โ โ โ โ โ โ ๐[package]
โ โ โ โ โ โ โ ๐jpa
โ โ โ โ โ โ โ โ ๐helper
โ โ โ ๐build.gradle
Generate Entry Point
The generateEntryPoint | gep
task will generate a module in Infrastructure layer, this task has one required parameter type
.
Whether you'll use generic one also parameter name
is required.
gradle generateEntryPoint --type=[entryPointType]
gradle gep --type [entryPointType]
Reference for entryPointType | Name | Additional Options | Java | Kotlin |
---|---|---|---|---|
generic | Empty Entry Point | --name [name] | โ | โ |
restmvc | API REST (Spring Boot Starter Web) | --server [serverOption] default undertow | โ | โ |
webflux | API REST (Spring Boot Starter WebFlux) | --router [true, false] default true | โ | โ |
rsocket | Rsocket Controller Entry Point | โ | โ | |
graphql | API GraphQL | --pathgql [name path] default /graphql | โ | โ |
asynceventhandler | Async Event Handler | โ | โ | |
mq | JMS MQ Client to listen messages | โ | โ | |
sqs | SQS Listener | โ | โ |
Additionally, if you'll use a restmvc, you can specify the web server on which the application will run. By default, undertow.
gradle generateEntryPoint --type=restmvc --server=[serverOption]
gradle gep --type=restmvc --server=[serverOption]
Reference for serverOption | Name |
---|---|
undertow | Undertow server (default) |
tomcat | Tomcat server |
jetty | Jetty server |
This task will generate something like that:
๐ฆinfrastructure
โฃ ๐entry-points
โ โ ๐generic
โ โ โฃ ๐src
โ โ โ โฃ ๐main
โ โ โ โ โ ๐java
โ โ โ โ โ โ ๐[package]
โ โ โ โ โ โ โ ๐generic
โ โ โ โ ๐test
โ โ โ โ โ ๐java
โ โ โ โ โ โ ๐[package]
โ โ โ โ โ โ โ ๐generic
โ โ โ ๐build.gradle
Generate Helper
The generateHelper | gh
task will generate a module in Infrastructure layer, this task has one required parameter name
.
gradle generateHelper --name=[helperName]
gradle gh --name=[helperName]
Generate Pipeline
The generatePipeline | gpl
task will generate CI pipeline inside the folder "./deployment/", this task has one required parameter type
.
gradle generatePipeline --type=[pipelineType]
gradle gpl --type=[pipelineType]
Reference for pipelineType | Name |
---|---|
azure | Azure Pipeline |
github | GitHub Action |
jenkins | Jenkins Pipeline |
circleci | CircleCI Pipeline |
Generate Acceptance Test
The generateAcceptanceTest | gat
task will generate subproject by karate framework inside the folder "./deployment/", this task has one optional parameter, name
.
name
= NameAcceptanceTestProject
: This parameter is going to specify the name of the acceptance test project.Default Value = acceptanceTest
gradle generateAcceptanceTest --name=[acceptanceTestProjectName]
gradle gat --name=[acceptanceTestProjectName]
Karate is an open-source tool to combine API test-automation, mocks, performance-testing and even UI automation into a single, unified framework. The BDD syntax popularized by Cucumber is language-neutral, and easy for even non-programmers. Assertions and HTML reports are built-in, and you can run tests in parallel for speed.
Generate Performance Test
The generatePerformanceTest | gpt
task will generate Performance test inside the folder "./performance-test/", this task has one required parameter type
.
gradle generatePerformanceTest --type=[performanceType]
gradle gpt --type=[performanceType]
| Reference for **performanceType** | Name |
| ------------------------------ | -------------- |
| jmeter | Jmeter Performance Test |
Validate Structure
The validateStructure | vs
Validate that project references aren't violated.
gradle validateStructure
gradle vs
This validation has another best practices verifications, which you can see on the generated
ArchitectureTest
file within the unit tests of the app-service
module.
Dependency Rules
One important point made by Robert C. Martin on Clean Architecture is the Dependency Rule, that can be summarized like this: source code dependencies can only point inwards. Nothing in an inner circle can know anything at all about something in an outer circle. In particular, the name of something declared in an outer circle must not be mentioned by the code in an inner circle.
Having that in mind, the validateStructure | vs
task performs the following validations:
- Model module: to have no dependencies at all.
- UseCase module: to declare dependency to the Model module ONLY, and no other additional dependencies.
- Infrastructure Layer modules:
- Allow declaration of any external dependency.
- Allow declaration of dependency on Model and/or UseCase modules.
- Avoid declaration of dependency AppService module.
Whitelisting dependencies:
Some dependencies, specially when working with BOMs (Bills of Materials), are injected transversally to the project, making the validation task to flag failures to rules 1 and 2. To avoid this scenario, or other you may encounter, you can configure a set of whitelisted dependencies.
Example:
-
Let's say you have declared a BOM in your project:
dependencies { implementation(platform("com.myorg:my-bom:0.0.1")) }
-
This will make
validateStructure | vs
to flag a failure indicating an error like this:Validating Model Module --- Dependency com.myorg:some-bom is not allowed in Model Layer
-
To avoid this, you can white list your BOM like this:
// build.gradle cleanPlugin { modelProps { whitelistedDependencies = "my-bom, <dep2>, <depN..>" } }
Indicating only the name of the dependencies comma-separated.
Delete Module
The deleteModule | dm
task will delete a sub project, this task has one required parameter module
.
gradle deleteModule --module=[name]
gradle dm --module=[name]
Update Project
The updateCleanArchitecture | u
task will update plugin and dependencies in all sub projects, this task has one optional parameter dependencies
if you only want to update some dependencies the dependency need to contain the group, and the artifact for example for the dependency cleanArchitecture you will need to append co.com.bancolombia:cleanArchitecture.
It also updates the spring, lombok, gradle and some other dependencies according to the plugin version that you are using, ocassionally it could make changes in other project structural files.
We recommend that you commit your changes to git before running this command, but you can skip the verification passing --git false
.
gradle updateCleanArchitecture --dependencies=[dependency1, dependency2, ...]
gradle u --dependencies=[dependency1, dependency2, ...]
How can I help?
Review the issues, we hear new ideas. Read more Contributing
Analytics
You can help the Contributors Team to prioritize features and improvements by permitting the Contributors team to send gradle tasks usage statistics to Analytics Server. The Contributors Team collect usage statistics unless you explicitly opt in off.
Due to the user input limitations to gradle task, when running any plugin task you will be notified about the analytics recollection, and you have the possibility to disable this recollection. If you enable or disable analytics explicitly, future task executions will not notify you.
To explicitly enable analytics and avoid the notification message
gradle analytics --enabled true
# o gradle a --enabled true
To disable analytics
gradle analytics --enabled false
# # o gradle a --enabled false
What is collected?
Usage analytics include the commands and selected flags for each execution. Usage analytics may include the following information:
- Your operating system (macOS, Linux distribution, Windows) and its version.
- Java vendor name and version.
- Java specification and runtime versions.
- Plugin version.
- Project language (
kotlin
orjava
) - Task name that was run.
- Workspace information like language, user that is running the task.
- For generate use case, generate model, generate helper and delete module tasks, the name will be sent.
- For all tasks, the type and name, the time it took to run the task, and project type (reactive, imperative).
Whats Next?
Read more About Clean Architecure