Slide 1

Slide 1 text

Majestic Modular Monoliths Photo by Jon Clark from Darwin, NT, Australia - Balls Pyramid pano, CC BY 2.0, https://commons.wikimedia.org/w/index.php?curid=41160475 @axelfontaine

Slide 2

Slide 2 text

Axel Fontaine @axelfontaine flywaydb.org boxfuse.com

Slide 3

Slide 3 text

about questions

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

10110111 00101011 01011011 11001... MyClass{ do() { run(); ...

Slide 6

Slide 6 text

10110111 00101011 01011011 11001... MyClass{ do() { run(); ... As code size increases, where is the bottleneck?

Slide 7

Slide 7 text

10110111 00101011 01011011 11001... MyClass{ do() { run(); ... As code size increases, where is the bottleneck? 95% / 5% Read/Write Ratio

Slide 8

Slide 8 text

MyClass{ do() { run(); ... As code size increases, where is the bottleneck? 95% / 5% Read/Write Ratio Optimize for this!

Slide 9

Slide 9 text

MyClass{ do() { run(); ... MyClass{ do() { run(); ... MyClass{ do() { run(); ... As code size increases, where is the bottleneck? 95% / 5% Read/Write Ratio ✓ Add Structure ✓ Raise Abstraction ✓ Reduce Cognitive Load

Slide 10

Slide 10 text

MyClass{ do() { run(); ... MyClass{ do() { run(); ... MyClass{ do() { run(); ... As code size increases, where is the bottleneck? 95% / 5% Read/Write Ratio Seeing the forest through the trees!

Slide 11

Slide 11 text

MyClass{ do() { run(); ... MyClass{ do() { run(); ... MyClass{ do() { run(); ... As code size increases, where is the bottleneck? 95% / 5% Read/Write Ratio ✓ Methods ✓ Classes ✓ Packages ✓ Modules ✓ Applications

Slide 12

Slide 12 text

Architecture = Interactions & Relationships between these ✓ Methods ✓ Classes ✓ Packages ✓ Modules ✓ Applications

Slide 13

Slide 13 text

Architecture Styles Monolith Microservices

Slide 14

Slide 14 text

Architecture Styles based on conference agendas of the last 3-4 years Monolith Microservices

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

Architecture Styles Monolith Microservices

Slide 19

Slide 19 text

Architecture Styles Integrated System Distributed System

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

Monolith Microservices • One artifact • Entanglement risk • Simple method calls • All parts always up and available • Easy interface refactoring • Application scales as a unit • One database • Transactions • One platform • JAR hell risk (forced dependency convergence) • Limited team parallelization • Many individual services • Focus on clear small units • Unreliable network calls • Service discovery + internal load balancing + circuit breakers • Difficult to refactor • Services scale individually • Polyglot persistence • Eventual consistency • Platform choice • Works with incompatible library versions • Easy team parallelization

Slide 22

Slide 22 text

Very large organizations Very complex applications Very small organizations Very simple applications Monolith Microservices Is there room for something in the middle?

Slide 23

Slide 23 text

Introducing Distributed Monoliths

Slide 24

Slide 24 text

Monolith Microservices Modular Monolith

Slide 25

Slide 25 text

Majestic Modular Monolith

Slide 26

Slide 26 text

Adding Structure to the Monolith Most monoliths

Slide 27

Slide 27 text

Layered Architecture Controllers Services Repositories M O D E L

Slide 28

Slide 28 text

Layered Architecture Controllers Services Repositories Customer Invoice Payment

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

Layered Architecture Controllers Services Repositories Customer Invoice Payment

Slide 32

Slide 32 text

Aggregate Domain Driven Design Controllers Services Repositories Customer Aggregate Invoice Aggregate Payment

Slide 33

Slide 33 text

Acyclic Dependencies Payment Customer Invoice Changes never affect Invoice Changes can affect Invoice

Slide 34

Slide 34 text

Acyclic Dependencies Unstable concept Stable concept depends on

Slide 35

Slide 35 text

Module Boundaries and Structure API ✓Look for highly cohesive blocks of functionality ✓Aim for low coupling to other modules ✓Expose a small, well-defined, stable API ✓Only expose aggregate root ✓Make implementation and other entities private ✓Only depend on API (not impl) of other modules Impl (private) Reduces cognitive load!

Slide 36

Slide 36 text

Only depend on API API Impl (private) API Impl (private) API Impl (private)

Slide 37

Slide 37 text

Code Isolation Separate Package Maven Module Separate Repo External Service different JAR same version same app different JAR different version same app same JAR same version same app different JAR different version different app Microservices Monolith Great for sharing technical & infra. modules between apps!

Slide 38

Slide 38 text

Maven Module Separate Repo different JAR same version same app different JAR different version same app ✓Restricts compile classpath (but not reflection!) ✓Enforces directed acyclic graph (Maven module build order) ✓Only rebuild & test module and its dependents mvn clean install -pl mymodule -amd ✓Easy overview diagrams with IntelliJ or Maven Graph Plugin Seeing the forest through the trees!

Slide 39

Slide 39 text

Avoiding Jar Hell myapp libxyz 5.3 libabc 4.0 mymodule libabc 2.0 ✓Limit your dependencies to absolute minimum ✓Prefer libraries with zero transitive dependencies ✓Enforce dependency convergence ✓Shade if conflict is not resolvable

Slide 40

Slide 40 text

org.apache.maven.plugins maven-enforcer-plugin 3.0.0-M1 enforce true enforce Enforcing Dependency Convergence

Slide 41

Slide 41 text

Enforcing Package Usage (Java 9 with named modules) module com.hello.payment { exports com.hello.payment.api; requires com.hello.invoice.api; requires java.sql; }

Slide 42

Slide 42 text

Enforcing Package Usage (Java 8 with code-assert) @Test public void dependency() { class ComHello extends DependencyRuler { DependencyRule paymentApi, paymentImpl, invoiceApi; public void defineRules() { paymentApi().mayUse(invoiceApi); paymentImpl().mayUse(paymentApi, invoiceApi); } } AnalyzerConfig config = AnalyzerConfig.maven().main(); DependencyRules rules = DependencyRules.denyAll() .withRelativeRules(new ComHello()).withExternals("java.sql"); DependencyResult result = new DependencyAnalyzer(config).rules(rules).analyze(); assertThat(result, matchesRulesExactly()); } https://github.com/nidi3/code-assert

Slide 43

Slide 43 text

✓Referential integrity ✓Atomic transactions (vs eventual consistency) Relational Databases

Slide 44

Slide 44 text

Relational Databases ✓Ensure each module only accesses its own tables

Slide 45

Slide 45 text

Relational Databases ✓Ensure each module only accesses its own tables ✓No sharing of tables between modules ✓Joins only between tables of same module (not across modules!) ✓Maintain referential integrity and transactions across modules

Slide 46

Slide 46 text

API Impl (private) API Impl (private) API Impl (private) Schema Schema Schema

Slide 47

Slide 47 text

Data Isolation Separate Table Separate Schema Separate Database Other Persistence different schema same database same RDBMS different schema different database same RDBMS same schema same database same RDBMS different schema different database different (R)DBMS Same flyway_schema_history table

Slide 48

Slide 48 text

Scaling EC2 x1e.32xlarge 128 vCPUs 3904 GB RAM EC2 t2.nano 1 vCPU 0.5 GB RAM

Slide 49

Slide 49 text

Scaling Asymmetrically Executor Service different capacity per module ExecutorService paymentExecutor = Executors.newFixedThreadPool(10); ExecutorService invoiceExecutor = Executors.newFixedThreadPool(25);

Slide 50

Slide 50 text

Scaling Asymmetrically Executor Service RDBMS Queue different number of consumers per module, persistent and participates in RDBMS transaction different capacity per module id message 1 {“customer”:”abc”} 2 {“other”:”xyz”} INSERT INTO queue (message) VALUES (?) DELETE FROM queue WHERE id = (SELECT id FROM queue ORDER BY id LIMIT 1 FOR UPDATE SKIP LOCKED) RETURNING message

Slide 51

Slide 51 text

Scaling Asymmetrically Executor Service RDBMS Queue Dedicated Queue different number of consumers per module, persistent and participates in RDBMS transaction different number of consumers per module, persistent and very high performance different capacity per module

Slide 52

Slide 52 text

Language independence

Slide 53

Slide 53 text

boxfuse.com Continuous Deployment as a Service for JVM, Node.js and Go apps on AWS Deploying ✓ Up and running in minutes ✓ Deploy with 1 command ✓ Focus on development ✓ Immutable Infrastructure as Code ✓ Minimal images ✓ Zero downtime blue/green deployments boxfuse run my-majestic-monolith.jar –env=prod

Slide 54

Slide 54 text

flywaydb.org Evolve your relational database schemas reliably across all your environments for each of your modules and services with pleasure and plain SQL ✓ Supports all popular RDBMS ✓ Millions of users ✓ Designed for Continuous Delivery ✓ Open-source Community Edition and commercial Pro and Enterprise Editions ✓ Highly focused and very easy to get started Database Schema Evolution

Slide 55

Slide 55 text

Best, pragmatic, choice for most companies combining the simplicity of monoliths with structure and focus of microservices Summary Majestic Modular Monolith

Slide 56

Slide 56 text

Go Modular and make your Monolith Majestic again!

Slide 57

Slide 57 text

Axel Fontaine @axelfontaine flywaydb.org boxfuse.com Thanks !