All Projects → dustinsand → Hex Arch Kotlin Spring Boot

dustinsand / Hex Arch Kotlin Spring Boot

Licence: mit
Reference JVM multi module project for a reactive micro service and lambda using a hexagonal architecture, DDD, Kotlin, Spring Boot, Quarkus, Lambda, Gradle.

Programming Languages

kotlin
9241 projects

Projects that are alternatives of or similar to Hex Arch Kotlin Spring Boot

Trampoline
Admin Spring Boot Locally
Stars: ✭ 325 (+291.57%)
Mutual labels:  microservice, gradle, spring-boot, spring
Sample Boot Micro
Spring Cloud + Gradle Multi Project + Java8
Stars: ✭ 72 (-13.25%)
Mutual labels:  microservice, gradle, spring-boot, ddd
Webfluxtemplate
Spring Webflux template application with working Spring Security, Web-sockets, Rest, Web MVC, and Authentication with JWT.
Stars: ✭ 107 (+28.92%)
Mutual labels:  gradle, reactive, spring-boot, spring
Web Development Interview With Java
Java 开发相关技术栈(大中厂)高频面试问题收录。
Stars: ✭ 69 (-16.87%)
Mutual labels:  microservice, spring-boot, spring
App Engine
分布式App服务端快速开发框架
Stars: ✭ 313 (+277.11%)
Mutual labels:  gradle, spring-boot, spring
Spring Boot Webflux Jjwt
Example Spring Boot and WebFlux (Reactive Web) with Spring Security and JWT for token Authentication and Authorization
Stars: ✭ 71 (-14.46%)
Mutual labels:  reactive, spring-boot, spring
Atom
Java course materials
Stars: ✭ 293 (+253.01%)
Mutual labels:  gradle, spring-boot, spring
Spring Boot Angular2
spring boot backend, angular2 frontend with webpack, typescript, sass, bootstrap4, karma, jasmine
Stars: ✭ 396 (+377.11%)
Mutual labels:  gradle, spring-boot, spring
Ms Backend Boilerplates
Boilerplate for Your Server Side(Backend) Application, Java | Spring(Boot, Cloud) | Node.js(Express, Koa, Egg) | Go | Python | DevOps 💫 服务端项目模板
Stars: ✭ 394 (+374.7%)
Mutual labels:  gradle, spring-boot, spring
Okta Blog Archive
Okta Developer Blog
Stars: ✭ 74 (-10.84%)
Mutual labels:  gradle, spring-boot, spring
Problem Spring Web
A library for handling Problems in Spring Web MVC
Stars: ✭ 636 (+666.27%)
Mutual labels:  microservice, spring-boot, spring
Microservices Example
Example of a microservices architecture on the modern stack of Java technologies
Stars: ✭ 66 (-20.48%)
Mutual labels:  microservice, gradle, spring-boot
Mmorpg
springboot编写的轻量级高性能mmorpg手游服务端框架,基本功能逐渐完善中。
Stars: ✭ 309 (+272.29%)
Mutual labels:  gradle, spring-boot, spring
Micro Company
Rest-full, Hipermedia-based distributed application. Spring boot & cloud. Angular. CQRS. Eventsourcing. Axonframework. Microservices. Docker. CloudFoundry
Stars: ✭ 307 (+269.88%)
Mutual labels:  microservice, spring-boot, spring
Spring Data R2dbc
Provide support to increase developer productivity in Java when using Reactive Relational Database Connectivity. Uses familiar Spring concepts such as a DatabaseClient for core API usage and lightweight repository style data access.
Stars: ✭ 534 (+543.37%)
Mutual labels:  reactive, spring, ddd
Jbone
jbone基于Spring Cloud框架开发,旨在为中小企业提供稳定的微服务解决方案,为开发人员提供基础开发骨架,jbone包含微服务中所有常用组件,例如注册中心、服务管理、服务监控、JVM监控、内存分析、调用链跟踪、API网关等等。业务功能包括系统权限的统一管理、单点登录、CMS、电商平台、工作流平台、支付平台等等。
Stars: ✭ 961 (+1057.83%)
Mutual labels:  microservice, spring-boot, spring
Mini Platform
Mini-Platform致力于更简洁易用的轻量级微服务治理平台。
Stars: ✭ 45 (-45.78%)
Mutual labels:  microservice, spring-boot, spring
Quickperf
QuickPerf is a testing library for Java to quickly evaluate and improve some performance-related properties
Stars: ✭ 231 (+178.31%)
Mutual labels:  microservice, spring-boot, spring
Istio By Example Java
A collection of examples of using Istio with Java applications.
Stars: ✭ 242 (+191.57%)
Mutual labels:  microservice, spring-boot, spring
All Things Cqrs
Comprehensive guide to a couple of possible ways of synchronizing two states with Spring tools. Synchronization is shown by separating command and queries in a simple CQRS application.
Stars: ✭ 474 (+471.08%)
Mutual labels:  spring-boot, spring, ddd

