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

Divide and Conquer - 2 Years of CQRS in Production

Divide and Conquer - 2 Years of CQRS in Production

“The MVC pattern solves a problem, that does not exist in the web.” - These few words and some scribbles on the whiteboard has a whole development ideology torn apart in seconds. Mhh, aha, Command Query Responsibility Segregation - Sounds good! And how does one implement this? This session tells the story about the genesis of a PHP micro-framework respecting CQRS, the rethinking of its developers, two years of production experience and the learnings on the road to version 2.0.

Holger Woltersdorf

September 30, 2016
Tweet

More Decks by Holger Woltersdorf

Other Decks in Programming

Transcript

  1. DIVIDE ANDCONQUER 2 YEARS OF CQRS IN PRODUCTION 30. SEPTEMBER

    • CODE.TALKS 2016 • HAMBURG HOLGER WOLTERSDORF
  2. GRÜNDUNGS-MITGLIED DER phpind.de HOLGER WOLTERSDORF CIO • FATHER • HUSBAND

    • PHP DEV github.com/hollodotme github.com/PHPinDD @hollodotme @phpindd
  3. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF KLEINE ZEITREISE 3 2014 2016 2015 MVC vs. CQRS EINFLÜSSE & GRUNDSÄTZE IceHawk 1.0 IceHawk 2.0 Pitfalls
  4. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 5 MODEL VIEW CONTROLLER (MVC)
  5. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 6 ๏ WEB-MVC FAQ [fʌk] ๏ Wie viel Logik gehört ins Model? ๏ Ist das Template meine View? ๏ Was kontrolliert ein Controller? ๏ … und was sind eigentlich Helper?
  6. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 7 (eine nicht gänzlich unbekannte PHP Beratungsfirma)
  7. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 8 ๏ DAS MVC PATTERN VIEW VIEW CONTROLLER MODEL BENUTZER EINGABE MODIFIZIERT AKTUALISIERT
  8. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 9 ๏ DAS MVC PATTERN VIEW VIEW CONTROLLER MODEL BENUTZER EINGABE MODIFIZIERT AKTUALISIERT !
  9. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 10 HTTP ZIEHT EINE NATÜRLICHE GRENZE ZWISCHEN SERVER UND CLIENT (…ja, ja Web-Sockets)
  10. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 11 DAS MVC-PATTERN LÖST EIN PROBLEM, DAS ES IM WEB NICHT GIBT.
  11. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 12 ๏ NEUE FRAGEN ๏ Warum nicht Lesen und Schreiben trennen? ๏ Wird ein Request kontrolliert oder behandelt? ๏ Wir liefern doch Seiten aus, warum gibt es keine Klasse, die Page heißt? ๏ Sollten Schreibvorgänge Ausgabe produzieren? ๏ Was ist ein Framework?
  12. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 13 COMMAND QUERY RESPONSIBILITY SEGREGATION (CQRS)
  13. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 14 ๏ DAS CQRS PATTERN (respektiert HTTP) PAGE 1 PAGE 2 REQUESTHANDLER APP STATE BENUTZER EINGABE MODIFIZIERT VORBEREITEN POST CLIENT / BROWSER REDIRECT ZU PAGE 2 GET GET
  14. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 15 ๏ DAS CQRS PATTERN (respektiert HTTP) PAGE 1 PAGE 2 REQUESTHANDLER APP STATE BENUTZER EINGABE MODIFIZIERT VORBEREITEN POST CLIENT / BROWSER REDIRECT ZU PAGE 2 GET GET
  15. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 16 ๏ CQRS REGELN ๏ Ein POST-Request liefert keinen Content aus ๏ Ein POST-Request kann den App-Zustand ändern ๏ Ein POST-Request antwortet mit einem Redirect ๏ Ein GET-Request liefert Content aus ๏ Ein GET-Request darf nicht den App-Zustand ändern
  16. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 17 MOMENT MAL …
  17. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 18 WAS IST DER UNTERSCHIED ZWISCHEN EINER (GUTEN) REST-API UND EINER WEBSITE?
  18. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 19 ๏ REST-API ๏ REST-API ändert Ressourcen durch Schreibbefehle (POST / PUT / PATCH / DELETE) ๏ REST-API verweist auf geänderte Ressourcen 
 (z.B. durch HATEOAS*-Tags) ๏ REST-API liefert Ressourcen im aktuellen Zustand durch Leseanfragen (GET) ๏ REST-API liefert Information über das Vorhandensein von Ressourcen und möglichen Aktionen (HEAD / OPTIONS) * HATEOAS = Hypermedia As The Engine Of Application State
  19. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 20 ๏ WEBSITE ๏ Website ändert den App-State durch Schreibbefehle 
 (POST [/ PUT / PATCH / DELETE]) ๏ Website verweist auf geänderte Seiten (REDIRECT) ๏ Website liefert Seiten im aktuellen Zustand durch Leseanfragen (GET) ๏ Website liefert Information über das Vorhandensein von Seiten und möglichen Aktionen (HEAD / OPTIONS)
  20. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 21 ๏ REST-API != WEBSITE ๏ Website hat einen "flüchtigen" Zustand (Session) ๏ Website liefert HTML statt XML/JSON/etc. aus
  21. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 22 SUPRISE, SUPRISE! GUTE REST-APIs SETZEN AUF CQRS
  22. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF MVC vs. CQRS 23 OKAY. UND WIE IMPLEMENTIERT MAN DAS JETZT?
  23. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF 24 EINFLÜSSE & GRUNDSÄTZE
  24. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF EINFLÜSSE & GRUNDSÄTZE 25 https://37signals.com/manifesto Google Group DDDinPHP http://DDDinPHP.org Gestartet von Mathias Verraes
  25. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF EINFLÜSSE & GRUNDSÄTZE 26 ๏ REWORK ๏ Schaffe Overhead ab ๏ Mach es selbst, bis es nicht mehr geht ๏ Entwickle Software für dein Business ๏ Sei konsequent und ehrlich ๏ Mach es so einfach wie möglich
  26. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF EINFLÜSSE & GRUNDSÄTZE 27 ๏ CLEAN CODE ๏ Namen und Lesbarkeit sind wichtig ๏ Inline-Kommentare sind redundanter Müll ๏ Kohäsion in Klassen ๏ SOLID Prinzipien ๏ Richtig testen & stetiges Refactoring
  27. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF EINFLÜSSE & GRUNDSÄTZE 28 ๏ GOOGLE GROUP DDD IN PHP ๏ Konvention für Interface-, Class- und Trait-Namen ๏ Domains & Subdomains ๏ Commands & Queries ๏ Aggregates, Entities & Value Objects ๏ Event Sourcing für besseres Verständnis von CQRS
  28. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF EINFLÜSSE & GRUNDSÄTZE 29 UNSERE 4 GRUNDSÄTZE
  29. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF EINFLÜSSE & GRUNDSÄTZE 30 NO MAGIC $product = Rage::getModel('catalog/product'); # vs. $product = new Catalog\Product();
  30. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF EINFLÜSSE & GRUNDSÄTZE 31 WRITE MORE - DO LESS ๏ Spalte Zuständigkeiten in (viele) Klassen auf ๏ Schreibe kurze & aussagekräftige Methoden ๏ Benutze Interfaces, Value-Objects und Type-Hints ๏ Teile keinen Business-Code in mehreren Projekten
  31. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF EINFLÜSSE & GRUNDSÄTZE 32 USE (plain) PHP ๏ Lerne PHPs Funktionsumfang zu nutzen ๏ Vermeide Drittanbieter-Libraries ๏ Verstehe das Problem - Löse es selbst
  32. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF EINFLÜSSE & GRUNDSÄTZE 33 THINK ABOUT THE NEXT DEV ๏ Schreibe unmissverständlichen, weisenden Code ๏ Vergebe sprechende (auch lange) Namen ๏ Schreibe (vollständige) Tests
  33. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF EINFLÜSSE & GRUNDSÄTZE 34 NAMENS-KONVENTION interface LogsActivity {} class ActivityLogger {} trait ActivityLogging {} class ActivityLogger implements LogsActivity { use ActivityLogging; }
  34. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF 35 «Wir brauchen einen Namen!» «Ja, irgendwas cooles schnelles!»
  35. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF 36 ICEHAWK 1.0
  36. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 37
  37. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 38 ๏ WAS IST EIN FRAMEWORK? ๏ Session- & Error-Handling initialisieren ๏ URIs auflösen & umschreiben ๏ Lese-Request-Daten weiter reichen ๏ Schreib-Request-Daten weiter reichen ๏ Requests behandeln ๏ Seiten ausliefern & Umleiten ๏ Finale Fehler-Behandlung (für 404 / 500 Seiten)
  38. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 39 class IceHawk { public function __construct( $config, $delegate ) public function init() {} public function handleRequest() {} }
  39. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 40 REQUESTS & RESPONSES
  40. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 41 class RequestInfo {} class GetRequest {} abstract class GetRequestHandler {} class PostRequest {} abstract class PostRequestHandler {} REQUEST-VERARBEITUNG
  41. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 42 class Page {} class NotFound {} class InternalServerError {} class Redirect {} RESPONSES
  42. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 43 DELEGATION & KONFIGURATION
  43. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 44 class IceHawkDelegate { public function setUpSessionHandling() {} public function setUpErrorHandling() {} public function handleUncaughtException( \Exception $exception ) {} } DELEGATION
  44. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 45 class IceHawkConfig { public function getRequestInfo() {} public function getUriResolver() {} public function getUriRewriter() {} public function getDomainNamespace() {} } KONFIGURATION
  45. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 46 class UriResolver { public function resolveUri(RequestInfo $requestInfo) { # Löse die URI hier auf einen RequestHandler auf return new UriComponents('Products', 'ShowGallery'); } }
  46. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 47 class UriRewriter { public function rewriteUri(RequestInfo $requestInfo) { # Schreibe die URI hier um (new Redirect('/code/talks/2016'))->respond(); } }
  47. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 48 class SessionRegistry {} class FormData {} class Command {} class Query {} class IceHawkWasInitializedEvent {} class HandlingRequestEvent {} class RequestWasHandledEvent {} UND…
  48. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 49 RELEASED 30.05.2015
  49. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 50 PAGE 1 PAGE 2 PostRequestHandler MYSQL BENUTZER EINGABE COMMAND QUERY POST CLIENT / BROWSER REDIRECT GET GET GetRequestHandler GetRequestHandler
  50. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 51 PAGE 1 PAGE 2 PostRequestHandler MYSQL BENUTZER EINGABE COMMAND QUERY POST CLIENT / BROWSER REDIRECT GET GET GetRequestHandler GetRequestHandler
  51. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 52 PAGE 1 PAGE 2 PostRequestHandler MYSQL BENUTZER EINGABE COMMAND QUERY POST CLIENT / BROWSER REDIRECT GET GET GetRequestHandler GetRequestHandler
  52. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 53 SCHNELLE AUTOS HABEN ZWEI ENDROHRE
  53. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 54 PAGE 1 PAGE 2 PostRequestHandler MYSQL BENUTZER EINGABE COMMAND QUERY POST CLIENT / BROWSER REDIRECT GET GET GetRequestHandler GetRequestHandler
  54. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 55 ETWAS ÜBER 1 JAHR UND…
  55. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 56
  56. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 1.0 57
  57. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF PITFALLS 59 ๏ OPT-IN E-MAILS ๏ RETURN-URLs (z.B. EXTERNE BEZAHLSYSTEM) ๏ AJAX ๏ CSRF TOKENS ๏ UNVOLLSTÄNDIGE READ/WRITE TRENNUNG ๏ UNFLEXIBLES ZUWEISEN VON REQUEST-HANDLERN …WEIL MAGIC ๏ DEFAULT-ROUTING ๏ VERLETZUNG DES SOC-PRINZIPS
  58. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF PITFALLS 60 ๏ OPT-IN E-MAILS ๏ Kein POST-Request möglich ๏ Option 1: Erneut ein Formular anzeigen ๏ Option 2: Die State-Änderung via GET-Request zulassen + REDIRECT
  59. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF PITFALLS 61 ๏ RETURN-URLs ๏ Kommen i.d.R. via GET-Request zurück ๏ Lösung: Die State-Änderung via GET-Request zulassen + REDIRECT
  60. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF PITFALLS 62 ๏ AJAX ๏ Redirects auf GET-Request funktionieren auch nach einem POST-XHR ๏ ALLES GUT
  61. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF PITFALLS 63 ๏ CSRF-TOKEN ๏ Gehört die Session zum App-State? ๏ Lösung: Nein. Die Session darf auch bei GET-Requests verändert werden.
  62. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF PITFALLS 64 ๏ UNVOLLSTÄNDIGE READ/WRITE TRENNUNG ๏ Trennung erfolgte erst nach dem Resolving ๏ Events unterschieden nicht nach Read/Write ๏ Finale Fehlerbehandlung unterschied nicht nach Read/Write
  63. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF PITFALLS 65 ๏ UNFLEXIBLES ZUWEISEN VON REQUEST-HANDLERN …WEIL MAGIC ๏ Suchpfad von Request-Handlern war je Projekt fix ๏ Beim Resolving war nicht ersichtlich, ob auf einen Read oder Write Handler aufgelöst wurde
  64. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF PITFALLS 66 ๏ DEFAULT-ROUTING ๏ Handler waren oft über 2 URIs erreichbar ๏ Lösung: Default-Routing abschaffen.
  65. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF PITFALLS 67 ๏ VERLETZUNG DES SOC-PRINZIPS ๏ Session-Wrapper gehörte nicht ins Framework ๏ FormData gehörte nicht ins Framework ๏ Command / Query gehörten nicht ins Framework
  66. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF 69 REFACTORING
  67. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF 70 ICEHAWK 2.0
  68. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 2.0 71 public function getReadRoutes() { return [ new ReadRoute( new Literal('/products/gallery'), new ProductGalleryRequestHandler() ), #... ]; } NO MAGIC, REALLY
  69. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 2.0 72 class FinalReadResponder { public function handleUncaughtException( \Throwable $throwable, ProvidesReadRequestData $request ); } FINAL RESPONDING R/W
  70. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 2.0 73 class InitializingIceHawkEvent {} class IceHawkWasInitializedEvent {} class HandlingReadRequestEvent {} class ReadRequestWasHandledEvent {} class HandlingWriteRequestEvent {} class WriteRequestWasHandledEvent {} EVENTS R/W
  71. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 2.0 74 ๏ WEITERE "FEATURES" ๏ Unterstützung aller HTTP-Methoden ๏ Interfaces definieren die erlaubten HTTP-Methoden ๏ Auto-Responding auf OPTIONS-Request ๏ "Traitful" Config (Defaults via Traits) ๏ Kein Default-Routing mehr ๏ Literal, RegExp und NamedRegExp URI-Patterns
  72. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF ICEHAWK 2.0 75 ๏ NEUE PACKAGES ๏ CSRF-Token Support und Feedback (Forms) ๏ Session Data Mapping (Session) ๏ Messaging (PubSub)
  73. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF 76 ICEHAWK FORMS SESSION PUBSUB COMING SOON EVENTSTORE
  74. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF 77 BUILD PASSING COVERAGE 100% LICENSE MIT
  75. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF 78 github.com/icehawk
  76. phpind.de VIELEN DANK! github.com/hollodotme github.com/PHPinDD @hollodotme / @phpindd fortuneglobe.com www.phpug-dresden.org

    @phpugdd HOLGER WOLTERSDORF https://joind.in/talk/f5095 slides available on slideshare FEEDBACK WELCOME github.com/icehawk
  77. DIVIDE AND CONQUER • 2 YEARS OF CQRS IN PRODUCTION

    HOLGER WOLTERSDORF LINKS / REFERENCES 81 ๏ MVC-Pattern: http://martinfowler.com/eaaDev/uiArchs.html ๏ CQRS-Pattern: http://martinfowler.com/bliki/CQRS.html ๏ "Rework" by David Heinemeier Hansson: http://amzn.to/2cWOwxQ ๏ "Clean Code" by Robert C. Martin: http://amzn.to/2dthxQn ๏ Google-Group DDDinPHP: https://groups.google.com/forum/#!forum/dddinphp ๏ "Traitful" Configs: https://phpind.de/posts/traitful-configs ๏ IceHawk Framework on GitHub: https://github.com/icehawk