Successfully reported this slideshow.
Your SlideShare is downloading. ×

Vertical Slicing Architectures

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Loading in …3
×

Check these out next

1 of 55 Ad

Vertical Slicing Architectures

Download to read offline

Throughout the years, the Concentric Architectures (Onion, Hexagonal, Clean-..) have grown into the undisputed leader among backend systems architectures. With the rise of Domain-Driven Design, keeping your Domain ring 'agnostic' to the outside world has become the norm today. But history proved that any 'norm' in software architectures will cause overengineering if applied without criticism.

After a brief recap of these architectures, their pitfalls, and weaknesses, we'll see two alternatives that segregate code not in 'layers' or 'rings' but in vertical slices: Feature Slicing and Modular Monolith.

[Feature Slicing](vertical Slice Architecture) (aka *UseCase) has its own pitfalls and weaknesses, that we'll briefly review. But this will just warm us up for the next style.
Modular Monolith (aka Modulith) is an architecture style that helped many companies break their legacy codebases, and smoothly move to microservices. Most of the techniques discussed here can also come handy when one single microservice grew big and needs to be broken down.

Even more, greenfield projects today opt for this architecture instead of microservices, to avoid paying the high cost of distributability. Imagine cohesive but decoupled modules living in the same code base & deployment, but on which different teams work in harmony, delivering more value much faster than an equivalent microservice ecosystem.🦄

On the agenda:
- patterns to break data structures
- how to protect Domains inside modules
- communication patterns between modules
- breaking cyclic dependencies

Throughout the years, the Concentric Architectures (Onion, Hexagonal, Clean-..) have grown into the undisputed leader among backend systems architectures. With the rise of Domain-Driven Design, keeping your Domain ring 'agnostic' to the outside world has become the norm today. But history proved that any 'norm' in software architectures will cause overengineering if applied without criticism.

After a brief recap of these architectures, their pitfalls, and weaknesses, we'll see two alternatives that segregate code not in 'layers' or 'rings' but in vertical slices: Feature Slicing and Modular Monolith.

[Feature Slicing](vertical Slice Architecture) (aka *UseCase) has its own pitfalls and weaknesses, that we'll briefly review. But this will just warm us up for the next style.
Modular Monolith (aka Modulith) is an architecture style that helped many companies break their legacy codebases, and smoothly move to microservices. Most of the techniques discussed here can also come handy when one single microservice grew big and needs to be broken down.

Even more, greenfield projects today opt for this architecture instead of microservices, to avoid paying the high cost of distributability. Imagine cohesive but decoupled modules living in the same code base & deployment, but on which different teams work in harmony, delivering more value much faster than an equivalent microservice ecosystem.🦄

On the agenda:
- patterns to break data structures
- how to protect Domains inside modules
- communication patterns between modules
- breaking cyclic dependencies

Advertisement
Advertisement

More Related Content

More from Victor Rentea (20)

Recently uploaded (20)

Advertisement

