Slide 1

Slide 1 text

SPRING MODULITH A DEEP DIVE Oliver Drotbohm odrotbohm@vmware.com odrotbohm

Slide 2

Slide 2 text

Coming in 2023… Follow @mawspring on

Slide 3

Slide 3 text

Introduction

Slide 4

Slide 4 text

Complexity …while the actual challenge is this. Most teams focus on that… 1.0 1.2 1.1 2.0

Slide 5

Slide 5 text

Understandability

Slide 6

Slide 6 text

Changeability

Slide 7

Slide 7 text

Functional Decomposition Encapsulation High Cohesion Low Coupling Modularity

Slide 8

Slide 8 text

A bit of Systems Theory…

Slide 9

Slide 9 text

Systems Thinking, Learning and Problem Solving Long version | Short version Russel L. Ackoff

Slide 10

Slide 10 text

"A system is a whole that consists of parts, each of which can affect its behavior and properties. … Each part of the system is dependent on some other part."

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

Put things together Pull things apart

Slide 13

Slide 13 text

Pull things apart

Slide 14

Slide 14 text

The System

Slide 15

Slide 15 text

The System Order Product Products Product details Prices Order Line items Customer Details Address Account

Slide 16

Slide 16 text

The System Order Product Products Product details Prices Order Line items Customer Details Address Account Auth PIM Pricing Invoicing Shipment

Slide 17

Slide 17 text

Artifact Process Bounded Context Module Logical Physical Package How do we map this … to that?

Slide 18

Slide 18 text

Monolith VS. Microservice Module A Module B Module C Module B Module C Module A Bounded Context Deployment Unit Internal invocation External invocation

Slide 19

Slide 19 text

Monolith VS. Microservice Module A Module B Module C Bounded Context Deployment Unit Internal invocation External invocation !"

Slide 20

Slide 20 text

Monolith The application packages the implementation of multiple Bounded Contexts as a single deployment unit. Easy to refactor Simple IDE features can be used to move significant parts of the codebase around and update all client code at the same time. Easy to test the overall system An overall test run is a matter of running a Spring (Boot) integration test.

Slide 21

Slide 21 text

Monolith 21 The application packages the implementation of multiple Bounded Contexts as a single deployment unit. Likely to degrade unless explicitly managed Unless explicit means of monitoring the structure are employed, the architecture will degrade over time. Harder to test individual Bounded Contexts Testing individual bounded contexts requires extra effort in setting up Spring configuration to make sure components can be picked up for each module individually.

Slide 22

Slide 22 text

Microservices A bounded context defines the boundaries of the deployment artifact. Often parts of the context are even deployed as separate processes. ○ Bounded Context interaction is remote The interaction between BCs involved remote interaction, either by sending messages or invoke other systems directly. This accumulates latency, and requires additional measures against the collaborators being unavailable which increases complexity. ○ Testing individual modules Testing individual modules usually requires collaborating systems to be bootstrapped, stubbed or mocked.

Slide 23

Slide 23 text

Microservices A bounded context defines the boundaries of the deployment artifact. Often parts of the context are even deployed as separate processes. Hard to refactor context boundaries Context boundaries are implemented as published APIs that have to be evolved carefully as clients cannot be updated to server changes immediately. Hard to test the overall system While testing an individual system usually works reasonably well, integration testing multiple systems together is complex and creates additional overhead.

Slide 24

Slide 24 text

Modular Architecture

Slide 25

Slide 25 text

Infrastructure Application Domain

Slide 26

Slide 26 text

Infrastructure Application Domain

Slide 27

Slide 27 text

Onion-/Hexagonal Architecture Modularization

Slide 28

Slide 28 text

Application Domain Infrastructure

Slide 29

Slide 29 text

Application Domain Infrastructure Application Domain Infrastructure

Slide 30

Slide 30 text

Domain Domain Domain Application Infrastructure

Slide 31

Slide 31 text

Application Domain Infrastructure

Slide 32

Slide 32 text

Application Domain Infrastructure

Slide 33

Slide 33 text

Domain Application Infrastructure Domain Application Infrastructure Domain Application Infrastructure

Slide 34

Slide 34 text

Infrastructure Infrastructure Domain Domain Domain Application Application Application Infrastructure

Slide 35

Slide 35 text

Infrastructure Infrastructure Domain Domain Domain Application Application Application Infrastructure

Slide 36

Slide 36 text

Module Module Module

Slide 37

Slide 37 text

The Domain

Slide 38

Slide 38 text

Orders Inventory Order Line items Stock Inventory items

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

Awesome! # Now… what? $

Slide 42

Slide 42 text

How do we represent functional architecture in a codebase? “

Slide 43

Slide 43 text

Let's get started… src/main/java ….acme.myproject ….acme.myproject.domain ….acme.myproject.persistence ….acme.myproject.service ….acme.myproject.web

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

Let's get started… src/main/java ….acme.myproject ….acme.myproject.domain ….acme.myproject.persistence ….acme.myproject.service ….acme.myproject.web %&

Slide 46

Slide 46 text

via https://devopedia.org/cohesion-vs-coupling

Slide 47

Slide 47 text

