CQRS, ReactJS, Docker in a nutshell

Post on 12-Apr-2017

693 views 2 download

Transcript of CQRS, ReactJS, Docker in a nutshell

CQRS, REACTJS, DOCKERIN A NUTSHELL

Andrea GiulianoClaudio D'Alicandro Simone Di Maulo

NEW AMAZING PROJECT

WE CAN WRITE IT FROM SCRATCH

BUT

immagine manager incazzato

WE NEED IT IN A VERY FEW TIME

AND

IT SHOULD BE

WTF!

WHERE DO WE START?

COMFORT ZONE

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 targetGOAL

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

IDEA

BLACK BOX REASONING▸ identify the main entities involved

▸ define a common input and output

▸ find a way to let things talk

INPUT OUTPUT

FROM BLACK BOXES TO BOUNDED CONTEXTS

DEPENDENCIES INFRA BC

MODEL

APPLICATION

PRESENTATION

PROJECT DIRECTORY TREE

APP DIRECTORY TREE

INFRASTRUCTURE DIRECTORY TREE

INSIDE THE BOUNDED CONTEXT

BC DIRECTORY TREE

BC APPLICATION DIRECTORY TREE

BC MODEL DIRECTORY TREE

BC PRESENTATION DIRECTORY TREE

EVERYTHING'S AWESOME

▸ the framework is an implementation detail

▸ the directory structure is explicit

▸ the domain is isolated

WE DON'T WANT TO MESS THINGS UP

DON'T MESS UP THINGS

WHAT'S THE ISSUE HERE

▸ understandable?

▸ code can't be reused

▸ high coupling

▸ untestable

▸ too many responsibilities

▸ hard to find bugs

▸ not changes-prone

WHAT WE WANT

COMMAND QUERY RESPONSIBILITY SEGREGATION AKA CQRS

A SOLUTION

CQRS

▸ separe reads from writes

▸ commands perform actions

▸ queries return data

▸ heterogeneous data storages

▸ easy scaling

▸ deal with eventual consistency

WRITE STORAGE

QUERY

COMMAND

COMMAND

COMMAND BUS

COMMAND HANDLERDOMAIN

REPOSITORY

READ STORAGEREPOSITORY

EVENT BUS

EVENT SUBSCRIBER

IT'S ALL ABOUT BUSES

IT'S ALL ABOUT BUSES COMMUNICATION

INTERNAL COMMUNICATION

BC

EVENT

COMMAND

MESSAGE BUS

$ composer require simple-bus/message-bus

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.

COMMANDS

COMMAND BUS

CONTROLLER

$commandBus->handle( ScheduleATask::fromTaskId($taskId) );

HANDLER

public function handle(Command $command) { //do something with the $command }

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

EVENTS

BC 1 BC 2

EVENT BUS

subscribes_to: 'user-created'

subscribes_to: 'task-stopped'

subscribes_to: 'task-suspended'

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) );

COMMUNICATION AMONG BCS

BC 1 BC 2

QUEUE

NETWORK

QUEUE

BC 1 BC 2

QUEUE

$producer->publish($message); $consumer->consume($message);

NETWORK

BC 1 BC 2

NETWORK

$httpClient->post('/tasks/schedule');

POST /tasks/schedule

SCENARIO: TRIGGER THE TASKS SCHEDULE EVERY 10 MINUTES

TIMER

SCENARIO: TRIGGER THE TASKS SCHEDULE EVERY 10 MINUTES

TIMER SCHEDULERPOST /tasks/schedule

SCENARIO: TRIGGER THE TASKS SCHEDULE EVERY 10 MINUTES

TIMER SCHEDULERPOST /tasks/schedule

DATA STORAGE

$taskRepository->getAll()

SCENARIO: TRIGGER THE TASKS SCHEDULE EVERY 10 MINUTES

TIMER SCHEDULERPOST /tasks/schedule

DATA STORAGE

$taskRepository->getAll()

TASK QUEUE

enqueue($taskId)

SCENARIO: TRIGGER THE TASKS SCHEDULE EVERY 10 MINUTES

TIMER SCHEDULERPOST /tasks/schedule

DATA STORAGE

$taskRepository->getAll()

