bancolombia-scaffold-clean-architecture
repository·master·Indexed 19 days ago
https://github.com/bancolombia/scaffold-clean-architectureA Gradle plugin that automates the scaffolding of Java applications based on Clean Architecture principles and Bancolombia's specific best practices. It organizes projects into four layers: Domain (business logic), Usecases (application logic), Infrastructure (Entry Points, Driven Adapters, and Helpers), and Application (module assembly and dependency injection via @ComponentScan).
What's inside scaffold-clean-architecture
- This project provides a Gradle plugin designed to scaffold Java applications following Clean Architecture principles and Bancolombia's best practices. It automates the creation of the project structure, ensuring consistency and adherence to architectural patterns.
How Use Case beans are automatically registered in the Application layer
masterIn this scaffold, you do not need to manually define beans for your Use Cases. The Application module uses a@ComponentScanannotation to automatically discover and register Use Case beans, injecting the necessary concrete instances of their declared dependencies (from the Infrastructure layer) at runtime.Understand the Dependency Rules for Clean Architecture
masterThe
validateStructuretask enforces the Dependency Rule: source code dependencies can only point inwards. Inner circles must not know about anything in outer circles. The task enforces the following specific constraints:- Model module: Must have no dependencies at all.
- UseCase module: Can only declare a dependency to the Model module. No other dependencies are allowed.
- Infrastructure Layer modules:
- Can declare any external dependency.
- Can declare dependencies on Model and/or UseCase modules.
- Must avoid declaring a dependency on the
AppServicemodule.
Understand the Clean Architecture structure in the Mongo example
masterThe
example-mongoproject follows a Clean Architecture pattern organized into specific layers. The flow moves from external components (Infrastructure/Entry Points) towards the core business logic (Domain/Usecases), with theApplicationmodule acting as the orchestrator.Layer Breakdown:
- Domain: The innermost layer. It encapsulates business logic and rules using domain models and entities.
- Usecases: Part of the domain layer. It implements system use cases, defines application logic, and orchestrates flows by interacting with the
Domainentities. It reacts to invocations fromEntry Points. - Infrastructure:
- Helpers: General utilities for Driven Adapters and Entry Points. These use generics to model behaviors for various persistence objects (based on the Unit of Work and Repository patterns). They must be inherited by Driven Adapters.
- Driven Adapters: Implementations of external systems, such as REST/SOAP services, databases (e.g., MongoDB), or file reading.
- Entry Points: The entry points of the application where business flows begin.
- Application: The outermost layer. It assembles all modules, resolves dependencies, and starts the application (it contains the
public static void mainmethod).
Understand the Clean Architecture structure in the Redis example
masterThis project implements Clean Architecture by separating concerns into distinct layers. The architecture flows from the outermost layer (Application) to the innermost layer (Domain).
- Domain: The innermost module. It encapsulates business logic and rules using domain models and entities.
- Usecases: A Gradle module within the Domain layer. It implements system use cases, defines application logic, and orchestrates flows by interacting with the Domain entities. It reacts to invocations from Entry Points.
- Infrastructure: Contains the technical implementation details, subdivided into:
- Helpers: General utilities for Driven Adapters and Entry Points. These use generics to model behaviors for persistence objects (based on Unit of Work and Repository patterns) and must be inherited by Driven Adapters.
- Driven Adapters: Implementations of external systems such as REST services, SOAP, databases, or file reading. They represent any external data source the system interacts with.
- Entry Points: The entry points of the application or the starting points of business flows.
- Application: The outermost module. It is responsible for assembling modules, resolving dependencies, and automatically creating Spring beans for Use Cases via
@ComponentScan. This is the only module containing thepublic static void main(String[] args)method.
Understand the Clean Architecture structure in the S3 Example
masterThe project follows a layered Clean Architecture pattern, organized from the most external components to the core business logic. The layers are:
- Application: The outermost layer. It assembles modules, resolves dependencies, and starts the application (contains the
public static void mainmethod). It uses@ComponentScanto automatically register UseCase beans. - Entry Points: Represent the entry points of the application or the start of business flows.
- Driven Adapters: Implementations of external systems such as REST/SOAP services, databases, or file reading (e.g., S3 interaction).
- Infrastructure (Helpers): Contains general utilities for Driven Adapters and Entry Points. These use generics and follow patterns like Unit of Work and Repository. Helpers must be inherited by Driven Adapters.
- Usecases: Implements system use cases and application logic. It orchestrates flows by calling the Entities module and reacts to invocations from Entry Points.
- Domain (Entities): The innermost module. It encapsulates business rules and logic through domain models and entities.
- Application: The outermost layer. It assembles modules, resolves dependencies, and starts the application (contains the
Understand the Clean Architecture layers
masterThe Scaffold Clean Architecture Gradle Plugin generates a multi-module project following Robert C. Martin's Clean Architecture principles. The architecture is organized into three main layers where dependencies always point inwards:
Domain (Internal): Encapsulates business rules and logic.
modelmodule: Contains domain models, entities, and defines ports (interfaces).usecasemodule: Contains application logic and orchestrates flows using the ports defined in themodelmodule.
Infrastructure (Middle): Contains technical implementations of the domain ports.
entry-pointsmodules: The start of business flows (e.g., REST controllers, Kafka consumers).driven-adaptersmodules: External implementations (e.g., database connections, REST/SOAP clients, file readers).helpersmodules: General utilities for Driven Adapters and Entry Points.
Application (External): The outermost layer responsible for assembling modules, resolving dependencies, and creating beans. This is the only module containing the
public static void main(String[] args)method to start the application.
Understand the Clean Architecture structure
masterThe project follows a Clean Architecture pattern organized into specific layers to isolate business logic from external details. The layers are organized from the most internal (core business) to the most external (infrastructure and application assembly):
- Domain: The innermost layer. It encapsulates business logic and rules using domain models and entities.
- Usecases: A Gradle module within the domain layer. It implements system use cases, defines application logic, and orchestrates flows by interacting with the Domain entities. It reacts to invocations from Entry Points.
- Infrastructure: Contains the technical implementations required by the system.
- Helpers: General utilities for Driven Adapters and Entry Points. These use generics to model behaviors for various persistence objects (based on the Unit of Work and Repository patterns). Helpers must be inherited by Driven Adapters.
- Driven Adapters: Implementations of external systems, such as REST/SOAP services, databases, or file readers.
- Entry Points: The entry points of the application that initiate business flows.
- Application: The outermost layer. It is responsible for assembling modules, resolving dependencies, and automatically creating Spring beans for the Use Cases. This is the only module containing the
public static void main(String[] args)method.
How UseCase beans are automatically registered in the Application layer
masterIn this scaffold, you do not need to manually define every bean for your business logic. TheApplicationmodule is configured with a@ComponentScanannotation. This allows the framework to automatically discover and instantiate UseCase beans and inject their required dependencies (such as Driven Adapters) during the application startup.Ensure UseCases and Beans use final attributes for concurrency safety
masterTo avoid concurrency issues caused by shared mutable state, ArchUnit enforces that all dependencies in
UseCaseclasses and Spring@Component(Beans) must be immutable.- UseCases: All attributes must be declared as
final. - Beans: Dependencies should be injected via constructor rather than using
@Valueon fields. This ensures all dependencies arefinaland immutable.
// Compliant Bean using constructor injection @Component public class MyService { private final String endpoint; public MyService(@Value("${external-service.endpoint}") String endpoint) { this.endpoint = endpoint; } }- UseCases: All attributes must be declared as
Implement Driven Adapters and Helpers
masterDriven Adapters and Helpers are part of the Infrastructure layer.
- Driven Adapters: Use these to implement interactions with external sources like databases, REST/SOAP services, or flat files.
- Helpers: Provide generic utilities for Driven Adapters and Entry Points. These utilities are not tied to concrete objects and use generics to model behaviors for various persistence objects (based on the Unit of Work and Repository patterns).
Note: Helper classes cannot exist in isolation; they must be inherited/used within Driven Adapters.
Template variables for module generation
masterModules are generated using Mustache templates. The following variables are available to impact template generation:
Boolean Variables:
lombok: Enables/disables Lombok annotations (default:true).metrics: Enables/disables metric generation (default:true).reactive: Determines if the module is reactive. Iftrue, the resource directory follows the<module-name>-reactivepattern; otherwise, it uses<module-name>(default:false).
Predefined Variables:
projectName: The name assigned by the user.projectNameLower: The project name in lowercase.package: The user-defined package (e.g.,co.com.bancolombia.sample).packagePath: The package path (e.g.,co/com/bancolombia/sample).- Constants: Any constant defined in the
Constantsclass is available by its name (e.g.,PLUGIN_VERSION).