Slide 1

Slide 1 text

From CRUD to Hexagonal & DDD “How Meetic saved its codebase” Icons made by Icongeek26, Freepik from www.flaticon.com Jean-Marie Lamodière - Backend tech lead @jmlamodiere

Slide 2

Slide 2 text

stackshare.io/meetic @meetictech microservice calls Kafka messages production deployments 3 500 000 000 250 000 000 25 / day

Slide 3

Slide 3 text

Legacy REST API Buzzwords Evangelism 2002-2012 2013 2015-2018 2018

Slide 4

Slide 4 text

WHY ? n-tiers architecture Presentation (Apps) Presentation Business logic Data access

Slide 5

Slide 5 text

But… Monolithic Rest API = new Legacy v2 Icons made by Freepik from www.flaticon.com

Slide 6

Slide 6 text

What’s wrong ? We use a modern web framework ! We follow its best practices ! Icons made by Freepik from www.flaticon.com

Slide 7

Slide 7 text

WHY ? MVC Framework = CRUD Create Read Update Delete = Database mindset Icons made by Smashicon from www.flaticon.com

Slide 8

Slide 8 text

WHY ? MVC Framework = CRUD Typical tutorial : 1. Generate entities + getters + setters 2. Generate Database 3. Expose as REST (or web )

Slide 9

Slide 9 text

WHY ? MVC Framework = CRUD N-tiers architecture Presentation Business logic Data access Framework focus Framework focus ...YOLO ! Icons made by Freepik, Smashicon from www.flaticon.com

Slide 10

Slide 10 text

WHY ? Tests… with code coverage in mind Complex Class Icons made by Pause08, Freepik from www.flaticon.com = No refactoring Test coupled with internal details + 100%

Slide 11

Slide 11 text

What is a useful test ? How to code business complexity ? Icons made by Freepik from www.flaticon.com

Slide 12

Slide 12 text

Legacy REST API Buzzwords Evangelism 2002-2012 2013 2015-2018 2018

Slide 13

Slide 13 text

WHY ? Let’s try buzzwords ! Test Driven Development Behaviour Driven Development Command Bus Hexagonal architecture Domain Driven Design Command Query Separation Icons made by Roundicons from www.flaticon.com Microservices

Slide 14

Slide 14 text

WHY ? 3 years later... ● Inconsistant code designs ● Differing opinions amongst developers Fewer libraries! More libraries! Get sh*t done! Refactor everything! Fewer libraries! More libraries! Refactor everything!

Slide 15

Slide 15 text

Legacy REST API Buzzwords Evangelism 2002-2012 2013 2015-2018 2018

Slide 16

Slide 16 text

WHY ? Evangelism Pro-tips ● Lead by example Pull Requests, Pair Programming ● Organize debates Teach, show code, vote ● Code example as documentation ● Use (anti-)pattern names

Slide 17

Slide 17 text

Hexagonal Architecture = Ports & Adapters Dr. Alistair Cockburn - 2005 Hexagonal Architecture Command / Query Separation Domain Driven Design Testing Strategy Gotchas Pro-Tips

Slide 18

Slide 18 text

WHY ?What is “Decoupling” ? Low coupling High cohesion “Allow unrelated things to change independently” Icons made by Roundicons from www.flaticon.com

Slide 19

Slide 19 text

WHY ?Hexagonal architecture Low coupling High cohesion “Decoupling business and technical choices” Icons made by Roundicons from www.flaticon.com

Slide 20

Slide 20 text

WHY ?Hexagonal architecture “Techno agnostic domain” Infrastructure ● Framework (+ version) ● Libraries (ORM, http client) ● Database ● REST, SOAP, Command line ? Domain (Business logic)

Slide 21

Slide 21 text

WHY ? Where to put my code ? Infrastructure Framework, libraries, techno Domain (Business logic) Icons made by Icongeek26 from www.flaticon.com Product Owner Business expert Architect Dev, Ops (Who decides ?)

Slide 22

Slide 22 text

WHY ?Domain inside hexagon RepositoryInterface Entity No framework Icons made by Freepik from www.flaticon.com /Domain MemberRepository Member Screaming architecture

Slide 23

Slide 23 text

