CQRS, React, Docker in a nutshell

CQRS, React, Docker in a nutshell

An journey into the world of Domain Driven Design using Command Query Responsibility Segregation, React and Docker as a deployment tool

21935bc100d813458e925f4a0bef80db?s=128

Andrea Giuliano

March 29, 2016
Tweet

Transcript

  1. CQRS, REACTJS, DOCKER IN A NUTSHELL Andrea Giuliano Claudio D'Alicandro

    Simone Di Maulo
  2. NEW AMAZING PROJECT

  3. WE CAN WRITE IT FROM SCRATCH

  4. BUT

  5. immagine manager incazzato WE NEED IT IN A VERY FEW

    TIME
  6. AND

  7. IT SHOULD BE

  8. WTF!

  9. WHERE DO WE START?

  10. COMFORT ZONE

  11. DOMAIN ▸ data come from and go to external entities

    ▸ users can configure to send a subset of data ▸ users send data based on their plan send data from a source to a target GOAL
  12. THE DOMAIN ▸ unpredictable data structures ▸ ad hoc workflow

    for each vendor ▸ variable number of steps ▸ handle rate limits from different vendors ▸ handle different error cases from different vendors ▸ handle business-oriented limits (based on plans...) ▸ some tasks need to be done asynchronously
  13. IDEA

  14. BLACK BOX REASONING ▸ identify the main entities involved ▸

    define a common input and output ▸ find a way to let things talk INPUT OUTPUT
  15. FROM BLACK BOXES TO BOUNDED CONTEXTS

  16. DEPENDENCIES INFRA BC MODEL APPLICATION PRESENTATION

  17. PROJECT DIRECTORY TREE

  18. APP DIRECTORY TREE

  19. INFRASTRUCTURE DIRECTORY TREE

  20. INSIDE THE BOUNDED CONTEXT

  21. BC DIRECTORY TREE

  22. BC APPLICATION DIRECTORY TREE

  23. BC MODEL DIRECTORY TREE

  24. BC PRESENTATION DIRECTORY TREE

  25. EVERYTHING'S AWESOME ▸ the framework is an implementation detail ▸

    the directory structure is explicit ▸ the domain is isolated
  26. WE DON'T WANT TO MESS THINGS UP

  27. DON'T MESS UP THINGS

  28. WHAT'S THE ISSUE HERE ▸ understandable? ▸ code can't be

    reused ▸ high coupling ▸ untestable ▸ too many responsibilities ▸ hard to find bugs ▸ not changes-prone
  29. WHAT WE WANT

  30. COMMAND QUERY RESPONSIBILITY SEGREGATIONAKA CQRS A SOLUTION

  31. CQRS ▸ separe reads from writes ▸ commands perform actions

    ▸ queries return data ▸ heterogeneous data storages ▸ easy scaling ▸ deal with eventual consistency
  32. WRITE STORAGE QUERY COMMAND COMMAND COMMAND BUS COMMAND HANDLER DOMAIN

    REPOSITORY READ STORAGE REPOSITORY EVENT BUS EVENT SUBSCRIBER
  33. IT'S ALL ABOUT BUSES

  34. IT'S ALL ABOUT BUSES COMMUNICATION

  35. INTERNAL COMMUNICATION BC EVENT COMMAND

  36. MESSAGE BUS $ composer require simple-bus/message-bus

  37. COMMANDS COMMAND BUS Represent the change that should be done

    in the domain 
 They are named with a verb in the imperative tense and may include the aggregate type, for example ScheduleATask.
  38. COMMANDS COMMAND BUS CONTROLLER $commandBus->handle(
 ScheduleATask::fromTaskId($taskId)
 ); HANDLER public function

    handle(Command $command)
 {
 //do something with the $command
 }
  39. EVENTS BC 1 BC 2 EVENT BUS An event represents

    something that took place in the domain. 
 
 They are always named with a past-participle verb, such as TaskScheduled
  40. EVENTS BC 1 BC 2 EVENT BUS subscribes_to: 'user-created' subscribes_to:

    'task-stopped' subscribes_to: 'task-suspended'
  41. EVENTS BC 1 BC 2 EVENT BUS $messageBus->handle(
 UserCreatedEvent::fromUser($user)
 );

    subscribes_to: 'user-created' subscribes_to: 'task-stopped' subscribes_to: 'task-suspended' $messageBus->handle(
 TaskSuspendedEvent::fromTask($task)
 );
  42. COMMUNICATION AMONG BCS BC 1 BC 2 QUEUE NETWORK

  43. QUEUE BC 1 BC 2 QUEUE $producer->publish($message); $consumer->consume($message);

  44. NETWORK BC 1 BC 2 NETWORK $httpClient->post('/tasks/schedule'); POST /tasks/schedule

  45. SCENARIO: TRIGGER THE TASKS SCHEDULE EVERY 10 MINUTES TIMER

  46. SCENARIO: TRIGGER THE TASKS SCHEDULE EVERY 10 MINUTES TIMER SCHEDULER

    POST /tasks/schedule
  47. SCENARIO: TRIGGER THE TASKS SCHEDULE EVERY 10 MINUTES TIMER SCHEDULER

    POST /tasks/schedule DATA STORAGE $taskRepository->getAll()
  48. SCENARIO: TRIGGER THE TASKS SCHEDULE EVERY 10 MINUTES TIMER SCHEDULER

    POST /tasks/schedule DATA STORAGE $taskRepository->getAll() TASK QUEUE enqueue($taskId)
  49. SCENARIO: TRIGGER THE TASKS SCHEDULE EVERY 10 MINUTES TIMER SCHEDULER

    POST /tasks/schedule DATA STORAGE $taskRepository->getAll() TASK QUEUE enqueue($taskId) W1 W2 W3 W..N ...
  50. LET ME SEE WHAT YOU HAVE DONE IT'S TIME TO

    SHOW DOWN
  51. WHAT THE TEAM HAS DELIVERED

  52. WHAT THE MANAGEMENT SEE

  53. WHAT THE MANAGEMENT WANTS

  54. LET'S START FROM THE TEMPLATE

  55. TWIG

  56. THE FRONTEND STUFF

  57. THE FRONTEND STUFF ORDER DEPENDENT

  58. THE FRONTEND STUFF GLOBAL SCOPE

  59. <script>
 $('.btn').click(function(e){
 e.stopPropagation();
 
 // Do something cool!
 
 });


    </script> NEVER TRUST THE GLOBAL SCOPE
  60. A STEP BACKWARD

  61. WE ARE BACKEND DEVELOPERS

  62. OUR COMFORT ZONE

  63. OOP

  64. ENCAPSULATION

  65. MODULES

  66. DEPENDENCY INJECTION

  67. GOOD NEWS

  68. None
  69. ECMASCRIPT 6

  70. DEFAULT VALUES

  71. CLASSES

  72. INHERITANCE

  73. CREATE YOUR MODULES

  74. IMPORT A MODULE

  75. IMPORT ONLY WHAT YOU NEED

  76. WHAT ABOUT THE UI?

  77. None
  78. var React = require('react');
 var ReactDOM = require('react-dom'); ReactDOM.render(
 <h1>Hello,

    world!</h1>,
 document.getElementById('app')
 );
  79. None
  80. https://kangax.github.io/compat-table/es6/

  81. None
  82. ASSETIC CUSTOM FILTERS

  83. None
  84. ANOTHER STEP BACKWARD

  85. REMEMBER THE BOUNDED CONTEXT

  86. A LOT OF SMALL COMPONENTS

  87. A LOT OF SMALL APPLICATIONS

  88. BOUNDED CONTEXT FACEBOOK BOUNDED CONTEXT MAILCHIMP BOUNDED CONTEXT MAPPING

  89. BOUNDED CONTEXT FACEBOOK BOUNDED CONTEXT MAILCHIMP BOUNDED CONTEXT MAPPING

  90. Gulp Bundler + BOUNDED CONTEXT FACEBOOK BOUNDED CONTEXT MAILCHIMP BOUNDED

    CONTEXT MAPPING
  91. DEVELOPMENT WORKFLOW

  92. $ docker/gulp docker-compose run --rm --entrypoint bash npm -c "gulp"

  93. // gulpfile.js
 var gulp = require('gulp');
 var hub = require('gulp-hub');

    process
 .env
 .WEBPACK_CONFIG_FILE = path.join(
 __dirname,
 'webpack.config.js'
 )
 ; hub(['src/**/gulpfile.js']);
  94. BOUNDED CONTEXT FACEBOOK BOUNDED CONTEXT MAILCHIMP BOUNDED CONTEXT MAPPING gulpfile.js

    gulpfile.js gulpfile.js
  95. BOUNDED CONTEXT FACEBOOK gulpfile.js "## FacebookPresentationBundle.php
 $## Resources
 "## assets


    "## config
 "## public
 $## views
  96. $ app/console assets:install LET'S EXPOSE TO THE WEB

  97. APPLICATION ENTRYPOINT

  98. IT'S A BIG WORLD OUT THERE!

  99. None
  100. None
  101. None
  102. None
  103. THE DEVELOPMENT ENVIRONMENT ▸ Easy to use so many technologies

    at no installation cost ▸ Prepare the scaffolding for a new developer is extremely simple ▸ Superior performances over previous systems
  104. docker-compose.yml docker-compose.dev.yml

  105. THE INFRASTRUCTURE

  106. THE INFRASTRUCTURE

  107. THE INFRASTRUCTURE

  108. THE INFRASTRUCTURE

  109. THE INFRASTRUCTURE VS

  110. THE INFRASTRUCTURE VS

  111. STAGE ▸ Automate image building ▸ Copy the same structure

    used in dev
  112. STAGE ▸ Automate image building ▸ Copy the same structure

    used in dev
  113. AUFS: VOLUMES MIGHT BE A LITTLE HARDER THAN IT SEEMS

  114. SYMFONY PARAMETERS

  115. incenteev/composer-parameter-handler

  116. DOCKER CLOUD REPOSITORY CONFIGURATION

  117. None
  118. None
  119. DATA ONLY CONTAINER

  120. DATA ONLY CONTAINER

  121. DATA ONLY CONTAINER

  122. DATA ONLY CONTAINER

  123. FIRST DEPLOY

  124. AN ELEPHANT IN THE ROOM... WE NEED ▸ Automated deploy

    strategy ▸ The freedom to easily scale
  125. SCALE $ docker-compose scale \ web=2 \ worker=3

  126. HARD TRUTH fpm: image: 'adespresso/hubespresso-staging:fpm-latest' deployment_strategy: every_node sequential_deployment: true tags:

    - fpm - hubespresso - production volumes: - /var/www/project volumes_from: - shared-fpm.hubespresso-production SCALE CONTAINERS IS WORTHLESS IF YOU DO NOT SCALE NODES
  127. HARD TRUTH SCALE CONTAINERS IS WORTHLESS IF YOU DO NOT

    SCALE NODES fpm: image: 'adespresso/hubespresso-staging:fpm-latest' deployment_strategy: every_node sequential_deployment: true tags: - fpm - hubespresso - production volumes: - /var/www/project volumes_from: - shared-fpm.hubespresso-production
  128. DATA ONLY CONTAINER IS A PAIN

  129. None
  130. DEPLOYMENT ▸ deploy the infrastructure is not straightforward ▸ multiple

    container in multiple nodes ▸ every container has its own lifecycle ▸ we are not assuring zero-downtime on deployment
  131. THE SOLUTION: GREEN BLUE DEPLOYMENT

  132. THE SOLUTION: GREEN BLUE DEPLOYMENT

  133. THE SOLUTION: GREEN BLUE DEPLOYMENT

  134. CONCLUSION

  135. CQRS PHP7 DOCKER REACTJS MONGODB WEBPACK GULP

  136. LEAVE THE COMFORT ZONE

  137. THANKS

  138. QUESTIONS?