Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Modeling Complexity: Using Modularization and Bounded Contexts in Domain Driven Design

Modeling Complexity: Using Modularization and Bounded Contexts in Domain Driven Design

Lemi Orhan Ergin

May 06, 2023
Tweet

More Decks by Lemi Orhan Ergin

Other Decks in Technology

Transcript

  1. then with every new adapter and 
 cable, entropy increases

    and chaos starts THE INEVITABLE CLUTTER
  2. 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
  3. 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
  4. 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?
  5. 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?
  6. Where is the business logic? where are the layers ?

    what are the features ? where is the business logic ? Where should we test ? THE REALITY
  7. 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
  8. 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
  9. Payment 
 Service Repository Repository it’s time to split the

    functionality payment service is growing gradually
  10. Repository Repository Service Repository Time to split payment service, but

    still dependent to it New use cases are comming Payment 
 Service
  11. 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
  12. Complexity is the degree of difficulty in sustaining quality, maintainability,

    speed, cognitive load, 
 and development. that is what kills the sustainable growth
  13. 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
  14. 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
  15. 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.
  16. 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" “
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. Any info in the model can change at any time,

    that’s chaos. 
 We need to control the change! CARD PAYMENT CONTEXT
  31. 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
  32. 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
  33. 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 ?
  34. 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
  35. 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
  36. 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
  37. 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
  38. 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
  39. CREATE USER NOTIFY CUSTOMER SAVE OUTBOX CREATE USER 
 USE

    CASE USER CREATED 
 MESSAGE OUTBOX SAVED 
 MESSAGE CUSTOMER 
 NOTIFIED 
 MESSAGE NON-TRANSACTIONAL TRANSACTIONAL TRANSACTIONAL TRANSACTIONAL
  40. MANAGING THE LEVEL OF 
 HOW DEPENDENT BOUNDED CONTEXTS TO

    EACH OTHER thinking in communicating objects?
  41. 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
  42. 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
  43. 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
  44. 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
  45. 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
  46. 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
  47. 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
  48. 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
  49. 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
  50. 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