Slide 1

Slide 1 text

MODELING COMPLEXITY USING MODULARIZATION AND BOUNDED CONTEXTS IN DDD LEMİ ORHAN ERGİN co-founder, craftgate

Slide 2

Slide 2 text

Reference: https://www.reddit.com/r/notinteresting/comments/8l4pct/man_decides_to_keep_box_of_cables

Slide 3

Slide 3 text

everything starts with keeping one 
 unused cable from an unknown gadget THE START

Slide 4

Slide 4 text

at the beginning, the order and 
 entropy is under control THE HONEYMOON

Slide 5

Slide 5 text

then with every new adapter and 
 cable, entropy increases and chaos starts THE INEVITABLE CLUTTER

Slide 6

Slide 6 text

Might work for a while but lead to frustration later Hard to find the right cable you need Sometimes we connect wrong cables to wrong adapters Requires time and patience to simplify the clutter At some point, we pour the box and reorganize all the cables Throwing the box away completely would also be a solution

Slide 7

Slide 7 text

THE START Java Spring Boot Hibernate Postgres

Slide 8

Slide 8 text

THE HONEYMOON Java Spring Boot Hibernate Postgres Gradle Kafka Lombok

Slide 9

Slide 9 text

Java Hibernate Postgres Gradle Kafka Unit Tests Lombok Kubernetes Integration Tests Feign Client Docker Jenkins Sonar MongoDB JWT React Prometheus Grafana Elastic Search Object Mapper Actuator Open API Swagger Config Server Euroka Kotlin Groovy Spring Cloud JPA Go Node Kibana Mockito THE REALITY Spring Boot

Slide 10

Slide 10 text

Java Hibernate Postgres Gradle Kafka Unit Tests Lombok Kubernetes Integration Tests Feign Client Docker Jenkins Sonar MongoDB JWT React Prometheus Grafana Elastic Search Object Mapper Actuator Open API Swagger Config Server Euroka Kotlin Groovy Spring Cloud JPA Go Node Kibana Mockito Spring Boot the implementation of 
 customers’ needs THE REALITY Where is the business logic?

Slide 11

Slide 11 text

Java Hibernate Postgres Gradle Kafka Unit Tests Lombok Kubernetes Integration Tests Feign Client Docker Jenkins Sonar MongoDB JWT React Prometheus Grafana Elastic Search Object Mapper Actuator Open API Swagger Config Server Euroka Kotlin Groovy Spring Cloud JPA Go Node Kibana Mockito Spring Boot scattered somewhere in the code THE REALITY Where is the business logic?

Slide 12

Slide 12 text

Where is the business logic? where are the layers ? what are the features ? where is the business logic ? Where should we test ? THE REALITY

Slide 13

Slide 13 text

Might work for a while but lead to frustration later Hard to find the right cable you need Sometimes we connect wrong cables to wrong adapters Requires time and patience to simplify the clutter At some point, we pour the box and reorganize all the cables Throwing the box away completely would also be a solution place to update the code grow the codebase the codebase stop adding new features and refactor Deleting legacy code and rewriting dependencies

Slide 14

Slide 14 text

BLOATED SERVICES IS LIKE 
 OVERLOADED PLUGS every new feature 
 is added like a patch

Slide 15

Slide 15 text

Repository One use case, one feature 
 all well defined implementation Payment 
 Service

Slide 16

Slide 16 text

Repository new use cases need new functionality 
 added to the same service same repository is enlarged to 
 fulfill the requirements of all use cases 
 and reused the existing ones Payment 
 Service

Slide 17

Slide 17 text

Payment 
 Service Repository Repository it’s time to split the functionality payment service is growing gradually

Slide 18

Slide 18 text

Repository Repository Service Repository Time to split payment service, but still dependent to it New use cases are comming Payment 
 Service

Slide 19

Slide 19 text

Rest Client Event Publisher Soap Client Repository Repository Manager Service Service Repository the dead end 
 of complexity Payment 
 Service Service Service Service Service Repository Repository Repository Repository

Slide 20

Slide 20 text

