Slide 1

Slide 1 text

The Way of the Modular Monolith [email protected] ♦ ♦ @victorrentea ♦ VictorRentea.ro

Slide 2

Slide 2 text

👉 victorrentea.ro/training-offer Hi, I'm Victor Rentea 🇷🇴 PhD(CS) Java Champion, 17 years of code, code, code, code, code.... Consultant & Trainer: 5000 developers of 100+ companies in EU: ❤ Clean Code, Architecture, Unit Tes3ng 🛠 Spring, Hibernate, Reactor ⚡ Java Performance, Secure Coding 🔐 Conference Speaker – many conferences talks on YouTube Founder of European SoLware CraLers (5500+ members) 🔥 Free monthly webinars, 1 hour a9er work 👉 victorrentea.ro/community Past events on my channel: youtube.com/vrentea Father of 👧👦, host of a 🐈, weekend gardener 🌼 h"ps://VictorRentea.ro

Slide 3

Slide 3 text

Modular Monolith

Slide 4

Slide 4 text

4 VictorRentea.ro a training by The Monolith Tangled highly-coupled code Full of dirty fixes Slow and risky to change Craving for refactoring, but lacking unit tests The architecture of many successful systems in produc@on today aka Big Ball of Mud

Slide 5

Slide 5 text

5 VictorRentea.ro a training by h-ps://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

Slide 6

Slide 6 text

6 © VictorRentea.ro a training by A large project is more likely to suffer from internal coupling (ie. domain dilu6on, scope creep) than from coupling to external APIs and Libraries Elders Wisdom Focus of tradi6onal Concentric Architectures (Clean, Onion, Hexagonal, Ports-Adapters)

Slide 7

Slide 7 text

7 © VictorRentea.ro a training by Microservices🌈 ü Faster Time-to-Market ⭐ ü Smaller Teams (Two-Pizza-sized) ü Improved Scalability ü Fault Tolerance ü Programming Language Agnos?c ü Data Security Microservice 💰 Premium 💰 - Network Latency - Timeout/Retry - Idempotency - Load balancing - Rate Limiter - Bulkhead - Circuit Breaker/503 - Distributed cache - Log aggregaGon - Request tracing - Message queues - k8s, Docker - Mature DevOps culture

Slide 8

Slide 8 text

8 VictorRentea.ro a training by 1) Big-Bang Rewrite - Start from scratch, re-specifying all behavior - New features in old system: delay or implement twice - 20-30% success rate - Likely to end up with a Distributed Monolith 😱 2) Strangler-Fig Pa4ern - Implement new features in fresh microservices - Con6nuously strip bits of func6onality from the monolith 3) Refactor to Modules > Extract 🌈 - Decouple logic and data in the same monolithic codebase From a Legacy Monolith💀 to Microservices🌈 Highly-coupled Distributed Systems

Slide 9

Slide 9 text

9 VictorRentea.ro a training by Modular Monolith is a safe Transi8oning Step from a Legacy Monolith è Microservices

Slide 10

Slide 10 text

10 VictorRentea.ro a training by What's faster to build from scratch? A Monolith or Microservices

Slide 11

Slide 11 text

11 VictorRentea.ro a training by What's faster to build from scratch? A Monolith or Microservices But coupling eventually starts slowing us down

Slide 12

Slide 12 text

12 VictorRentea.ro a training by Produc@vity Func@onal Complexity (Time) Microservices as complexity accumulates, produc6vity starts to drop overhead of managing distributed systems reduces ini6al produc6vity the decreased coupling of microservices outweighs their governance overhead Produc2vity years Monolith But I'm going to build a complex system!

Slide 13

Slide 13 text

13 VictorRentea.ro a training by "You shouldn't start a new project with microservices, even if you're sure your application will be big enough to make it worthwhile." - Martin Fowler h-ps://marKnfowler.com/bliki/MonolithFirst.html (2015) Start simple and address the natural bottlenecks of the system (functional/technical).