Vertical Slicing Architectures

  1. 1. 1 VictorRentea.ro a training by
  2. 2. Hi, I'm Victor Rentea Java Champion, enjoying since 2006 Trainer – 5000+ developers in 100+ companies / 20+ countries Clean Code✨ Unit Testing 🙌 Architecture 📐 Spring & JPA 🛠 Java Performance 🔥 Reactive Programming 😱 Secure Coding 🔐 Speaker at Conferences & Meetups Join at victorrentea.ro/community and enjoy 1h/month of free workshop/talk Software Crafters Community @victorrentea VictorRentea.ro YouTube Channel - in-house - mixed groups - video classes
  3. 3. 3 VictorRentea.ro a training by 🫵 About You! Zoom Poll: your experience and language
  4. 4. 4 VictorRentea.ro a training by Chapter 1. Concentric Architectures = Onion, Clean, Hexagonal, Ports-and-Adapters
  5. 5. 5 VictorRentea.ro a training by IAdapter Adapter Onion/Clean Architecture Recap Outer layers depend on inner layers Persistence concerns pushed out Dependency Inversion (call logic in an outer circle via an interface) Services + Model Flow control (method call direction) Domain is agnostic to UI, DB, APIs, Frameworks (protect the business rules) Onion Architecture Primer: https://marcoatschaefer.medium.com/onion-architecture-explained-building-maintainable-software-54996ff8e464
  6. 6. Application Service +Controller DTO Value Object Entity id Domain Service IRepo application IAdapter Adapter External API DTO (agnostic) domain UI, Client External Systems Pragmatic Onion🧅  Detailed explanation in my talk: https://youtu.be/ewe68u1v6bo
  7. 7. 7 VictorRentea.ro a training by vs interface Hexagonal aka Port-and-Adapters Architecture Original Article: https://alistair.cockburn.us/hexagonal-architecture/ Bad cost-benefit Useless interface implements DepENDENCY INvERSION Flow control (method call direction)
  8. 8. 9 VictorRentea.ro a training by https://herbertograca.com/2017/11/16/explicit-architecture-01-ddd-hexagonal-onion-clean-cqrs-how-i-put-it-all-together/
  9. 9. 10 VictorRentea.ro a training by Sources of overengineering in Concentric Architectures Too many interfaces "any layer must only expose and consume interfaces" Mandated layers "a Controller MUST call a Service that MUST call a Repo" Mock-full tests 🧅 "each layer is tested by mocking the layer below" Separate Domain from Persistence 😭 "CustomerModel should be mapped  CustomerEntity in Repo layer" Application-layer structures "Application layer should have its own data structures ≠Domain, ≠Dto" Rigid dependency management "domain MUST NEVER depend on anything outside" Monolithic in nature "the (one) Domain is in the center" Are these still problems in our pragmatic variation? Delete interfaces with only 1 implementation, unless Dep Inversion Extract complexity into Domain Services; challenge Controllers More integration tests (honeycomb) or squash layers ArchUnit allows exceptions 😬 Only required if UC exposed via 2+ channels Gulp... 😬 Indeed Only required if legacy/enemy DB
  10. 10. 11 VictorRentea.ro a training by Chapter 2. Vertical Slicing with a taste of CQRS
  11. 11. 12 VictorRentea.ro a training by Layers Controller Repository + Infrastructure Application Service Vertical SLICING DOMAIN Service + Model Change
  12. 12. 13 VictorRentea.ro a training by How "wide" should an Application Service be? = how many use-cases? Multiple use-cases 👈 what we did class OrderApplicationService { public getOrderById() {/*trivial logic🥱*/} public placeOrder() {..extract..extract...} // eg. 10 more } One class / use-case = Slice by Feature class GetOrderByIdUseCase{/* 5 useful lines*/} class PlaceOrderUseCase {/* 400 lines  */} risk: god class https://jimmybogard.com/vertical-slice-architecture/ continuously extract logic ou accidental coupling between use-cases change 1 use-case= change 1 (less) files Group code by axis of change
  13. 13. 14 VictorRentea.ro a training by One class / use-case = Slice by Feature class GetOrderByIdUseCase{/* 5 useful lines*/} class PlaceOrderUseCase {/* 400 lines  */} risk: god classes https://jimmybogard.com/vertical-slice-architecture/ The stricter the rules are, the less creative we think risk: too small classes risk: repeating logic (DR extract shared logic to Domain extract complex logic to Domain Start  Put everything related to a UseCase in a single file, from Controller down to any custom Repository methods
  14. 14. 15 VictorRentea.ro a training by One class / use-case = Slice by Feature class GetOrderByIdUseCase{/* 5 useful lines*/} class PlaceOrderUseCase {/* 400 lines  */} Query Command read data change data CQRS
  15. 15. 16 VictorRentea.ro a training by Encapsulate DTOs whenever possible class GetOrderByIdUseCase{ // query 👁 private static class Request { ... } //  JSON private static class Response { ... } //  JSON public Response handle(Request request) {...} } class PlaceOrderUseCase { // command ✍️ private static class Request { ... } //  JSON private static class Response { ... } //  JSON public Response handle(Request request) {...} } allows different architecture styles per use-case
  16. 16. 17 VictorRentea.ro a training by Queries 👁 class GetOrderById { private static class Request { ... } private static class Response { ....<large>...... } @GetMapping public Response handle(Request request) {...} } - Can select projections ("select new Dto" JPQL) = different READ Model (CQRS) - Can use raw SQL, or whatever ... - If ≥2 Query UC share logic (rarely)  extract it (eg. into a Util) = DRY
  17. 17. 18 VictorRentea.ro a training by Commands ✍️ • Start simple • Can get veeeery complex. Don't PANIC! Continuously refactor: Extract Method Extract Class Move Methods (into a Domain Model Object or a Domain Service) class PlaceOrder { private static class Request { ....<large>.... } // + @NotNull, @Size.. private static class Response { ... } @PostMapping @Transactional public Response handle(@Validated Request request) { *read stuff* *interesting domain logic to extract* *save stuff* } } Perfect Fit for Task-Based UI
  18. 18. 19 VictorRentea.ro a training by Layers Controller Repository + Infrastructure Application Service SLICE BY FEATURE DOMAIN Service/Model Logic Shared by 2 Features extracted into a Domain Service/Model Complex business logic of a Feature extracted into a Domain Service/Model
  19. 19. 20 VictorRentea.ro a training by Application / Infrastructure Domain 👁 UC-1 External API ✍️UC-3 ✍️UC-4 Domain Service Vertical-Slicing vs Concentric Architecture Equivalence ✍️UC-2 Domain Model 👁 UC-19 👁 UC-17 Not enough domain complexity: they don't deserve to be part of Domain
  20. 20. 21 VictorRentea.ro a training by Microservice (if you must) Module in a Modulith 👑 Large Slice Shippin g Invoicin g Catalo g NO: Each Module can decide how many layers/rings has its internal structure Slice by Feature (aka UseCase, previous slides) Vertical Slicing Small Slice What Size? No layers? = Modular Monolith
  21. 21. 22 VictorRentea.ro a training by A large codebase is more likely to suffer from internal coupling (scope creep, domain model dilution), than external coupling (to external APIs)
  22. 22. 23 VictorRentea.ro a training by Chapter 3. Finding Module Boundaries one of the toughest problems in architecture
  23. 23. 24 VictorRentea.ro a training by It all started with...
  24. 24. 25 VictorRentea.ro a training by .controller .service .repo .infra com.myorg.myapp .order .product Too keep packages small, we grouped classes in subpackages Package Names .entity .order .product ll started with... technical layers names (not domain concepts)
  25. 25. 26 VictorRentea.ro a training by .service com.myorg.myapp .order .product .service The Screaming Architecture =organize code first by subdomain, not by technical layers https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html .entity .repo … …  separate microservices teams modules
  26. 26. 27 VictorRentea.ro a training by Naming (again) .order .product .fulfillment .catalog .invoice .invoicing Group by Business Capability👌 (what it does, its value) Group by Concept (Data)
  27. 27. 28 VictorRentea.ro a training by The Fallacy of Nano-Services or -Modules
  28. 28. 29 VictorRentea.ro a training by The Fallacy of Nano-Services • If you break the code in too many modules (eg 20+) • The local complexity of each piece is ↓ ✅ • But the global complexity gets 🔝 🚫🚫🚫 or Module https://vladikk.com/2020/04/09/untangling-microservices/
  29. 29. 30 VictorRentea.ro a training by The Fallacy of Nano-Services or Module Local Complexity how much complexity is in one microservice/module Global Complexity how hard it is to integrate the microservices/modules Increase cohesiveness of modules (=break complexity) while reducing coupling between them (=micro-APIs) https://vladikk.com/2020/04/09/untangling-microservices/
  30. 30. 31 VictorRentea.ro a training by A Service is NOT • Just behavior Example: calculation, validation • Just CRUD data Example: Country, Tenant, Clinic or Module Modulith: repos in commons Microservices: static data or entity microservice
  31. 31. 32 VictorRentea.ro a training by A Service is ... the technical authority for a business capability or Module .invoice .invoicing
  32. 32. 33 VictorRentea.ro a training by Cognitive🧅 Load: able to specialize in one area Code Ownership & Control: free to refactor the Domain Model Bounded Contexts: sharp concepts, less attributes & more constraints Ideally 1 module = 1 Team = Two-Pizza Team Align with Organization Boundaries (stakeholders) - Conway's Law Has a sound responsibility ? Finding Module Boundaries🏆  Changing its internal structures and business rules affects other modules?  Its API changes when other modules change? (=coupling)  Is it replaceable with off-the-shelf software?  Is it easy to remove when the business need is gone?  Is it testable alone, ie without creating many entities from other modules?
  33. 33. 37 VictorRentea.ro a training by Chapter 4. Decoupling Modules code tactics
  34. 34. 38 VictorRentea.ro a training by Modularizing the Monolith
  35. 35. 39 VictorRentea.ro a training by What's faster to build? from scratch Microservices A Monolith or
  36. 36. 40 VictorRentea.ro a training by What's faster to build? (from scratch) Microservices A Monolith or But soon complexity and coupling start slowing us down
  37. 37. 41 VictorRentea.ro a training by 41 From a Big Ball of Mud  Microservices 1) Rewrite (big-bang) No new features for 1 year Requires re-specifying everything 20-30% success chance (studies) 2) Modularize => Extract Experiment and prototype Be ready to stop any time 3) Strangler-Fig Pattern Reimplement any all features in fresh microservices 👑 Modulith
  38. 38. 42 VictorRentea.ro a training by A new greenfield project Proxy The Strangler Fig Pattern 😁 When a feature is reimplemented, route the requests for it to the new project Prerequisite: clear requirements
  39. 39. 43 VictorRentea.ro a training by order product Unlink Domain Entities class OrderLine { ... Product product; Long productId;1 String productName;2 } class Product { id name ... } 1) Keep only the ID ✅ 👌 Preserve the FK in Modulith + then later: fetch on-demand 2) Snapshot immutable data + according to domain rules 3) Keep mutable data in sync 😨 + replicate changes (eg via events) ⚠️Eventual Consistency (iff distributed) object reference
  40. 40. 44 VictorRentea.ro a training by complexity complexity booking appointment Split Domain Entities class BookingRequest { id date + time specialtyId ... } class Appointment { id medical report followup date date + time ... } class Appointment { id date + time specialtyId ... +20 fields appointed:boolean medical report followup date ... 40 more }
  41. 41. 45 VictorRentea.ro a training by 👌 The owner of some data is the module who changes it The modules that need the data must ask the owner
  42. 42. 46 VictorRentea.ro a training by 0 Writers | * Readers = Reference Data  'shared' module - eg. Country list 1 Writer | n Readers = Owned  Readers get data from Writer - eg. Catalog  Stock.getStock() n Writers | 0 Readers = Notifications  commons via events - eg. Audit, sendSMS 2+ Writers | * Readers  Split Entity 😩 or Merge modules ❤️ - eg. break Order  PlacedOrder + ShippedOrder Data Ownership # modules
  43. 43. 48 VictorRentea.ro a training by Calls between Modules module A module B call any class inside B Lack of encapsulation External API (eg HTTP, gRPC,...) dev riot Why so many structures?!!😡 Goal = Decoupling - Review the coupling - Detect cyclic dependencies - Detect "Module in the middle" DTO Internal API ("Door") DDO Data Decoupling Objects calls only via B's "Door"
  44. 44. 49 VictorRentea.ro a training by Cyclic Dependencies between Modules A B call call Bad news: Maven/Gradle build fails <dependency> <dependency>
  45. 45. 50 VictorRentea.ro a training by Ways to fix Cyclic Dependencies between Modules Key Questions: - massive interdependence? - need to reuse technical/infra stuff? - any existing monolithical clients / frozen API? - are modules exposing external APIs?
  46. 46. 51 VictorRentea.ro a training by A B A-api B-api Extract API modules No single orchestrator runtime calls A B O orchestrator Keep Orchestration Up = Facade (eg site?, mobile) Ways to fix Cyclic Dependencies between Modules A B event call Fire Events Upstream ⭐️Decoupled A B implements call Dependency Inversion ⭐️Decoupled AProvider AProviderImpl call microservices: N/A microservices: events on queue microservices: interdependent microservices microservices: api gateway/saga microservices: shared lib/3rd service microservices: merge? A B C commons Push Commons Down Technical: emails country audit, ... ❤️ AB Merge Modules if tight coupling
  47. 47. 52 VictorRentea.ro a training by B Surface of a Module publish events call interface implementation A command (change) query (read) (a) notification {id} (b) fat-event {data} listen to events
  48. 48. 53 VictorRentea.ro a training by Segregate in baby-steps Prepare to stop/undo when needed - incorrect boundary? Too many tiny modules will 🔝 the Global Complexity Focus on Data ownership & Flow control Introduce Events for one-way signals, w/o response Do NOT sacrifice consistency too early (Transactions, FKs) Measure progress (eg. ArchUnit, custom tool) Modulith Lessons
  49. 49. VictorRentea.ro 54 archunit.org ArchRule rule = classes().that().resideInAPackage("..service..") .should().onlyBeAccessed() .byAnyPackage("..controller..", "..service..");
  50. 50. 55 VictorRentea.ro a training by Chapter 5. Towards Microservices as a painful decision
  51. 51. 56 VictorRentea.ro a training by Reasons to extract a Module into a Microservice • Different Resource Requirements (eg NOSQL vs RDB) • Scalability, or go Reactive🔥 • Availability (not impacted by failures in other modules) • Requires different programming language / exotic framework • High rate of delivery => independent deployability • Security posture (vs Wild Wild Web) • 🛑 STOP if Strong Consistency Requirements: terrible business consequences • ...
  52. 52. 57 VictorRentea.ro a training by Module or Microservice? https://www.confluent.io/resources/event-driven-microservices/
  53. 53. 59 VictorRentea.ro a training by 4) Distributed Systems 1) code decoupling 3) ❌ DB Consistency 2) ❌ Transactions A B A B Shared Transaction TX method calls and events only via doors ✅ External REST API Foreign Key Data Replication (events, CDC, ...) 🔥 MICROSERVICES 🔥 - retry - idempotency - queues - load balancing - 503 - Network Delay - k8s, Docker - rate limiter - distrib. cache - circuit breaker - 😱😱😱😱 TX >@TransactionEventListener(AFTER_COMMIT) >@Async @EventListener (worse!) Tx not shared between modules ✅ Separate Schemas ✅ 😱 😱 😱 Eventual Consistency 😱 😱 😱 => Questions to BIZ Monolith => Modulith => Microservices Blue Team 👕 Pink Team👚 Partially inspired by Axel Fontaine's talk about the "Majestic Modular Monolith": https://www.youtube.com/watch?v=vV34-3NZkh4
  54. 54. VictorRentea.ro 60 Final poll, what architecture have you used by now? A) Layers: 13/ B) Onion (domain module) 6/ C) Port-adapters (*Port) 4/ D) Feature Slices (*UseCase) 5/ E) Modulith (functional modules in a monolith) 10/ F) Event Sourcing + CQRS 4/ (Total answers: 16/)
  55. 55. 61 VictorRentea.ro a training by 📚  Hexagonal Architecture aka. Ports-and-Adapters - Original article by Alistair Cockburn, 2005: https://alistair.cockburn.us/hexagonal-architecture/ - Colorful explanation, 8th light: https://8thlight.com/insights/a-color-coded-guide-to-ports-and-adapters - Input Port Interface are useless: https://softwareengineering.stackexchange.com/q/438705  Onion Architecture - Clean Architecture Uncle Bob: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html - Onion Architecture Primer: https://marcoatschaefer.medium.com/onion-architecture-explained-building-maintainable-software-54996ff8e464 - Original article, Jeffrey Palermo, https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/  Vertical Slice Architecture (aka -UseCase) - Feature slicing Jimmy Bogard talk: https://youtu.be/5kOzZz2vj2o and short intro article: https://jimmybogard.com/vertical-slice-architecture/ - Task-based UI: https://cqrs.wordpress.com/documents/task-based-ui/  Finding Module/Service Boundaries - Heuristics to find boundaries: https://www.dddheuristics.com/design-heuristics/ - Organize by features, not by entities, Adam Ralph: https://youtu.be/tVnIUZbsxWI  Modular Monoliths - Majestic Modular Monolith, Axel Fontaine: https://youtu.be/BOvxJaklcr0 - Local Complexity vs Global Complexity in microservices: https://vladikk.com/2020/04/09/untangling-microservices/  Comparisons: - Comparison of Layered, Onion, vs Vertical Slices, Simon Brown: https://youtu.be/5OjqD-ow8GE - Nice overview + picture ⭐️ https://herbertograca.com/2017/11/16/explicit-architecture-01-ddd-hexagonal-onion-clean-cqrs-how-i-put-it-all-together/  Task-based UI: - https://codeopinion.com/decomposing-crud-to-a-task-based-ui/  Books: - Software Architecture: Fundamentals & The Hard Parts by Neal Ford & Mark Richardson Architecture Reading

Editor's Notes

  • Salut! Eu sunt Victor si am 14 ani… de lucru cu Java, desi in ultimii ani am fost impins sa invat si PHP, Scala si C#.
    Lucrez la IBM ca Lead Archirect, in Bucuresti. Stiati voi ca aveti un IBM chiar aici in Cluj, intr-un sediu nou-nout. In….
    De fapt, cu ajorul IBM sunt astazi aici cu voi.
    Stiu deja ce ganditi… aa.. E architect. Sta undeva langa un ficus si deseneaza pe pereti diagrame UML..
    -NU . Eu bag la cod. Lucrez pe cele mai dificile proiecte pe care le avem.



    La sfarsh:Sala mare -

×