1 of 48

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']

});

2 of 48

Hi !

StyleLounge

Me

@alexanderthiel�me@alexthiel.degithub.com/reasnlinkedin.com/in/reasnxing.com/profile/Alex_Thiel

  • I manage @StyleLounge's great engineers.
  • We build reactive microservices at scale.
  • Price comparison for fashion
  • 3 years old
  • > 2M visits
  • 6 countries (ch, de, fr, nl, se, us)
  • 45 people
  • 12 devs

StyleLounge.io�(team, pictures, stack)

3 of 48

Patterns for Reactive

Node.js Microservices

slides: StyleLounge.io

4 of 48

Service Oriented�Architectures

Microservices

Reactive

Microservices

5 of 48

The Reactive Manifesto

Reactive Software is

  • Responsive
  • Resilient
  • Elastic
  • Message driven

6 of 48

Message / Event-Driven

Types of message/event-driven communications

  • Event notification
  • Event-carried state transfer
  • Event sourcing

7 of 48

Message / Event-Driven

Types of message/event-driven communications

  • Event notification
  • Event-carried state transfer
  • Event sourcing

8 of 48

Focus on Data Flow

B

A

C

D

A queries DB

DB

B polls A

B push-notifies C

D subscribes to C

9 of 48

Focus on Data Flow

B

A

C

D

A queries DB

DB

B polls A

B push-notifies C

D subscribes to C

10 of 48

Service Interactions

Webapp

Scoring

Product-�Catalog

Tracking

Mailing

11 of 48

Resilience

Webapp

Scoring

Product-�Catalog

Tracking

Mailing

12 of 48

Properties of Reactive Systems

  • Each service maintains its own state
    • data is heavily duplicated
    • each service has its own BoundedContext
  • Data flow > data models

13 of 48

StyleLounge after almost 2 years of Microservices

Six countries with each

  • 20 databases
  • 10 brokers
  • 85 individual (micro)services (some clustered)

2,500+ containers�20-30 deployments per day

14 of 48

Patterns

slides: StyleLounge.io

15 of 48

Patterns are small reusable structures that allow …

  • a focused discussion of
    • Applicability
    • Expected impact
  • forks
  • efficient speech by replacing concepts with terms

16 of 48

Basics

  • 12factor
  • Testing

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

  • Continuous Integration
  • Linting

17 of 48

Design Phase

slides: StyleLounge.io

18 of 48

Know Your Weaknesses

  • Reactive microservices
    • scale by design
    • require powerful monitoring
  • Technologies solve problems and create others
  • There’s no silver bullet
  • But some bullets are better against vampires than others

19 of 48

Walking Skeleton

  • It’s easy to underestimate integration #worksOnMyMachine
  • Deploy before adding business logic
  • Create service with hardcoded mock data
  • Deploying mock data - design for failure

20 of 48

Canonical Names

mailing

scoring

tracking

scoring

tracking

tracking

tracking

mailing

scoring

scoring

scoring

product-catalog

mailing

mailing

mailing

21 of 48

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

22 of 48

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

23 of 48

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

24 of 48

Data Structures

slides: StyleLounge.io

25 of 48

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 ...

  • are easy to fabricate
  • are language independent
  • are immutable
  • aggregate to values

26 of 48

Validate first

async handleMessage(car) {

try { � await validate(car)

} catch (error) {

return reject(error.message);

}� console.log(car.driver);

}

  • Protects during runtime
  • Less unit tests for invalid input

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

27 of 48

Structural Interface Schemas

  • Object classes provide structural safety
  • Better:�flow/TypeScript + schema validation

interface IUser {

name: string;

petUnicorn: { name: string; age: number; };

}

28 of 48

Errors

slides: StyleLounge.io

29 of 48

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;

}

30 of 48

If we embrace crashing :)

const fetch = () => query(`SELECT red FROM gummi_bears`);

31 of 48

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

);

}

32 of 48

Never catch generic errors (catch less)

  • Execution paths in try-blocks change
  • Unanticipated errors are caught
  • The app is a zombie
  • Better:

} catch (error) {

if (!error.message.match(/no red found/) {

throw error;

}

console.warn(“Could not find red”);

}

33 of 48

Reuse

slides: StyleLounge.io

34 of 48

DRY has big downsides

  • Extracting code from two places couples them together
  • Overestimated immediate savings
  • Underestimated maintainability issues�
  • Copy-paste is dangerous and often bad
  • But copying and adapting is the definition of learning�
  • Coding is little about code and a lot about understanding a problem

35 of 48

Thou shall not create frameworks ;)

  • Frameworks lock in our current state of domain knowledge�
  • Brevity has no intrinsic value.�Maintainability does.�
  • Many of us have written a framework that nobody should actually use

36 of 48

Migration

slides: StyleLounge.io

37 of 48

Reactive Facade

Legacy Macroservice

Database

38 of 48

Reactive Facade

Legacy Macroservice

Database

A

39 of 48

Reactive Facade

Legacy Macroservice

Legacy�Publisher

Database

A

40 of 48

Reactive Facade

Legacy Macroservice

Legacy�Publisher

Database

A

B

41 of 48

Reactive Facade

D

Legacy Macroservice

Legacy�Publisher

Database

A

B

42 of 48

Reactive Facade

D

Legacy Macroservice

Legacy�Publisher

Database

A

C

B

43 of 48

Reactive Facade

D

Legacy Macroservice

Legacy�Publisher

Legacy�Persister

Database

A

C

B

44 of 48

Meta

slides: StyleLounge.io

45 of 48

Monitoring is the unit testing of dynamic systems

  • Unit tests check deploy-time behavior against expectations
  • Manual checks of eventually consistent systems suck
  • Monitoring
    • Logging ELK
    • Metering Prometheus
    • Alerting Prometheus
    • Frequent automated consistency probes Custom

46 of 48

Collect patterns

“RangeError: Maximum call stack size exceeded”�Luis Ricardo Falero, Oil on canvas, 1878�

classicprogrammerpaintings.com/post/154133754039

47 of 48

Thank You!

patterns: patterns.StyleLounge.io

slides: StyleLounge.io

Join StyleLounge. Today!

48 of 48

References & Further Reading