core. In this module, gateways for the repositories are being defined. Each use case defines the interface of the gateway that is required following the ISP. These gateways, operate on the domain entities defined in
[UseCaseExecutor](https://github.com/thecodegang/clean-architecture-example/blob/master/usecases/src/main/kotlin/com/github/aantoniadis/delivery/usecases/core/UseCase.kt)are also defined.
UseCaseis an interface similar to the
java.util.Function. It just gets a request and transforms it into a response.
UseCaseExecutorhandles the execution of a
UseCase. To do so, it has an
invokemethod that takes the following arguments:
UseCasethat will be executed
Requestobject (the input of the use case)
Responseobject (the output of the use case) of the
UseCaseexecution to a
invokemethod, which omit the input and/or the output of the
[UseCaseExecutorImp](https://github.com/thecodegang/clean-architecture-example/blob/master/usecases/src/main/kotlin/com/github/aantoniadis/delivery/usecases/core/UseCase.kt)) is using
java.util.concurrent.CompletionStagefor the execution abstraction. These abstractions are convenient as they can perform asynchronous executions and also have out of the box compatibility with most frameworks.
usecasesmodule. This module depends on the framework that facilitates the data access. In our example, we use JPA and Spring Data. The
Jpa*Repositoryclasses are the actual implementation of the gateways defined in the
JpaRepository. Here is an example
DBProductRepositoryis a subclass of the a Spring Data
JpaProductRepository. An example of an entity is
dataprovidersmodule, the DTOs have mappers to convert from and to the domain entities.
RequestDtoand forwards it to the related use case through the
UseCaseExecutor. The response of the use case (which is a
ResponseDto) is the response of the controller's method that implements the endpoint. An example of such usage is
usecasesmodules). The flexibility is provided by the clean boundaries that we have between each layer. Also, due to the dependency rule that outer layers depend on the in inner layers, the
usecasesmodules are unaware of everything that we have changed in the outer modules. Hence, we don't even have to recompile these modules to deploy the application with the new data layer.
usecasesmodules contain only the business objects and the way they interact. Someone might say, that it is possible for a new team member to start writing new functionality without getting familiar enough first with the frameworks and/or the libraries that are used (of course there are some exceptions). The core of our application doesn't contain any magic framework that might make the learning curve steeper.