Complexity is the degree of difficulty in sustaining quality, maintainability, speed, cognitive load, 
 and development. that is what kills the sustainable growth

Slide 21

Slide 21 text

Adding new features becomes harder and harder in time Complexity rises till the dead end You either redesign or rewrite to continue adding new features Adding new people to the team makes the progress slower Microservices transformation projects usually aim to fix these kinds of legacy projects THE IMPACT OF 
 COMPLEXITY AS USUAL Feature 
 Count Time Growth 
 Limit Growth 
 Limit let’s split it into 
 microservices we need to 
 rewrite it again Difficulty Level 
 While Adding 
 New Features Time refactor 
 redesign 
 zone Growth 
 Limit Growth 
 Limit the increase in endurance level is due to the new senior endurance level: 
 do not touch 
 if it works transfor- 
 mation 
 project 
 zone go-live 
 night

Slide 22

Slide 22 text

Feature 
 Count Time Difficulty Level 
 While Adding 
 New Features Time THE IMPACT OF 
 MANAGABLE 
 COMPLEXITY aka. SUSTAINABLE GROWTH No need for big redesigns or rewrites, refactoring is enough Refactoring should be continuous The system should be open to extension and close to modification Adding new people to the team has a positive impact No direct need for microservices

Slide 23

Slide 23 text

Source code is the real software design. Designing software is an exercise in 
 What is Software Design? The C++ Journal Vol. 2, No. 2. 1992 http://user.it.uu.se/~carle/softcraft/notes/Reeve_SourceCodeIsTheDesign.pdf Reference: Jack W. Reeves Author of the "(B)leading Edge" column for the publication C++ Report “ managing complexity.

Slide 24

Slide 24 text

The critical complexity of most software projects is in understanding the business domain itself. “Interview With Eric Evans; Why DDD Matters Today” Dec 20, 2006 http://www.infoq.com/articles/eric-evans-ddd-matters-today Reference: Eric Evans Author of the "Domain-Driven Design: Tackling Complexity in Software" “

Slide 25

Slide 25 text

Managing complexity for sustainable growth Otel-imiz-in karşı-sın-da-ki dükkan-da gör-dü-ğüm bir elbise-yi dene-mek iste-r-im needs a paradigm shift like the difference between 
 structure in English and Turkish Unlearn what you’ve known so far and Relearn with no biases and limits

Slide 26

Slide 26 text

Microservices Programming in Go, Rust Using Kafka or MongoDB Spring Boot, Frameworks Cloud Engineering Event-based architecture Distributed systems Scrum, Kanban, etc. Story point estimations Packaging by infrastructure Dependency Injection Having modules anywhere These may decrease complexity but not enough for sustainable growth

Slide 27

Slide 27 text

Having modules everywhere makes your software modular but it may not achieve 
 sustainable growth

Slide 28

Slide 28 text

SEPARATION 
 OF CONCERNS INFORMATION HIDING PRINCIPLE INVERSION OF CONTROL PRINCIPLE DEPENDENCY INVERSION PRINCIPLE COUPLING COHESION sustainable growth The mentality behind modularization, i.e. the principle of “Separation of Concerns” - Edsget W. Dijkstra 1 Know The Fundamentals Details can be found in my talk: Modular Architecture For Pragmatic Developer 
 https://speakerdeck.com/lemiorhan/modular-architecture-for-pragmatic-developers PRINCIPLES

Slide 29

Slide 29 text

sustainable growth Focus on how modules communicate rather than what internal properties and behaviors should be. - Alan Kay 2 Focus on Modules & Communication Details can be found in my talk: Unlearn OOP 
 https://speakerdeck.com/lemiorhan/unlearn-oop-deleted-scenes-misconceptions-unspoken-truths OBJECT 
 ORIENTED 
 PROGRAMMING PRINCIPLES

Slide 30

Slide 30 text

sustainable growth SOLID principles are about managing dependencies and limiting the impact of change. - Robert C. Martin 3 Learn How to Manage Dependencies Details can be found in my talk: It’s Not SOLID Anymore 
 https://speakerdeck.com/lemiorhan/it-is-not-solid-anymore DESIGN 
 PRINCIPLES PRINCIPLES

