In the past few years, many blog posts and articles have been written that present the , as it has been presented by in his and (in more details) in his fantastic book Clean Architecture Robert C. Martin (Uncle Bob) blog post “Clean Architecture: A Craftsman’s Guide to Software Structure and Design.” In this post, we present an example of a REST service that uses Clean Architecture and is written in . Kotlin The source code can be found in this repo: _clean-architecture-example - A simple clean architecture example in Kotlin and Spring Boot 2.0_github.com thecodegang/clean-architecture-example A short description of the clean architecture example modules The project consists of 4 modules , , , and . core usecases dataproviders delivery module core This module contains the domain entities. There are no dependencies to frameworks and/or libraries. module usecases This module contains the business rules that are essential for our application. The only dependency of this module is to . In this module, gateways for the repositories are being defined. Each use case defines the interface of the gateway that is required following the . These gateways, operate on the domain entities defined in . core ISP core In this module, and are also defined. [UseCase](https://github.com/thecodegang/clean-architecture-example/blob/master/usecases/src/main/kotlin/com/github/aantoniadis/delivery/usecases/core/UseCase.kt) [UseCaseExecutor](https://github.com/thecodegang/clean-architecture-example/blob/master/usecases/src/main/kotlin/com/github/aantoniadis/delivery/usecases/core/UseCase.kt) The is an interface similar to the . It just gets a request and transforms it into a response. UseCase java.util.Function The handles the execution of a . To do so, it has an method that takes the following arguments: UseCaseExecutor UseCase invoke the that will be executed UseCase a RequestDto a that converts the to a object (the input of the use case) mapper function RequestDto Request a that converts the object (the output of the use case) of the execution to a mapper function Response UseCase ResponseDto There are three more overloaded versions of the method, which omit the input and/or the output of the . invoke UseCaseExecutor Currently, the implementation ( ) is using and for the execution abstraction. These abstractions are convenient as they can perform asynchronous executions and also have out of the box compatibility with most frameworks. UseCaseExecutor [UseCaseExecutorImp](https://github.com/thecodegang/clean-architecture-example/blob/master/usecases/src/main/kotlin/com/github/aantoniadis/delivery/usecases/core/UseCase.kt) java.util.concurrent.CompletableFuture java.util.concurrent.CompletionStage module dataproviders This module contains the implementation of the gateways defined in the module. This module depends on the framework that facilitates the data access. In our example, we use JPA and Spring Data. The classes are the actual implementation of the gateways defined in the module. usecases Jpa*Repository usecases These repositories, make use of the Spring Data . Here is an example : JpaRepository [JpaProductRepository.kt](https://github.com/thecodegang/clean-architecture-example/blob/master/dataproviders/src/main/kotlin/com/github/aantoniadis/dataproviders/db/jpa/repositories/JpaProductRepository.kt) is a subclass of the a Spring Data . DBProductRepository JpaRepository The entities in this module, are JPA entities, so mapper functions are required to make the translation between these entities and domain entities. In the previous snippet, we demonstrated how these mapper functions are used in the . An example of an entity is : JpaProductRepository [ProductEntity.kt](https://github.com/thecodegang/clean-architecture-example/blob/master/dataproviders/src/main/kotlin/com/github/aantoniadis/dataproviders/db/jpa/entities/ProductEntity.kt) module delivery This module contains all the details of the delivery mechanism that we use along with the wiring of the app and the configurations. In our example, we use rest services built with Spring Boot. Similarly, to the JPA entities of the module, the DTOs have mappers to convert from and to the domain entities. dataproviders A rest controller gets the and forwards it to the related use case through the . The response of the use case (which is a ) is the response of the controller's method that implements the endpoint. An example of such usage is . RequestDto UseCaseExecutor ResponseDto [ProductResourceImp.kt](https://github.com/thecodegang/clean-architecture-example/blob/master/delivery/src/main/kotlin/com/github/aantoniadis/delivery/rest/imp/ProductResourceImp.kt) The exceptions are handled by , and they are converted to . GlobalExceptionHandler.kt [ErrorDto](https://github.com/thecodegang/clean-architecture-example/blob/master/delivery/src/main/kotlin/com/github/aantoniadis/delivery/rest/api/ErrorDto.kt) Clean Architecture separates low-level details from high-level policies In this , we present how easy is to change the data layer without having to touch the business logic ( and modules). 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 and modules 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. pull request core usecases core usecases Moreover, it is much simpler for someone who joins the project to understand the domain of the application since the and modules 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 framework that might make the learning curve steeper. core usecases magic Clean Architecture is testable Due to the separation discussed in the previous section, it is straightforward to test the business logic of the application without having to setup any framework or library. We can write simple unit tests to test the complex business logic in our application without having to deal with the frameworks. Also, we don’t have to change these tests when we change something in a framework. Of course, we should have integration tests that ensure that everything is wired up correctly, but these costly tests will only be a few and will not increase when the complexity in our business logic is increased. Clean Architecture is not a silver bullet It is easy to notice that we have written way too much for the simple functionality that out application offers, even in a concise language like Kotlin. Clean Architecture requires some abstractions that might be considered as over-engineering if the application we are building is relatively simple. It might not feel natural to indirect the invocations to the data and the delivery layer in the beginning, but as we add new functionality to our system, our velocity is increased, since we separate pure domain code with frameworks and configurations. Clean Architecture, like every software architecture, comes with a cost, so it is up to the developers/architects to decide if they can benefit from it or not. Further Reading by “Clean Architecture: A Craftsman’s Guide to Software Structure and Design (Robert C. Martin Series” Robert C. Martin (Uncle Bob) The Clean Architecture Clean Architecture using Golang