Domain Based Structure Domain Based Boundaries via Dan North – CUPID—for joyful coding Video cast episode @ Software Architektur im Stream (english)

Slide 48

Slide 48 text

Taking a domain-based approach to the code structure makes it easy to understand what the code is there for, and easy to navigate to wherever you need to be for anything more complicated than “make that button light blue”. Instead, the layout of code—the directory names, the relationships of child and sibling folders, the grouping and naming of related files—should mirror the problem domain as closely as possible. Domain-Based Structure Domain-Based Boundaries “ “ Source: Dan North, CUPID—for joyful coding

Slide 49

Slide 49 text

src/main/java ….acme.myproject ….acme.myproject.customer ….acme.myproject.inventory ….acme.myproject.order Much better… '#

Slide 50

Slide 50 text

via https://devopedia.org/cohesion-vs-coupling

Slide 51

Slide 51 text

Web Business logic Data access @Repository Order Inventory … @Controller @Service Verification? Testing? Documentation? Observation?

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

Sample code odrotbohm/arch-evident-spring events/230821-springone odrotbohm/spring-modulith-deep-dive main

Slide 54

Slide 54 text

Simple Application Modules

Slide 55

Slide 55 text

API Package Convention ….acme ….acme.moduleA ….acme.moduleB Application class goes here Logical modules

Slide 56

Slide 56 text

Some conventions… 01 10 M M 01 10 Allowed by the compiler Allowed by Moduliths Rejected by the compiler Rejected by Moduliths Public Package protected Bounded Context Java Package

Slide 57

Slide 57 text

Module B moduleB Module A moduleA 57 ComponentA ComponentAImpl ComponentB ComponentBImpl Public Package protected Bounded Context Java Package 01 10 01 10

Slide 58

Slide 58 text

package com.acme @SpringBootApplication class MyApplication { … } var modules = ApplicationModules.of(MyApplication.class); modules.verify(…); Applies package conventions Verifies rules for MyApplication

Slide 59

Slide 59 text

Lab time! (#

Slide 60

Slide 60 text

Complex Application Modules

Slide 61

Slide 61 text

Application Domain Infrastructure

Slide 62

Slide 62 text

Infrastructure Application Domain

Slide 63

Slide 63 text

Infrastructure Application Domain Primary (driving) Adapters @Controller @KafkaListener Spring beans Published events Event listeners Secondary (driven) Adapters Repositories Message publishers

Slide 64

Slide 64 text

Infrastructure Application Domain Primary (driving) Adapters @Controller @KafkaListener Spring beans Published events Event listeners Secondary (driven) Adapters Repositories Message publishers

Slide 65

Slide 65 text

API Package Convention 65 ….modulith ….modulith.moduleA ….modulith.moduleA.internal ….modulith.moduleB ….modulith.moduleB.internal Access to components residing in internal packages forbidden and checked during tests. API packages

Slide 66

Slide 66 text

Module A moduleA.foo Module B moduleB moduleA 66 ComponentA ComponentAImpl ComponentB ComponentBImpl moduleA.bar SupportA SupportAImpl 01 10 M 01 10 01 10 Public Package protected Bounded Context Java Package

Slide 67

Slide 67 text

Demo time! (#

Slide 68

Slide 68 text

Integration Testing

Slide 69

Slide 69 text

Web Business logic Data access @Data…Test Module A Module B Module C @WebMvcTest @…Test ?

Slide 70

Slide 70 text

Infrastructure Application Domain Primary (driving) Adapters @Controller @KafkaListener Spring beans Published events Event listeners Secondary (driven) Adapters Repositories Message publishers

Slide 71

Slide 71 text

Infrastructure Application Domain Primary (driving) Adapters @Controller @KafkaListener Spring beans Published events Event listeners Secondary (driven) Adapters Repositories Message publishers

Slide 72

Slide 72 text

Demo time! (#

Slide 73

Slide 73 text

Application Module Integration

Slide 74

Slide 74 text

Pull things apart

Slide 75

Slide 75 text

Put things together Pull things apart

Slide 76

Slide 76 text

Put things together

Slide 77

Slide 77 text

"A system is never the sum of its parts, it's the product of their interactions."

Slide 78

Slide 78 text

Orders Inventory Order Line Items Inventory Item Active invocation Bounded Context Legend Aggregate

Slide 79

Slide 79 text

Orders Inventory Order completed Event Events published to Bounded Context Legend

Slide 80

Slide 80 text

Demo time! (#

Slide 81

Slide 81 text

Error Scenarios Transactional Event Listeners

Slide 82

Slide 82 text

@EventListener @EventListener … @TransactionalEventListener @TransactionalEventListener … @Transactional Event Event Commit Consistency boundary Spring bean Legend

Slide 83

Slide 83 text

Error scenarios

Slide 84

Slide 84 text

What if the service fails? $

Slide 85

Slide 85 text

84 @EventListener @EventListener … @TransactionalEventListener @TransactionalEventListener … @Transactional Event Event Commit Consistency boundary Spring bean Legend )!

Slide 86

Slide 86 text

85 @EventListener @EventListener … @TransactionalEventListener @TransactionalEventListener … @Transactional Event Event Commit Consistency boundary Spring bean Legend Rollback! * )!

Slide 87

Slide 87 text

Application events – Error Scenarios The service fails Only standard event listeners up until the failure will have been executed. Assuming the already triggered event listeners also execute transactional logic, the local transaction is rolled back and the system is still in a strongly consistent state. Transactional event listeners are not invoked in the first place.

Slide 88

Slide 88 text

What if an event listener fails? $

Slide 89

Slide 89 text

88 @EventListener @EventListener … @TransactionalEventListener @TransactionalEventListener … @Transactional Event Event Commit Consistency boundary Spring bean Legend )!

Slide 90

Slide 90 text

89 @EventListener @EventListener … @TransactionalEventListener @TransactionalEventListener … @Transactional Event Event Commit Consistency boundary Spring bean Legend )! Rollback! *