WHY ? Port = simplest interface meeting use-case needs UseCase RepositoryInterface Entity Start inside hexagone, free your mind from infrastructure No framework Icons made by Freepik from www.flaticon.com

Slide 24

Slide 24 text

WHY ? Port = simplest interface meeting use-case needs Icons made by Roundicons, Freepik from www.flaticon.com repo.persist(member).flush (framework details) repo.add(member) repo.get(id) A repository can be seen as a list

Slide 25

Slide 25 text

WHY ? Port = simplest interface meeting use-case needs Icons made by Roundicons, Freepik from www.flaticon.com Intention revealing interface getInactiveMembers() getDefaultChoices(gender) increaseCounter()

Slide 26

Slide 26 text

WHY ? Adapter = techno-specific “driver” UseCase RepositoryInterface Entity MysqlRepository HttpRepository No framework Framework welcome Icons made by Freepik from www.flaticon.com TestRepository

Slide 27

Slide 27 text

WHY ? Adapter = techno-specific “driver” MysqlRepository Icons made by Freepik from www.flaticon.com /Domain MemberRepository Member /Infrastructure MysqlMemberRepo... Framework welcome

Slide 28

Slide 28 text

WHY ? MysqlMemberRepository implements MemberRepositoryInterface { getInactiveMembers() {...} } Adapter = techno-specific “driver” Techno name Icons made by Freepik from www.flaticon.com

Slide 29

Slide 29 text

WHY ? Adapter = techno-specific “driver” UseCase RepositoryInterface Entity MysqlRepository @Throws UserNotFound Icons made by Freepik from www.flaticon.com Convert infra exceptions to domain exceptions

Slide 30

Slide 30 text

WHY ? Adapter = techno-specific “driver” UseCase RepositoryInterface Entity AggregatorRepository MysqlDao* CacheDecoratorDao HttpDao *Data Access Object (No impact here) Icons made by Freepik from www.flaticon.com (Complex infra)

Slide 31

Slide 31 text

WHY ? Difference with n-tiers architecture Service MysqlDao1* Dto1* Dao2Interface *Data Access Object *Data Transfert Object CacheDecoratorDao2 HttpDao2 Dto2 (Aware of 2 Dao) (Mimic database structure)

Slide 32

Slide 32 text

WHY ? Port & Adapters : entrypoints UseCase RepositoryInterface Entity RestController Test CliController No framework Framework welcome Icons made by Freepik from www.flaticon.com

Slide 33

Slide 33 text

RestController Framework welcome Icons made by Freepik from www.flaticon.com /Infrastructure /Symfony MemberController MemberSerializer WHY ? Port & Adapters : entrypoints

Slide 34

Slide 34 text

WHY ? Ex. of adapter refacto @Meetic Symfony 2 Database Database Oracle Icons made by Freepik from www.flaticon.com Symfony 4 External REST API Config files PostgreSQL

Slide 35

Slide 35 text

WHY ?Layers inside hexagone UseCase RepositoryInterface Entity Icons made by Freepik from www.flaticon.com Application Use cases (do, get…) Domain Modeling business reality (Use case agnostic)

Slide 36

Slide 36 text

Command Query Separation Command (do) : produces an effect Query (get) : gets data, no state change Same as “Query” vs. “Mutation” in GraphQL Hexagonal Architecture Command / Query Separation Domain Driven Design Testing Strategy Gotchas Pro-Tips

Slide 37

Slide 37 text

WHY ? Command / Query Separation RepositoryInterface Entity Icons made by Freepik, Smashicons from www.flaticon.com Query Handler Command Handler

Slide 38

Slide 38 text

WHY ? Command / Query Separation /Application /Command RegisterMember RegisterMemberHandler /Query GetNewMembers GetNewMembersHandler /Domain MemberRepository Member

Slide 39

Slide 39 text

WHY ? Command / Query Separation Command, Query ● simple DTO ● user intention ● primitive values /Application /Command RegisterMember RegisterMemberHandler /Query GetNewMembers GetNewMembersHandler

Slide 40

Slide 40 text

WHY ? Steps 1. Infrastructure\Controller Converts HTTP request to Command/Query and call Handler 2. Application\CommandHandler Apply logic, act on Entity through Repository 3. Infrastructure\Controller Send HTTP response

Slide 41

Slide 41 text