Slide 31

Slide 31 text

sustainable growth The timeless goal of software engineering has been to separate code rather than change frequently from stable code. - James Coplien 4 Protect Business Logic from Poisoning Details can be found in my talk: Growing Hexagonal Microservices with TDD 
 https://speakerdeck.com/lemiorhan/growing-hexagonal-microservices-by-tdd HEXAGONAL 
 ARCHITECTURE APPROACH

Slide 32

Slide 32 text

sustainable growth Adding a new test to the system should be adding a new behavior rather than adding a method or class. - Ian Cooper 5 Test Really What Matters: Behaviors Details can be found in my talk: Unlearn Unit Testing 
 https://speakerdeck.com/lemiorhan/unlearn-unit-testing UNIT TESTING APPROACH

Slide 33

Slide 33 text

sustainable growth No rules are universal, rules need context - Dave Thomas 6 Focus on Contexts, Build Rules Around Details can be found in my talk: Pure Agile 
 https://speakerdeck.com/lemiorhan/pure-agile-building-a-culture-without-scrum-kanban-and-xp-extended-version-v22-dot-11 AGILE IS DEAD 
 LONG LIVE AGILITY APPROACH there are no rules in software, there are patterns. The critical part is deciding which patterns to use

Slide 34

Slide 34 text

sustainable growth Use cases are sequences of tasks toward a goal, context represents use cases, one per use case - James Coplien 7 Put Bricks on the Wall One-by-One Details can be found in my talk: Domain Driven Modular Architecture 
 https://speakerdeck.com/lemiorhan/domain-driven-modular-architecture USE CASE DRIVEN APPROACH DESIGN

Slide 35

Slide 35 text

sustainable growth If your model is telling a story, the modules are chapters. It isn’t just code being divided into modules, but concepts. 
 - Eric Evans 8 Shape Software based on Contexts BOUNDED CONTEXT DOMAIN DRIVEN DESIGN Details can be found in my talk: Domain Driven Modular Architecture 
 https://speakerdeck.com/lemiorhan/domain-driven-modular-architecture DESIGN

Slide 36

Slide 36 text

8 Shape Software based on Contexts DESIGN 7 Put Bricks on the Wall One-by-One 6 Focus on Contexts, Build Rules Around 5 Test Really What Matters: Behaviors 4 Protect Business Logic from Poisoning APPROACH Modularity & Sustainable Growth 3 Learn How to Manage Dependencies 2 Focus on Modules & Communication 1 Know The Fundamentals PRINCIPLES

Slide 37

Slide 37 text

DESIGN BOUNDED CONTEXT DOMAIN DRIVEN DESIGN USE CASE DRIVEN APPROACH UNIT TESTING HEXAGONAL 
 ARCHITECTURE AGILE IS DEAD 
 LONG LIVE AGILITY APPROACH SEPARATION 
 OF CONCERNS INFORMATION HIDING PRINCIPLE INVERSION OF CONTROL PRINCIPLE DEPENDENCY INVERSION PRINCIPLE COUPLING COHESION OBJECT 
 ORIENTED 
 PROGRAMMING DESIGN 
 PRINCIPLES PRINCIPLES

Slide 38

Slide 38 text

Let’s build a payment API start from the beginning…

Slide 39

Slide 39 text

Represent the model as how the business sees them that is where concepts 
 find their meanings, people speak the same language and share the same concerns CARD PAYMENT CONTEXT

Slide 40

Slide 40 text

Any info in the model can change at any time, that’s chaos. 
 We need to control the change! CARD PAYMENT CONTEXT

Slide 41

Slide 41 text

An aggregate defines consistency boundaries, everything inside (i.e. the data) needs to be always consistent An aggregate is just a construct to organize business rules Aggregate is a unit for the purpose of data changes CARD PAYMENT CONTEXT

Slide 42

Slide 42 text

Each aggregate has a root and a boundary Aggregate Root is the facade representing the whole structure, and it is the gateway. It enforces the aggregate's business/consistency rules References to aggregate internals from the outer world are strictly forbidden CARD PAYMENT CONTEXT

