const StyleLounge.getStack = async () => ({
architecture: 'reactive microservices',
hosting: ['gcloud', 'aws'],
monitoring: ['grafana', 'prometheus'],
deployment: ['wercker', 'kubernetes', 'terraform'],
persistence: ['redis', 'mongo', 'neo4j', 'BigQuery',
'elasticsearch', 'MySQL', 'Riak KV', 'InfluxDB'],
languages: ['TypeScript', 'ESnext'],
runtimes: ['node.js', 'electron', 'nextgen browsers only'],
brokers: ['rabbitmq'],
client: ['react', 'redux', 'redux-saga', 'BEM'],
build: ['webpack', 'postCSS', 'tslint'],
testing: ['mocha', 'chai', 'istanbul', 'ava', cucumber'],
tools: ['@style/kbomb', @style/peacekeeper'],
office: ['Slack', 'G Suite', 'Fridge with beers'],
team: {devs: 12, nations: 10, hiring: true, seniorReferralFee: 2000},
legacy: new Date() > new Date('2017-06')
? []
: ['PHP', 'angular.js', 'sass/compass',� 'Ansible', 'Stackdriver']
});
Hi !
StyleLounge
Me
@alexanderthiel�me@alexthiel.de�github.com/reasn�linkedin.com/in/reasn�xing.com/profile/Alex_Thiel
StyleLounge.io�(team, pictures, stack)
Patterns for Reactive
Node.js Microservices
slides: StyleLounge.io
Service Oriented�Architectures
Microservices
Reactive
Microservices
The Reactive Manifesto
Reactive Software is
Message / Event-Driven
Types of message/event-driven communications
Message / Event-Driven
Types of message/event-driven communications
Focus on Data Flow
B
A
C
D
A queries DB
DB
B polls A
B push-notifies C
D subscribes to C
Focus on Data Flow
B
A
C
D
A queries DB
DB
B polls A
B push-notifies C
D subscribes to C
Service Interactions
Webapp
Scoring
Product-�Catalog
Tracking
Mailing
Resilience
Webapp
Scoring
Product-�Catalog
Tracking
Mailing
Properties of Reactive Systems
StyleLounge after almost 2 years of Microservices
Six countries with each
2,500+ containers�20-30 deployments per day
Patterns
slides: StyleLounge.io
Patterns are small reusable structures that allow …
Basics
Simple Testing Can Prevent Most Critical Failures
“... for the most catastrophic failures, almost all of them are caused by incorrect error handling, and 58% of them are trivial mistakes or can be exposed by statement coverage testing.” - acm.org/citation.cfm?id=2685068
Design Phase
slides: StyleLounge.io
Know Your Weaknesses
Walking Skeleton
Canonical Names
mailing
scoring
tracking
scoring
tracking
tracking
tracking
mailing
scoring
scoring
scoring
product-catalog
mailing
mailing
mailing
Canonical Names
tracking
tracking
tracking
tracking
product-catalog
scoring-product-�persister
scoring-tracking-�persister
scoring-�calculator
scoring-�product-db
scoring-�tracking-db
mailing
mailing
mailing
mailing
mailing
Canonical Names
mailing-product-�persister
scoring-product-�persister
tracking-�event-emitter
product-catalog
scoring-tracking-�persister
mailing-tracking-�persister
tracking-�pixel
tracking-�persister
tracking-�db
mailing-�recommender
mailing-�publisher
scoring-�calculator
scoring-�product-db
scoring-�tracking-db
mailing-db
Canonical Names
s-scoring-calculator-de-1
s-scoring-persister-de-1
s-scoring-persister-de-5
p-scoring-persister-de-1
p-scoring-persister-de-5
p-scoring-persister-us-1
p-scoring-persister-us-5
...
...
...
p-scoring-calculator-de-1
p-scoring-calculator-us-1
Data Structures
slides: StyleLounge.io
Values > Objects
class User {
petUnicorn = null;
constructor(name) {
this.name = name;
}
}
class PetUnicorn {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
const a = new User("Meister Eder");
a.petUnicorn = new PetUnicorn("Erwin", 13);
const b = {
name: "Meister Eder",
petUnicorn: {
name: "Erwin",
age: 13
}
};
Values ...
Validate first
async handleMessage(car) {
try { � await validate(car)
} catch (error) {
return reject(error.message);
}� console.log(car.driver);
}
myTypedFunction(name: string, age: number) {
ok(name.length > 10, "name too short");
myFunction(name, age) {� ok(typeof name === "string",
"namemust be string");
ok(name.length > 10, "name too short");
Structural Interface Schemas
interface IUser {
name: string;
petUnicorn: { name: string; age: number; };
}
Errors
slides: StyleLounge.io
Error Handling
const fetch = async () => fetchWithRetries(5);
const fetchWithRetries = async (retriesLeft) => {
let result;
try {
result = await query(`SELECT red FROM gummi_bears`);
} catch (error) {
if (retriesLeft > 0
&& typeof error === "object"
&& ( error.message.match(/db gone/) || error.message.match(/timeout/) )
) {
try {
await disconnect();
} catch(error) { /* ignored */ }
await sleep(1000);
return fetchWithRetries(retriesLeft - 1);
}
throw error;
}
return result;
}
If we embrace crashing :)
const fetch = () => query(`SELECT red FROM gummi_bears`);
Error Handling II
async function eat () {
try {
return await query(`GET red FROM gummibears`);
} catch (error) {
console.warn(“Could not find food” + error.message);
return [];
}
}
async function query(queryString) {
return (
await cache.get(queryString)
||
request(“http://my-database.google.com”, {query: queryString})
);
}
Never catch generic errors (catch less)
} catch (error) {
if (!error.message.match(/no red found/) {
throw error;
}
console.warn(“Could not find red”);
}
Reuse
slides: StyleLounge.io
DRY has big downsides
Thou shall not create frameworks ;)
Migration
slides: StyleLounge.io
Reactive Facade
Legacy Macroservice
Database
Reactive Facade
Legacy Macroservice
Database
A
Reactive Facade
Legacy Macroservice
Legacy�Publisher
Database
A
Reactive Facade
Legacy Macroservice
Legacy�Publisher
Database
A
B
Reactive Facade
D
Legacy Macroservice
Legacy�Publisher
Database
A
B
Reactive Facade
D
Legacy Macroservice
Legacy�Publisher
Database
A
C
B
Reactive Facade
D
Legacy Macroservice
Legacy�Publisher
Legacy�Persister
Database
A
C
B
Meta
slides: StyleLounge.io
Monitoring is the unit testing of dynamic systems
Collect patterns
“RangeError: Maximum call stack size exceeded”�Luis Ricardo Falero, Oil on canvas, 1878�
Thank You!
patterns: patterns.StyleLounge.io
slides: StyleLounge.io
Join StyleLounge. Today!
References & Further Reading