Slide 14

Slide 14 text

14 VictorRentea.ro a training by Modular Monolith is the best way to start a Greenfield

Slide 15

Slide 15 text

15 VictorRentea.ro a training by Monolith or Microservices?

Slide 16

Slide 16 text

16 VictorRentea.ro a training by What if we could have the best of both worlds? Physical architecture of a Monolith Logical architecture of Microservices Ability to easy extract a Microservice out when necessary

Slide 17

Slide 17 text

Modular Monolith Modulith

Slide 18

Slide 18 text

18 VictorRentea.ro a training by Legacy Monolith Microservices Database eShop ApplicaGon Catalog Microservice Catalog DB Orders Microservice Orders DB REST REST/MQ Payment Microservice Payment DB Customer Microservice Customer DB vs

Slide 19

Slide 19 text

19 VictorRentea.ro a training by Modular Monolith Database E-Shop Modular Monolith ApplicaGon Catalog Module Orders Module Payment Module Customer Module

Slide 20

Slide 20 text

20 VictorRentea.ro a training by Life in a Modulith The complexity of the project is split in decoupled modules managed by separate teams 🎉

Slide 21

Slide 21 text

21 VictorRentea.ro a training by Okay, But what IS a module?

Slide 22

Slide 22 text

22 VictorRentea.ro a training by Think of a module as a stand-alone logical applica/on (including its own frontend)

Slide 23

Slide 23 text

23 VictorRentea.ro a training by Internal Architecture of a Module Can be decided per-module

Slide 24

Slide 24 text

24 VictorRentea.ro a training by Internal Architecture of a Module Layered Architecture Presenta6on / API Service Repository

Slide 25

Slide 25 text

25 VictorRentea.ro a training by Internal Architecture of a Module Layered Architecture Clean, Pragma/c* Architecture Domain * Avoid over-engineering: h"ps://www.youtube.com/watch?v=ewe68u1v6bo

Slide 26

Slide 26 text

26 VictorRentea.ro a training by Internal Architecture of a Module Layered Architecture Clean, Pragma/c* Architecture Ver/cal Slice Architecture Presenta6on / API Service Repository Place Order Es6mate Shipping Date

Slide 27

Slide 27 text

27 VictorRentea.ro a training by Modulith Challenges Defining module boundaries CommunicaJon between modules Data independence

Slide 28

Slide 28 text

28 © VictorRentea.ro a training by Architecture is the art of drawing lines (boundaries) Elders Wisdom

Slide 29

Slide 29 text

29 VictorRentea.ro a training by .controller .service .repo .infra com.myorg.myapp .order .product Top Packages Reflec8ng Technical Layers (tradi'onal style) .entity .order .product To keep packages small, we introduce sub-packages

Slide 30

Slide 30 text

30 VictorRentea.ro a training by .service com.myorg.myapp .order .product .service The Screaming Architecture Top-level packages reflect your domain structure .entity .repo … … separate modules h"ps://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html

Slide 31

Slide 31 text

31 VictorRentea.ro a training by .order .product .fulfillment .catalog .invoice .invoicing Group by Business Capability (what value it brings the users) Group by Data Concept Module Names

Slide 32

Slide 32 text

32 VictorRentea.ro a training by Organize by Capability supports beIer the complexity Pricing Catalog Customer • customer first name • customer last name • product name • product description • customer status • product price class Customer { firstName lastName status !!... } class Product { name description price !!... }

Slide 33

Slide 33 text

33 VictorRentea.ro a training by A Module* is NOT: • Just Behavior Example: calcula6on, valida6on • Just CRUD Data Example: Country, Tenant, Clinic * the same applies for "Microservice" Microservices: configura6on or en6ty microservice CountryRepo in the 'shared' module

Slide 34

Slide 34 text

34 VictorRentea.ro a training by A Module* is the technical authority for a business capability .product .catalog * the same applies for "Microservice"

Slide 35

Slide 35 text

35 VictorRentea.ro a training by The boundary within which a Domain Model applies The smaller the boundary, the more useful the model. Bounded Context 2003

Slide 36

Slide 36 text

36 VictorRentea.ro a training by How Big should a Module* be? * the same applies for "Microservice" As small as possible!

Slide 37

Slide 37 text

37 VictorRentea.ro a training by The Fallacy of Nano-Services

Slide 38

Slide 38 text

38 VictorRentea.ro a training by The Fallacy of Nano-Services Modules

Slide 39

Slide 39 text

39 VictorRentea.ro a training by The Fallacy of Nano-Modules* h)ps://vladikk.com/2020/04/09/untangling-microservices/ * the same applies for "Microservice" Global Complexity of integraGng all the APIs Local Complexity of a single module High Cohesion, Low Coupling