TASK QUEUE

enqueue($taskId)

W1 W2 W3 W..N...

LET ME SEE WHAT YOU HAVE DONE

IT'S TIME TO SHOW DOWN

WHAT THE TEAM HAS DELIVERED

WHAT THE MANAGEMENT SEE

WHAT THE MANAGEMENT WANTS

LET'S START FROM THE TEMPLATE

TWIG

THE FRONTEND STUFF

THE FRONTEND STUFFORDER DEPENDENT

THE FRONTEND STUFF

GLOBAL SCOPE

<script> $('.btn').click(function(e){

e.stopPropagation(); // Do something cool! }); </script>

NEVER TRUST THE GLOBAL SCOPE

A STEP BACKWARD

WE ARE BACKEND DEVELOPERS

OUR COMFORT ZONE

OOP

ENCAPSULATION

MODULES

DEPENDENCY INJECTION

GOOD NEWS

ECMASCRIPT 6

DEFAULT VALUES

CLASSES

INHERITANCE

CREATE YOUR MODULES

IMPORT A MODULE

IMPORT ONLY WHAT YOU NEED

WHAT ABOUT THE UI?

var React = require('react'); var ReactDOM = require('react-dom');

ReactDOM.render( <h1>Hello, world!</h1>, document.getElementById('app') );

https://kangax.github.io/compat-table/es6/

ASSETIC CUSTOM FILTERS

ANOTHER STEP BACKWARD

REMEMBER THE BOUNDED CONTEXT

A LOT OF SMALL COMPONENTS

A LOT OF SMALL APPLICATIONS

BOUNDED CONTEXT FACEBOOK BOUNDED CONTEXT MAILCHIMPBOUNDED CONTEXT MAPPING

BOUNDED CONTEXT FACEBOOK BOUNDED CONTEXT MAILCHIMPBOUNDED CONTEXT MAPPING

Gulp Bundler

+

BOUNDED CONTEXT FACEBOOK BOUNDED CONTEXT MAILCHIMPBOUNDED CONTEXT MAPPING

DEVELOPMENT WORKFLOW

$ docker/gulp

docker-compose run --rm --entrypoint bash npm -c "gulp"

// 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']);

BOUNDED CONTEXT FACEBOOK BOUNDED CONTEXT MAILCHIMPBOUNDED CONTEXT MAPPING

gulpfile.js gulpfile.js gulpfile.js

BOUNDED CONTEXT FACEBOOK

gulpfile.js

"## FacebookPresentationBundle.php $## Resources "## assets "## config "## public $## views

$ app/console assets:install

LET'S EXPOSE TO THE WEB

APPLICATION ENTRYPOINT

IT'S A BIG WORLD OUT THERE!

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

docker-compose.yml docker-compose.dev.yml

THE INFRASTRUCTURE

THE INFRASTRUCTURE

THE INFRASTRUCTURE

THE INFRASTRUCTURE

THE INFRASTRUCTURE

VS

THE INFRASTRUCTURE

VS

STAGE

▸ Automate image building

▸ Copy the same structure used in dev

STAGE

▸ Automate image building

▸ Copy the same structure used in dev

AUFS: VOLUMES MIGHT BE A LITTLE HARDER THAN IT SEEMS

SYMFONY PARAMETERS

incenteev/composer-parameter-handler

DOCKER CLOUD REPOSITORY CONFIGURATION

DATA ONLY CONTAINER

DATA ONLY CONTAINER

DATA ONLY CONTAINER

DATA ONLY CONTAINER

FIRST DEPLOY

AN ELEPHANT IN THE ROOM... WE NEED

▸ Automated deploy strategy

▸ The freedom to easily scale

SCALE

$ docker-compose scale \web=2 \worker=3

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

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

DATA ONLY CONTAINER IS A PAIN

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

THE SOLUTION: GREEN BLUE DEPLOYMENT

THE SOLUTION: GREEN BLUE DEPLOYMENT

THE SOLUTION: GREEN BLUE DEPLOYMENT

CONCLUSION

CQRSPHP7

DOCKERREACTJS

MONGODBWEBPACKGULP

LEAVE THE COMFORT ZONE

THANKS

QUESTIONS?