Build Status

Hexagonal Architecture (aka Ports and Adapters) / Clean Architecture / DDD

Allow an application to equally be driven by users, programs, automated test or batch scripts, and to be developed and tested in isolation from its eventual run-time devices and databases.

As events arrive from the outside world at a port, a technology-specific adapter converts it into a usable procedure call or message and passes it to the application. The application is blissfully ignorant of the nature of the input device. When the application has something to send out, it sends it out through a port to an adapter, which creates the appropriate signals needed by the receiving technology (human or automated). The application has a semantically sound interaction with the adapters on all sides of it, without actually knowing the nature of the things on the other side of the adapters.”
Alistair Cockburn

Personally I've used hexagonal architectures with DDD for years because it aligns well with how I reason about designing applications. However, I'm not aware of a "standard" project structure for JVM microservices so this is my interpretation. If a canonical project structure exists, please let me know. I've seen a different interpretation of project structures from each engineer I've learned this architecture from.

Thank you to all the engineers who have shared their knowledge on this topic. If you are unfamiliar with this architecture, please review the references first. This project is my interpretation of how to design and implement a hexagonal architecture for the JVM.

Project Description

This project is used to show how the hexagonal architecture can be applied to a Microservice (Spring Boot) and a native AWS Lambda (Quarkus) in a multi module project. The multi module project allows for code re-use (each application re-uses the application core and the output adapters) across modules. The sample code is intentionally simple in order to focus on how to structure the packages for a hexagonal architecture and apply the concepts.

Objective Of This Architecture

  • Maintainable. Consistently structured software which is easy to understand, navigate and reason about.
  • Encourage a separation of concerns through layers of responsibility.
  • Evolutionary design. Easy to change, loosely coupled.
  • Platform Agnostic. Architecture can be used for applications developed for modern programming platforms such as the JVM, Go, .Net, Python, etc.
  • Independent of Frameworks. The architecture does not depend on a framework, freeing developers to use their frameworks of choice.
  • 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.
  • Modular. Minimizes tangled dependencies by decoupling the business logic from the technical code. Reduces the friction of extracting core domain objects to another context. Sometimes it makes design sense to start as more of a monolith and extract later to another context when there are strong reasons to do so.
  • Testable. The business rules can be tested without the UI, Database, Web Server, or any other external element.
  • Architecture is enforceable using tests so it remains clean over time as old and new developers work on the code base.
  • Clean Code. You will see influences from Clean code in the design.

Concepts

The hexagonal architecture conceptually consists of two parts: the Application Core, and the Ports and Adapters.

Outer layers depend on inner layers. Inner layers expose interfaces that outer layers must adapt to and implement. This form of dependency inversion protects the integrity of the domain and application layers. Outside the application layer, we have ports (Interfaces) and adapters (Implementations) that handle the technical delivery to the outside world. The adapters handle the technical delivery by using the application services in the domain layer.

Application Core