WHY ? Command / Query Separation Command Handler RepositoryInterface Entity Icons made by Freepik, Smashicons from www.flaticon.com Query Handler DaoInterface DTO (with validation) (no logic, readonly) Same database (≠ CQRS)

Slide 42

Slide 42 text

WHY ? Command / Query Separation /Application /Command RegisterMember RegisterMemberHandler /Query GetContactPictures GetContactPicturesHandler /Domain MemberRepository Member /Read ContactDao ContactPicture

Slide 43

Slide 43 text

WHY ? Command / Query Separation Create custom Read DAO only when it simplifies code Ex : custom DTO with less fields

Slide 44

Slide 44 text

Domain Driven Design Eric Evans - 2004 Icons made by Icongeek26, Freepik from www.flaticon.com Hexagonal Architecture Command / Query Separation Domain Driven Design Testing Strategy Gotchas Pro-Tips

Slide 45

Slide 45 text

WHY ? Domain Driven Design ● Talk with domain experts ● Use domain words in your code ● Focus on events instead of data Icons made by Icongeek26 from www.flaticon.com

Slide 46

Slide 46 text

WHY ? Domain Driven Design Make domain logic explicit

Slide 47

Slide 47 text

WHY ? Before DDD : fake entities... Anemic domain model Temporal coupling memberEntity .setStatus(“active”) .setActivationDate(now) .setCanTalk(true) Icons made by Roundicons from www.flaticon.com Feature envy

Slide 48

Slide 48 text

WHY ? Same (anti)patterns with REST PUT /member/123 {“status”: “active”, “activDate”:”now”“canTalk”:true} Icons made by Roundicons, Freepik from www.flaticon.com POST /member/123 {“action”: “activate”} Logic on caller = feature envy POST /member/123/activate

Slide 49

Slide 49 text

WHY ? DDD Entity Rich domain model Icons made by Roundicons from www.flaticon.com memberEntity .activate() ● State always valid (check invariants) ● Explicit mutators ● Emit domain events

Slide 50

Slide 50 text

WHY ? Before DDD : primitive types only... Icons made by Roundicons from www.flaticon.com Primitive obsession productEntity .setPriceAmount(20.50) .setCurrenty(“EUR”) (same concern)

Slide 51

Slide 51 text

WHY ? DDD Value Object price = new Price(20.50, “EUR”) productEntity .setPrice(price) ● Explicit ● Immutable ● Valid

Slide 52

Slide 52 text

WHY ? DDD Value Object @ Meetic age = new Age(23) … = age .toSearchBirthdayMax() ● Factorize validation ● Factorize features Must be >= 18

Slide 53

Slide 53 text

Testing strategy Hexagonal Architecture Command / Query Separation Domain Driven Design Testing Strategy Gotchas Pro-Tips Icons made by Freepik from www.flaticon.com

Slide 54

Slide 54 text

WHY ? Inside hexagon: unit tests Command Handler RepositoryInterface Entity Icons made by Freepik, Smashicons from www.flaticon.com ● Mock Infra only ● Don’t mock entities / value objects Test Mock

Slide 55

Slide 55 text

WHY ? Outside hexagon: integration tests Icons made by Freepik, Smashicons from www.flaticon.com Don’t mock a library API The test should allow refactoring : ● QueryBuilder -> SQL ● Change Http library MysqlRepository Docker mysql HttpRepository Wiremock

Slide 56

Slide 56 text

Gotchas ? Pro-Tips ? Hexagonal Architecture Command / Query Separation Domain Driven Design Testing Strategy Gotchas Pro-Tips Icons made by Freepik from www.flaticon.com

Slide 57

Slide 57 text

WHY ? Do not stack new layers Lava flow Refacto “vertical” business slices Icons made by Freepik, Pixel Perfect, Roundicons from www.flaticon.com New layer Old layer 1 Old layer 2

Slide 58

Slide 58 text

WHY ? Gotchas, Pro-tips ● Hexagon overkill when no domain logic. CRUD / framework magic more suited. ● Start inside hexagon, not with database. Otherwise, infra complexity will leak into domain ● To choose layer => whose decision is it ? Product Owner Business expert Architect Dev, Ops @jmlamodiere Icons made by Icongeek26 from www.flaticon.com Thanks for coming !