Slide 43

Slide 43 text

AGGREGATE BUSINESS RULES DOMAIN MODEL CONTEXT TRANSACTIONAL AND LINGUISTIC BOUNDARY INPUT OUTPUT Each BC is loosely coupled & independent and has its own ubiquitous language, own data, and an explicit owner. We split software into BCs, like microservices. Unlike modules, which are organized primarily around technical concerns, BCs are organized around business concerns. is it a realization of Moduliths ?

Slide 44

Slide 44 text

CONTEXT A CONTEXT B CONTEXT C CONTEXT D Context Map includes a high-level view of the domains involved, along with the relationships and interactions between them communication patters used in 
 microservices are applicable here Relationship Models Customer-Supplier Conformist Partneship Anti-Corruption Layer Separate Ways Open-Host Service Shared Kernel

Slide 45

Slide 45 text

The communication strategy between bounded contexts defines how extensible your software is Different than relationship models Strategies Chained - Unchained Transactional - Non-Transactional CONTEXT A CONTEXT B CONTEXT C CONTEXT D

Slide 46

Slide 46 text

CREATE USER NOTIFY CUSTOMER SAVE OUTBOX CREATE USER 
 USE CASE USER CREATED 
 MESSAGE USER CREATED 
 MESSAGE OUTBOX SAVED 
 MESSAGE CUSTOMER NOTIFIED 
 MESSAGE CHAINED SYNC SYNC

Slide 47

Slide 47 text

CREATE USER NOTIFY CUSTOMER SAVE OUTBOX CREATE USER 
 USE CASE USER CREATED 
 MESSAGE USER CREATED 
 MESSAGE OUTBOX SAVED 
 MESSAGE CUSTOMER NOTIFIED 
 MESSAGE UN-CHAINED ASYNC ASYNC

Slide 48

Slide 48 text

CREATE USER NOTIFY CUSTOMER SAVE OUTBOX CREATE USER 
 USE CASE USER CREATED 
 MESSAGE OUTBOX SAVED 
 MESSAGE CUSTOMER 
 NOTIFIED 
 MESSAGE TRANSACTIONAL SINGLE TRANSACTION One exception triggers rollbacking of all previous operations in multiple contexts

Slide 49

Slide 49 text

CREATE USER NOTIFY CUSTOMER SAVE OUTBOX CREATE USER 
 USE CASE USER CREATED 
 MESSAGE OUTBOX SAVED 
 MESSAGE CUSTOMER 
 NOTIFIED 
 MESSAGE NON-TRANSACTIONAL TRANSACTIONAL TRANSACTIONAL TRANSACTIONAL

Slide 50

Slide 50 text

MANAGING THE LEVEL OF 
 HOW DEPENDENT BOUNDED CONTEXTS TO EACH OTHER thinking in communicating objects?

Slide 51

Slide 51 text

We want to avoid having to change the source code and then rebuild the system every time you make these shifts Two patterns closely related with each other to achieve this A. Configurable Connection Pattern B. Configurable Dependency Pattern https://alistaircockburn.com/Configurable%20Connection%20Configurable%20Dependency.pdf

Slide 52

Slide 52 text

Configurable Connection Pattern Configurable Dependency Pattern Sender does not depend on any receiver. It’s like polymorphism from OOP. Sender has a source-code dependency 
 on the receiver. SENDER RECEIVER 1 RECEIVER 2 RECEIVER3 sender’s provided interface sender’s required interface RECEIVER 
 CONTRACT Sender asks the configurator which receiver 
 to use, like in dependency lookup. Sender contains a hard-coded reference to 
 the configurator. We avoid hard-coding the names of classes 
 on which we depend in our code. Sender has a source-code dependency on 
 the configurator. SENDER RECEIVER 1 RECEIVER 2 RECEIVER3 RECEIVER 
 CONTRACT CONFIGURATOR CONFIGURATOR CONFIGURATOR B application 
 context spring SENDER RECEIVER 1 RECEIVER 2 RECEIVER3 sender’s provided interface sender’s required interface RECEIVER 
 CONTRACT CONFIGURATOR Configurator tells the sender what receiver 
 to use, like in dependency injection. Receiver is held in sender in a local variable. It is set the receiver during execution, or 
 at initialization. Sender still has a source-code dependency 
 on the receiver. A spring