The inside of the hexagon contains the business logic and is unaware of the technologies used to implement the application. The business logic does not care if the application provides a REST API or a GraphQL API or whether the data is stored in a database or a file. The application core declares the ports that are needed to fulfill the use cases. The technical details of how the adapters implement the ports are not a concern of the application core.

Ports and Adapters

The ports (Interfaces) are at the inside edge of the hexagon, and they declare the requirements of the application to fulfill the use cases. Input ports allow different types of drivers to interface with the application core. Output ports allow different kinds of technologies to be driven by the application core.

The ports at the edge allow the design to be switched with other technologies without impacting the core of the application. For example, the application could be driven by a REST API or a GraphQL API using the same input ports while the application could drive storing the data in a relational database, or a file using the same output ports.

Adapters are at the outside edge of the hexagon, and are the implementation of the port using the technology of choice. For example, a REST API input adapter, or a PostgreSQL output adapter.

voter_hex_diagram lambda diagram

Gradle Multi-Module Project

Used Gradle's multi-module capability to demonstrate how a hexagonal project could be modularized. The modules are 99.9% in Kotlin, but there are edge cases when Java is required so you will find Kotlin and Java classes mixed together in the same src directory. I chose src/main/java and src/test/java for both the Kotlin and Java source files.

Modules

voter-application-core

The inner hexagon. See definition in 'How it works'

Package Structure

domain

Isolated from technical complexities of clients, frameworks and adapter (infrastructure) concerns. Contains the business models. Dependencies face inward so it does not depend on any layers outside of it. Why is this important? Adapters (Infrastructure) can be changed without changes to the domain.

The objects in this layer contain the data and the logic pertaining to the business. Independent of the business processes that trigger that logic, they are independent and completely unaware of the Application Layer.

The business objects that represent something in the domain. Examples of these objects are, first of all, Entities but also Value Objects, Enums and any objects used in the Domain Model.

The Domain Model is also where Domain Events “live”. These events are triggered when a specific set of data changes and they carry those changes with them. In other words, when an entity changes, a Domain Event is triggered and it carries the changed properties new values. These events are perfect, for example, to be used in Event Sourcing.

model

Using DDD this is where you define the Entities, Aggregates, Value Objects and Domain Events to model your domain.

Refer to the DDD tactical patterns for descriptions

service

Sometimes we encounter some domain logic that involves different entities, of the same type or not, and we feel that that domain logic does not belong in the entities themselves, we feel that that logic is not their direct responsibility.

So our first reaction might be to place that logic outside the entities, in an Application Service. However, this means that that domain logic will not be reusable in other use cases: domain logic should stay out of the application layer!

The solution is to create a Domain Service, which has the role of receiving a set of entities and performing some business logic on them. A Domain Service belongs to the Domain Layer, and therefore it knows nothing about the classes in the Application Layer, like the Application Services or the Repositories. In the other hand, it can use other Domain Services and, of course, the Domain Model objects.

Characteristics of a domain service are:

  • Domain services encapsulate domain logic and concepts that are not naturally modeled as value objects or entities in your model.
  • Domain services represent domain concepts; they are part of the ubiquitous language.
  • Domain services have no identity or state; their responsibility is to orchestrate business logic using entities and value objects.
  • Too many domain services can lead to an anemic domain model that does not align well with the problem domain.
  • Too few domain services can lead to logic being incorrectly located on entities or value objects. This causes distinct concepts to be mixed up, which reduces clarity.
application layer
port.input

This layer defines use case (application behavior) interfaces of the application.

port.output

This layer defines infrastructure interfaces implemented by the adapters so there is no coupling between domain layer and technical code.

service

The API representing the business use cases of the application. Dependent on the domain layer to orchestrate the business use cases and acts as a facade to the domain. The domain model can continue to evolve without impacting clients. This layer is also responsible for coordinating notifications to other systems when significant events occur within the domain.

Clients must adapt to the input defined by the API and also transform the output from the API into their own format. The application layer then acts as an anti-corruption layer, ensuring the domain layer stays unaffected by external technical details.

Example role of an Application Service to fulfill a use case:

  1. use a repository to find one or several entities
  2. tell those entities to do some domain logic
  3. and use the repository to persist the entities again

adapter-output

The outer hexagon containing a gradle module per adapter. Output adapters can be re-used by applications (microservice, lambda, cli). For example, voter-ms uses modules from adapter-output.

output (preferred 'out' for the name, but 'out' is a reserved word in Kotlin)

These are the outbound adapter technical details that the application uses (right side of diagram below in tan), for example, a database, a 3rd party APIs. These are needed to support the domain use cases.

voter-ms

The microservice is a composition of the voter-application-core and adapter-output modules.

adapter input layer

The adapter layer provides the technical capabilities of the application to be consumed, such as a UI, web services, messaging endpoints. It also provides the application the ability to consume external services such as databases, 3rd party services, logging, security and other bounded contexts. These are all technical details that should not directly affect the use case exposed and the domain logic of an application. Typically hexagonal architectures diagram the left side (see "in" below) for the the clients which use the domain. The right side (see "out" below) of the diagram are the services used by the domain.

input (preferred 'in' for the name, but 'in' is a reserved word in Kotlin)

The entry point (left side of diagram) of clients to use the application layer. The inbound adapter translates whatever comes from a client into a method call in the application layer.

voter-lambda

The lambda is a composition of the voter-application-core and adapter-output modules. It demonstrates:

  • how Spring beans declared in external modules (voter-application-core and adapter-output) can be used together with Quarkus
  • how a native binary can be created so there is no cold start latency cost when executed in AWS Lambda

adapter input layer

The adapter layer provides the technical capabilities of the application to be triggered by AWS Lambda.

input (preferred 'in' for the name, but 'in' is a reserved word in Kotlin)

The entry point (left side of diagram) of AWS Triggers to use the application layer. The inbound adapter translates whatever comes from a client into a method call in the application layer.

Targets

Run the tests

./gradlew clean test

Run the microservice

./gradlew clean :voter-ms:bootRun

Run the lambda

See the Lambda README

Communication Across Layers

When communicating across layers, to prevent exposing the details of the domain model to the outside world, you don’t pass domain objects across boundaries. For the same reasons, you don’t send raw, unchecked user input straight into the domain layer. Instead, you use simple data transfer objects (DTOs), presentation models, and application event objects to communicate changes or actions in the domain.

Testing in Isolation

Separating the concerns in the application and ensuring the domain logic is not dependent on any technical details allows you to test domain and application logic in isolation independent of any adapter frameworks.

The application layer is more appropriate for integration testing and the domain layer is more appropriate for unit testing with mocks.

Enforcing the Architecture

The architecture is at risk of eroding over time if boundaries between layers are not maintained. ArchUnit is used to check if the code follows the architecture. ArchUnit does so by analyzing the given Java bytecode, importing all classes into a Java code structure.

Kotlin added the keyword modifier, internal, to enforce component boundaries and overcome the weakness of package-private in Java. I liked the idea in the reference, Clean Boundaries, to be explicit and put "internal" classes in a package named internal which could then be enforced by ArchUnit. However, Kotlin doesn't support Package annotations so you will see the InternalPackage annotation is written in Java and the package-info.java in the "internal" packages are also in Java. I'm experimenting if this is a good idea or not with Kotlin because it does seem redundant since Kotlin has the internal modifier. However, I like that I can test for any class in an "internal" package is not used inappropriately (developers can still forget to use the internal modifier) and it guides the developer to use the dependency inversion principle.

ArchUnit’s main focus is to automatically test architecture and coding rules, using any plain Java unit testing framework. See src/test/java/.../HexagonalArchitectureTest.kt and InternalPackageTest.kt for the rules checked.

TL;DR Show me a diagram

The references have great example diagrams to visually explain how the components fit together so no point reinventing the wheel here. Herberto Graca has a diagram which is one of my favorites showing all the components together.

herbertograca_hex_diagram

References

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].