The clean Architecture
The clean architecture separates concerns of the application in a scalable and maintainable way.
Clean architecture systems are:
- Independent of Frameworks. The architecture does not depend on the existence of some library of feature laden software. This allows you to use such frameworks as tools, rather than having to cram your system into their limited constraints.
- Testable. The business rules can be tested without the UI, Database, Web Server, or any other external element.
- Independent of UI. The UI can change easily, without changing the rest of the system. A Web UI could be replaced with a console UI, for example, without changing the business rules.
- Independent of Database. You can swap out Oracle or SQL Server, for Mongo, BigTable, CouchDB, or something else. Your business rules are not bound to the database.
- Independent of any external agency. In fact your business rules simply don’t know anything at all about the outside world.
- App contains the Business Entities and the Interactors (Use cases)
- Ports are the boundaries of the app: interfaces and DTOs.
- Adapters are the implementations of the ports (boundaries)
- primary adapters are source of the control (or driving adapters)
- secondary adapters are target of the control (or drived adapters)
Outside of the adatpers are the frameworks, drivers.
All the dependencies pointing towards the center, and nothing on the opposite way.
Business Rules (Entities)
Entities are not the same as JPA Entities, they are high level business rules, policies, and should be independent from any other concerns.
suggested by Uncle Bob:
Probably this is not a perfect solution, I departed from Uncle Bob’s recommendations at some points.
- I didn’t separated Contoller and Presenter, because I didn’t wanted to move UI workflows to usecase layer. (opening views, popups, etc)
- I introduced UI abstraction that encapsulates a view and a controller, to provide a single interface for this relation.
- I used Visitor pattern many places but I found it’s implementation side effects very cumbesome,
- so somewhere I just used switch (but that switch is in the main module)
- I didn’t used builders for data structures (request, response dtos), so i just put them to the ports layer together with interfaces.
- I used Guice DI in several modules, but only(!) outside of the Boundaries (Ports).
- There are Unit Tests only for Entities, and Integration tests (testing usecases) in Main module.
- I used a proxy mechanism implementing entity gateway for JPA.
This is the module view of my implementation
Project PayrollMain -> Main.java:
In Main class it is selectable to run with JPA, or InMemory database. This example has configured JPA with hsqldb, so no database needed to test it.
Payroll.builder() .withDatabaseJPA(JPAPersistenceUnit.HSQL_DB) .withBankTransferPortFake() .withLoadedTestData() .buildGuiAdminSwing() .run();
Full Source Code is available on GITHUB, or as a download: