Meetups microservice, applying tactical DDD building blocks and in a real example.

Overview

Meetups microservice: Applying tactical DDD

Description

This project is a practical example to understand the tactical patterns/building-blocks that domain-driven design provides at code level.

In addition to that, it brings a full tested and production ready microservice that could be used as a blueprint to develop services with DDD and hexagonal architecture.

Keywords: Tactical DDD, microservice, kotlin, Quarkus, Hexagonal-Architecture, SOLID, Domain-Driven Design, functional-programming, Testing, Event-Driven Architecture, Domain-Events, Kafka, PostgreSQL, Transactional-outbox, jdbi, optimistic-locking

The problem to solve

To drive all the project, we need a problem to solve, in this case we will get inspiration from the famous meetup platform.

The basics are:

  • As a host, I should be able to create a Meetup to talk about some topic at some date in the future
  • If I get sick, as a host, I would like to cancel it ;-)
  • We can add attendants to the meetups
  • Meetups can be in-place somewhere or online in any platform
  • Once a meetup has finished, an attendant can rate it
  • Meetings can be part of a group
  • Groups could have members
  • Both group and meetups should have limitations on text sizes

We will model these business constraints using DDD tactical patterns to structure our solution around the business.

In addition, this project will use Hexagonal Architecture as an architectural style and functional programming principles.

Building blocks

  • Aggregates are a cluster of objects that acts as a single unit, each aggregate has:

    • Root: single entity that follow some rules such as:
      • All business operations should go through it
      • As the name suggest, is in the root of the objects tree, therefore it should control the access to its child
      • Keeps everything inside in a consistent state ensuring the integrity of their invariants
      • Is the basic element of data storage, either you load or save it as a whole
    • Boundary: that defines what is inside and:
      • Has a global identity, the root, and any entity inside has a local identity
      • Nothing outside the aggregate boundary can hold a reference to anything inside, except for the aggregate root
      • Objects inside the boundary could hold references to other aggregates, preferable weak references (ids)
  • Entities are objects defined is defined by their identity, independently of the value of their properties. Usually, their state could change during their lifecycle. For example, a Person, it could be identified by their doc id, but they will change during their life in many ways.

  • Value Objects are immutable types and their equality is defined by all their properties together. Examples of VO could be a Currency, Address or UserId. A subset of Values objects are called:

    • Tiny types: A very lightweight value object with only one value, wrapping a primitive type.
  • A Factory encapsulates:

    • Creation: the creation of an aggregate, ensuring the integrity of it.
    • Reconstitution: At some point, most of the objects got stored somewhere, factories should be the point to reassemble it when the object is retrieved.

    Note: A factory could be just a constructor, a function or a separate object when the creation is complex.

  • Commands are requests for changes in an aggregate, they could be just methods in the root or objects themselves.

  • Domain events are triggered when an aggregate changes and is important from business perspective, they are the way to notify other aggregates or systems about changes.

  • Repositories are abstractions that allow us to load and store our aggregates without knowing about datasource impl details under the hood.

Important: All these patterns talk business domain, they should be decoupled from the external world and shouldn't be polluted with infrastructure concerns such as persistence libraries, dtos from outside the domain, http concerns, messaging platforms and so on.

The Meetup model

Usually microservices are around one aggregate, but in this case the MS is going to handle two, potentially the service could be split up if necessary:

Wait ... where are commands, domain events and repositories? Or even more, what about other external dependencies like other services, queues, streams, logs or metrics? where are they fitting?

We have an amazing and clean domain, easy, right? But a real world application needs to be operative, it means that we would need to:

  • Expose entry-points to communicate with our domain, such as http, streams or grpc
  • Store our aggregates in a datastore
  • Call other services that we can depend on
  • Perform other side effects like write logs, send metrics or publish events

That's when we need an architectural style to support these different concerns in a structured way and decouple our domain operations, right? take a look on the next section.

Hexagonal architecture

Hexagonal architecture is an architectural style that fits perfectly for domain isolation, hence, for DDD projects.

Here an example of how a simple business use-case looks like:

Hexagonal introduces a chassis for our app, a way by which we can organise our code and do a proper separation of concerns.

Package structure

  • Application: Application Services (the use cases of our app)
  • Domain: Domain model and ports.
  • Infrastructure: Adapters, configuration and infrastructure code.

Accessing to the meetups: Queries

If you take a look in the application service layer you will see that there are no use-cases to access to the aggregates. This is done in purpose in order to:

  • Empower async microservices approach.
  • Separate writes (business operations on our aggregates) from reads (just projections/views of them).
  • Don't pollute our aggregates with view information at persistence level such as foreign keys or extra info to be queried.

Our microservice is publishing events about all the lifecycle, if a client wants to get either a meetup or a group, they would need to subscribe to the stream and replicate the information.

Anyways, if for any reason you want to expose synchronous endpoints, there are several ways:

  • CQRS way: create a separate project or module, listen to the events and create proper read models to be queried (views)
  • Query handlers: Create query handlers, similar to use cases with a different meanings, just aggregate information and present views models
  • Access repositories in the controllers: Access repositories right away, is a view a business concern?
  • Just another use-case: treat queries/reads as another use-case more, keeping consistency in the project.

Events

Messaging patterns

In order to avoid dual writes the project uses a couple of patterns:

Domain events

A Domain-event is something that happened in the domain that is important to the business.

This service advocates for asynchronous communication instead of exposing endpoints to be consumed by clients. To do so , since the service uses also domain-driven design tactical patterns, all use-cases are producing domain-events: Domain events

Integration events

An integration event is a committed event that ocurred in the past within a bounded context which may be interesting to other domains, applications or third party services, so it is the sibling of a domain event but for the external world.

Why not to publish our domain events directly? We can not publish our domain events directly for several reasons:

  • Back-ward compatibility: We should provide a way to maintain backward compatibility, if we were publishing our domain events we would couple them to the external contracts.
  • Different schema for messages: In almost all the companies using event-driven these messages are defined in a different schema such as avro, protobuf or json schema.
  • We don't want to publish all domain-events: Sometimes we don't want to publish to our consumers all our internal domain events.

Here the contracts

Error Handling

This project uses a mixed approach to handle errors:

  • Domain errors: Domain errors are always returned for any meaningful error interesting for the consumer that they can recover from. Domain errors are wrapped using Either monads.
  • Exceptions: Let the application crash for uncontrolled errors such as framework exceptions, timeouts, sql exceptions or any infrastructure error that the consumer can not recover from and deal with them at the boundary of the app.

Resources

You might also like...
Account-hexa-service-kotlin - Microservice with Kotlin using Hexagonal architecture

Microservice Construindo microservice de conta para fins Didáticos. Objetivos Cr

Kotlin-ES-CQRS-Microservice

Kotlin Spring Reactive EventSourcing and CQRS with PostgreSQL, Kafka, MongoDB, tracing and monitoring 👋 ✨ 💫 👨‍💻 Full list what has been used: Spri

🎓 Learning Kotlin Coroutines for Android by example. 🚀 Sample implementations for real-world Android use cases. 🛠 Unit tests included!
🎓 Learning Kotlin Coroutines for Android by example. 🚀 Sample implementations for real-world Android use cases. 🛠 Unit tests included!

Kotlin Coroutines - Use Cases on Android 🎓 Learning Kotlin Coroutines for Android by example. 🚀 Sample implementations for real-world Android use ca

A webapp which generates a simple Discord profile banner image in real-time which shows user's status and activity.

DiscordProfileBanner This tool generates a Discord profile banner image in realtime. I wrote it for use in my AniList profile. An example in action: H

Task Manager feat. real-time competitive system and user engagement
Task Manager feat. real-time competitive system and user engagement

Dira Что из себя представляет Dira? Android-приложение Directa (сокр. Dira) - это планер, который способен улучшить жизнь пользователей. Он позволяет

An Android app that scans images or human faces in real time and detects whether the mask is worn or not, with the ability to set an audible alert
An Android app that scans images or human faces in real time and detects whether the mask is worn or not, with the ability to set an audible alert

Swift Mask Real time face mask detection Brief overview Swift Mask scans images or human faces in real time and detects whether the mask is worn or no

EduApp is a mini e-learning platform based on udemy's public api. It has 4 main navigation destinations (Home, Search, Wishlist, Cart). Users can search courses from different categories and get real-time results from the api using Chips for a smooth filtering experience. It has different theme for dark mode. Android Project to find FatMax in real time with a Polar H10
Android Project to find FatMax in real time with a Polar H10

FatMaxxer According to recent research (see below) the FatMaxxer Android app may help you to exercise at the optimum effort level for fat burning, mea

sample project that shows you how you can use Ktor to creat a server for real Project.

Ktor-Sample This is a sample project that shows you how you can use Ktor to creat a server for real Project. What is done Save data to database (Get a

Owner
Albert Llousas Ortiz
@N26
Albert Llousas Ortiz
Learning Project (Story App) For Applying Android Architecture Components And Clean Architecture Using MVVM With Kotlin

Learning Project (Story App) For Applying Android Architecture Components And Clean Architecture Using MVVM With Kotlin. Implemented by Clean Architecture, Hilt, MVVM, LiveData, Coroutines, Retrofit2, Glide

Samad Talukder 4 Sep 27, 2022
Muhammad Valian Masdani 2 Jul 5, 2022
Screencast using Minecraft blocks using Minestom

BlockScreen ??️ Usage Note: This can only be used locally, servers generally don't have capturable screens First, download the latest jar, then to sta

emortal 3 May 4, 2022
Kafka Streams Processor to unwrap CØSMOS blocks into CØSMOS transactions

Kafka Processor CØSMOS-Block A Kafka Streams Processor to unwrap CØSMOS blocks into CØSMOS transactions. Purpose The Kafka Processor CØSMOS-Block is b

OKP4 – Open Knowledge Protocol For 4 Dec 15, 2022
FirestoreCleanArchitectureApp is an app built with Kotlin and Firestore that displays data in real-time using the MVVM Architecture Pattern. For the UI it uses Jetpack Compose, Android's modern toolkit for building native UI.

FirestoreCleanArchitectureApp FirestoreCleanArchitectureApp is an app built with Kotlin and Cloud Firestore that displays data in real-time using Andr

Alex 66 Dec 15, 2022
Collection of Rewrite Recipes pertaining to the JHipster web application & microservice development platform

Apply JHipster best practices automatically What is this? This project implements a Rewrite module that applies best practices and migrations pertaini

OpenRewrite 5 Mar 7, 2022
🐹 Kotlin microservice to aid slash command creation for Nino.

slash-commands ?? .Kotlin microservice to aid slash command creation for Nino. More of this README will be fixed up once the first release is here. Li

Nino 5 Oct 1, 2021
Créer un microservice avec Spring Boot et Kotlin

?? Créer un microservice avec Spring Boot et Kotlin Ce dépôt contient les slides et la démo du talk "créer un microservice avec Spring Boot et Kotlin"

François Delbrayelle 0 Nov 28, 2021
Microservice kotlin micronaut

Arquitetura de Microserviços Instruções Criando rede no docker: docker network c

null 1 Dec 25, 2021
Microservice-arch - Basic micro service architecture using spring boot

Readme 4 applications are created: discovery-service: every application register

Melvin Zottola 1 Jan 8, 2022