Slide 53

Slide 53 text

Configurable Connection Pattern C spring Only one configurator exists & sender calls 
 it via static methods. Receivers register themselves at initialization 
 to the configurator. Configurator knows which receiver to select. Sender has no source-code dependency. SENDER RECEIVER 1 RECEIVER 2 RECEIVER3 RECEIVER 
 CONTRACT CONFIGURATOR CONFIGURATOR CONFIGURATOR the new approach publisher Sender asks the configurator which receiver 
 to use, like in dependency lookup. Sender contains a hard-coded reference to 
 the configurator. We avoid hard-coding the names of classes 
 on which we depend in our code. Sender has a source-code dependency on 
 the configurator. SENDER RECEIVER 1 RECEIVER 2 RECEIVER3 RECEIVER 
 CONTRACT CONFIGURATOR CONFIGURATOR CONFIGURATOR B application 
 context spring SENDER RECEIVER 1 RECEIVER 2 RECEIVER3 sender’s provided interface sender’s required interface RECEIVER 
 CONTRACT CONFIGURATOR Configurator tells the sender what receiver 
 to use, like in dependency injection. Receiver is held in sender in a local variable. It is set the receiver during execution, or 
 at initialization. Sender still has a source-code dependency 
 on the receiver. A spring

Slide 54

Slide 54 text

C spring Only one configurator exists & sender calls 
 it via static methods. Receivers register themselves at initialization 
 to the configurator. Configurator knows which receiver to select. Sender has no source-code dependency. SENDER RECEIVER 1 RECEIVER 2 RECEIVER3 RECEIVER 
 CONTRACT CONFIGURATOR CONFIGURATOR CONFIGURATOR the new approach publisher CONFIGURATOR: MESSAGE PUBLISHER SENDER RECEIVER: USE CASE HANDLER

Slide 55

Slide 55 text

RECEIVER: USE CASE HANDLER Use case handlers are injected by Spring into the registry, which is accessed by Message Publisher to submit messages HANDLER REGISTRATION Receivers are extended by MessageHandlers not only for being detected by Spring, and also for providing base “handle method” infrastructure STEP 1

Slide 56

Slide 56 text

RECEIVER: USE CASE HANDLER Use case handlers return Aggregate Roots (if required) since it is the gateway for data change USE CASE HANDLING Use case handlers trigger “publishMessages” after handling is completed STEP 2

Slide 57

Slide 57 text

Bounded contexts do not know which bounded contexts are connected with which strategy. That makes every bounded context independent. DEFINING COMMUNICATION STRATEGIES STEP 3 SYNC SINGLE 
 TRANSACTION

Slide 58

Slide 58 text

Java library for building loosely-coupled bounded contexts https://github.com/craftgate/craftgate-modulith-messaging Supports loosely coupled, real-time dependency strategy to bounded contexts Supports aggregate roots and domain events Supports use-case driven approach and hexagonal architecture Supports transactional flows among aggregates Supports sync and async call chains between bounded contexts Contains unit tests for the API and acceptance tests for checking possible flows Detailed documentation describing why we need that & how it works Actively being used in production craftgate-modulith-messaging

Slide 59

Slide 59 text

HOW MODULARITY LOOKS LIKE?

Slide 60

Slide 60 text

THE SHAPE OF MODULARITY Each module is self-contained, with well- defined input/output interfaces Each module hides implementation details and exposes a high-level contract Each module handles multiple use cases directly related to user needs Each module extends by one use case at a time, no bloating experienced Each module is loosely coupled and highly coherent

Slide 61

Slide 61 text

WE ARE 
 HIRING speakerdeck.com/lemiorhan twitter.com/lemiorhan lemi orhan ergin co-founder mail: [email protected] CRAFTGATE one-stop shop payment gateway payment hub for your virtual poses with dynamic pos routing, you always pay the lowest commission to banks craftgate.io @craftgateio