Slide 91

Slide 91 text

Application events – Error Scenarios A synchronous event listener fails In case a normal event listener fails the entire transaction will roll back. This enables strong consistency between the event producer and the listeners registered but also bears the risk of supporting functionality interfering with the primary one, causing the latter to fail for less important reasons. The tradeoff here could be to move to a transactional event listener and embrace eventual consistency.

Slide 92

Slide 92 text

What if a transactional event listener fails? $

Slide 93

Slide 93 text

@EventListener @EventListener … @TransactionalEventListener @TransactionalEventListener … @Transactional Event Event Commit Consistency boundary Spring bean Legend )!

Slide 94

Slide 94 text

@EventListener @EventListener … @TransactionalEventListener @TransactionalEventListener … @Transactional Event Event Commit Consistency boundary Spring bean Legend Publication lost! " )!

Slide 95

Slide 95 text

Application events – Error Scenarios A transactional event listener fails In case a transactional event lister fails or the application crashes while transactional event listeners are executed, the event is lost and functionality might not have been invoked. Other transactional event listeners will still be triggered. BONUS: An asynchronous event listener fails The event is lost but the primary functionality can still succeed as the event is handled in a separate thread. Retry mechanisms can (should?) be deployed in case some form of recovery is needed.

Slide 96

Slide 96 text

Event Publication Registry

Slide 97

Slide 97 text

@TransactionalEventListener @TransactionalEventListener … Event @TransactionalEventListener … @TransactionalEventListener … Transaction Commit

Slide 98

Slide 98 text

@TransactionalEventListener @TransactionalEventListener … Event @TransactionalEventListener … @TransactionalEventListener … Transaction Commit

Slide 99

Slide 99 text

Demo time! (#

Slide 100

Slide 100 text

Documentation

Slide 101

Slide 101 text

Pace of change Level of detail Effort of manual work

Slide 102

Slide 102 text

Infrastructure Infrastructure Domain Domain Domain Application Application Application Infrastructure

Slide 103

Slide 103 text

No content

Slide 104

Slide 104 text

No content

Slide 105

Slide 105 text

Infrastructure Infrastructure Domain Domain Domain Application Application Application Infrastructure

Slide 106

Slide 106 text

Domain Application Infrastructure

Slide 107

Slide 107 text

Infrastructure Application Domain Primary (driving) Adapters @Controller @KafkaListener Spring beans Published events Event listeners Secondary (driven) Adapters Repositories Message publishers

Slide 108

Slide 108 text

My Component Provided Interface Exposed Service API Spring Beans available for DI Exposed Aggregates Primary elements of the domain and constraints Published events Events the component emits Required Interface Consumed Service API External dependencies of Spring beans Configuration Spring Boot configuration properties Consumed events Events that the component reacts to

Slide 109

Slide 109 text

No content

Slide 110

Slide 110 text

No content

Slide 111

Slide 111 text

Observability

Slide 112

Slide 112 text

No content

Slide 113

Slide 113 text

Splitting the Modulith

Slide 114

Slide 114 text

Module Module Module

Slide 115

Slide 115 text

Module Module Module

Slide 116

Slide 116 text

Module Module Module

Slide 117

Slide 117 text

Demo time! (#

Slide 118

Slide 118 text

Summary

Slide 119

Slide 119 text

Spring Modulith A convention to map modules to packages Simple set of access rules and API to verify Test support to bootstrap modules Event publication registry Documentation support Actuator and observability support

Slide 120

Slide 120 text

Spring Modulith Additional implementations of the Event Publication Registry Automatic externalization of events to Kafka, AMQP, potentially Redis

Slide 121

Slide 121 text

Resources Moduliths Project website on GitHub Majestic Modular Monoliths Video on Youtube Modular Monoliths Simon Brown – Video on YouTube Refactoring to a System of Systems Video on YouTube

Slide 122

Slide 122 text

Resources Software Architecture for Developers Simon Brown – Books Just Enough Software Architecture George Fairbanks – Book Architecture, Design, Implementation Ammon H. Eden, Rick Kazman – Paper Sustainable Software Architecture Carola Lilienthal – Book The Programmer's Brain Felienne Hermans – Book

Slide 123

Slide 123 text

Thank you! Questions? Oliver Drotbohm odrotbohm@vmware.com odrotbohm