Slide 40

Slide 40 text

40 VictorRentea.ro a training by Be brave and Keep It Super Simple When Complexity Grows > Extract it Evolutionary Architecture

Slide 41

Slide 41 text

41 VictorRentea.ro a training by Module A @Test !// unit test on CI public void independentSubdomains() { slices().matching("!..myapp.(*)!..*") .should().notDependOnEachOther() .ignoreDependency(resideInAnyPackage( "!..shared!..", "!..api!..")) .check(new ClassFileImporter(). importPackages("com.myapp")); } 2) Communica2on between Modules The internals of a module should never be accessed from another module Each Module exposes a Public API that other modules can reference Public API events calls 1. Compiler-enforced Separate CompilaGon Units (eg Maven modules) 2. Unit Tests on CI Code Analysis, eg ArchUnit: Part of the Public API can be exposed as External API to remote apps (eg via REST, MQ) External API

Slide 42

Slide 42 text

42 VictorRentea.ro a training by Module CommunicaJon via Method Calls calls Extremely simple Fast, in-memory calls (no networking) ⚠ Methods called and objects involved must be part of the Public API

Slide 43

Slide 43 text

43 VictorRentea.ro a training by ⚠ Published Events must be part of the Public API J Decoupled: publisher unaware of listeners (poten@ally mul@ple) J Poten@ally async J Poten@ally persisted L Not suitable for request-reply interac@on L Naviga@ng code is harder (than a method call) Event Types: No@fica@on {id}, or Heavy-Events {state} events Module CommunicaJon via Events / Messages

Slide 44

Slide 44 text

44 VictorRentea.ro a training by Cyclic Dependencies between Modules A B call call Build fails if modules are separate compila@on units (eg. Maven/Gradle modules)

Slide 45

Slide 45 text

45 VictorRentea.ro a training by api (shared) A B O orchestrator Keep Orchestra@on Up Just fix the build, allow the ó calls A B A-api B-api Extract API modules run'me calls Facade keep a coarse grained API, eg for a monolith site Fixing Cyclic Dependencies between Modules microservices: N/A microservices: events on queue microservices: interdependent microservices microservices: api gateway/bff/saga microservices: shared lib/3rd service microservices: merge? ❤ AB Merge Modules Tight Coupling (eg dozens of links) wrong boundaries? Using Dependency Inversion B can let A implement logic, without depending on A A B ç event call Publish Events (in-mem) ⭐Decoupled A B C commons Push Commons Down A B implements è call Dependency Inversion ⭐Decoupled AProviderImpl runKme call AProvider Module A must react to changes in B Technical Stuff Only send email countryRepo audit, ... uSls

Slide 46

Slide 46 text

46 VictorRentea.ro a training by A Surface of a Module publish events call interface implementa-on B command query (a) no-fica-on {id} (b) Heavy-Event {state} listen to events External API Public API

Slide 47

Slide 47 text

47 VictorRentea.ro a training by 3) Module Data Independence Every module is responsible for its own data ⚠ A Module should not query the tables of another module (breaks encapsula@on) Instead, ask for that data via the Public API

Slide 48

Slide 48 text

48 VictorRentea.ro a training by Module Data Isola2on Levels No IsolaGon: Any module can freely read/write any table Write IsolaGon: A table is updated by ONE module, but can be read by other modules Table IsolaGon⭐: A module has exclusive access to its tables (usually separate schemas) Consistency IsolaGon - tables of different modules: (a) cannot share a Foreign Key, and (b) are never updated in the same DB transac@on Separate database instance / module Different database types, eg PostgresSQL / MongoDB Before extrac@ng a microservice

Slide 49

Slide 49 text

49 VictorRentea.ro a training by Tes8ng a Modulith End-to-end Tests are easier in a monolith Module Tests Integra0on tes0ng an Module in isola0on - mock public APIs of other modules - mock event bus è Spring Modulith project h4ps://spring.io/projects/spring-modulith

Slide 50

Slide 50 text

50 VictorRentea.ro a training by Modulith – Lessons Learned Ø Invest more @me to clarify module boundaries Ø Consider merging highly-coupled modules Ø Don't sacrifice consistency too early Ø Carefully design how data is shared between modules Ø Don't leak internal classes via module's Public API Ø Monitor architecture fitness func@ons using code analysis tools

Slide 51

Slide 51 text

51 VictorRentea.ro a training by •Migrating legacy monoliths eg. an existing large-scale banking platform monolith that needs to split into microservices, but isn't ready to separate into completely independent services. •A greenfield implementation eg. a new peer-to-peer lending platform in the early stages of growing into a full suite of financial services •A system with a low-moderate scale eg. a movie ticket booking platform that serves several thousand users and handles a few million transactions per week. •Non-complex software platforms eg. a notes/documents syncing and management platform for consumer apps. When to choose a Modulith? When to move to Microservices? •High Delivery Rate ? eg. the company decides investing in shipping to self-collect boxes on the street, and new versions are deployed weekly. •Scalability eg. the endpoint selecting the ad to insert in a live stream expected to take 1k-10k requests/second. •Fault-tolerance eg. in the same ad-insert solution, if the management part fails, the ads still have to be inserted •Different Programming Language eg. the senior developers of sales department are using C# while the rest of the teams use Java. Oh, and Kotlin rocks!🤘 •Security eg. customer management has to be audited for GDPR compliance regarding PII information.

Slide 52

Slide 52 text

52 VictorRentea.ro a training by But remember, The Skills of the Team will outweigh any monolith/microservice choice A great team will build a great project whatever architectural style you choose #investInPeople

Slide 53

Slide 53 text

thank you [email protected] ♦ ♦ @victorrentea ♦ VictorRentea.ro victorrentea.ro/community Want more? Register for my upcoming deep dive webinar on Architectures on May 29-30 at h"ps://clean.re For a company workshop see victorrentea.ro/training-offer

Slide 54

Slide 54 text

54 VictorRentea.ro a training by § Ugly (Successful) Monolith☠ - "It works > Ship it now, refactor later" for 5-25 years § Domain-Driven Design (Eric Evans, 2003) link - Design Rich Domain Model for complex problems; - Split soluKon in Bounded Context § Onion/Clean Architecture (Jeffrey Palermo, Uncle Bob 2008) link - Keep core Domain Logic agnosKc from UI, APIs, DB, frameworks (by dep. inversion) § PragmaQc Onion link - Merge applicaKon with infrastructure, evolve layers as needed, tolerate ORM on Domain Model § Microservices (2011) - Loosely coupled, independent business capabiliKes deployed separately § Distributed Monolith☠ link - Tightly coupled microservices due to premature, too fine-grained breakdown § VerQcal Slice Architecture (Jimmy Bogard, 2018) link - Group code by feature, not by technical layer § Modular Monolith, aka Modulith (Simon Brown, 2018) - Implement business capabiliKes as loosely coupled modules in a single deployment unit Overview of Architecture Styles