The Services your Microservices Could Be LiKe
Ethan Garofolo - OpenWest 2017
Who am I?
Ethan Garofolo - ethan@suchsoftware.com
Software consultant - I help companies make the transition to microservices
Used to run Learn All the Nodes
What is the opposite of a services-based architecture?
The monolith!
Image credit: https://upload.wikimedia.org/wikipedia/en/5/53/African_monolith_2001.jpg
What’s a monolith?
kloc < 300
Running on different machines
kloc < 300
Running on different machines
What is a monolith?
What is an entity focus?
Implicit coupling in the database
The User Model
“Extract microservices”
users
products
users
products
These lines are function calls
users
products
users
products
users
products
What are these lines now?
users
products
users
products
users
products
users
products
What defines a service?
Autonomy
Services are autonomous
How do you get services to do anything?
https://xkcd.com/1312/
“Extract microservices”
Take Two
“JUST EXTRACT KITTENS FROM THIS SLIDE.” -- The Blogosphere
users
products
Asynchronous events
Case Study: HPC resource management
HPC assets used by scientists
Needed to manage access to them
Existing application could not adapt to the needs
API
?
Event bus
Legacy runtime
dispatch
New runtime
send-email
move-files
API
?
Event bus
Legacy runtime
dispatch
New runtime
send-email
move-files
API
?
Event bus
Legacy runtime
dispatch
New runtime
send-email
move-files
Job requested!
API
?
Event bus
Legacy runtime
dispatch
New runtime
send-email
move-files
API
?
Event bus
Legacy runtime
dispatch
New runtime
send-email
move-files
I started moving the files
yawn
noted
API
?
Event bus
Legacy runtime
dispatch
New runtime
send-email
move-files
API
?
Event bus
Legacy runtime
dispatch
New runtime
send-email
move-files
noted
API
?
Event bus
Legacy runtime
dispatch
New runtime
send-email
move-files
I finished moving the files
API
?
Event bus
Legacy runtime
dispatch
New runtime
send-email
move-files
API
?
Event bus
Legacy runtime
dispatch
New runtime
send-email
move-files
noted
API
?
Event bus
Legacy runtime
dispatch
New runtime
send-email
move-files
I scheduled the job to run
API
?
Event bus
Legacy runtime
dispatch
New runtime
send-email
move-files
Big win #1: Testing
API
?
Event bus
Legacy runtime
dispatch
New runtime
send-email
move-files
Test harness
send-email
Big win #2: Other teams not moving fast enough
API
?
Event bus
Legacy runtime
dispatch
New runtime
send-email
move-files
API
?
Event bus
dispatch
simulate-jobs
send-email
move-files
Big win #3: New features
API
?
Event bus
Legacy runtime
dispatch
New runtime
send-email
move-files
API
?
Event bus
Legacy runtime
dispatch
New runtime
send-email
move-files
send-sms
What changes were required everywhere else?
Big win #4: Leveraged existing system
And this was all cool, but...
API
?
Event bus
Legacy runtime
dispatch
New runtime
send-email
move-files
What happened to the events themselves?
send-sms
Event Sourcing
Traditional way of storing data
Web server
Biz
logic
DB
buttons
id | name | clicks |
| | |
Web server
req.body = {
name: “foo”,
}
Biz
logic
DB
buttons
id | name | clicks |
| | |
POST /buttons
Web server
req.body = {
name: “foo”,
}
Biz
logic
DB
buttons
id | name | clicks |
| | |
Web server
req.body = {
name: “foo”,
}
Biz
logic
DB
buttons
id | name | clicks |
1 | foo | 0 |
Web server
Biz
logic
DB
id | name | clicks |
1 | foo | 0 |
buttons
Web server
Biz
logic
DB
id | name | clicks |
1 | foo | 1 |
buttons
req.body = {
buttonId: 1,
}
POST /buttons/1/click
Web server
Biz
logic
DB
id | name | clicks |
1 | foo | 2 |
buttons
req.body = {
buttonId: 1,
}
POST /buttons/1/click
Web server
Biz
logic
DB
id | name | clicks |
1 | foo | 3 |
buttons
req.body = {
buttonId: 1,
}
POST /buttons/1/click
Implications
id | name | clicks |
1 | foo | 3 |
buttons
Event Sourcing
Web server
Biz
logic
Web server
Biz
logic
POST /buttons
{
type: “buttonCreated”,
streamId: 1,
}
Web server
Biz
logic
POST /buttons
{
type: “countIncremented”,
streamId: 1,
}
{
type: “buttonCreated”,
streamId: 1,
}
Web server
Biz
logic
POST /buttons
{
type: “countIncremented”,
streamId: 1,
}
{
type: “buttonCreated”,
streamId: 1,
}
{
type: “countIncremented”,
streamId: 1,
}
Web server
Biz
logic
POST /buttons
{
type: “countIncremented”,
streamId: 1,
}
{
type: “buttonCreated”,
streamId: 1,
}
{
type: “countIncremented”,
streamId: 1,
}
{
type: “countIncremented”,
streamId: 1,
}
Does that feel weird?
What are events?
Anotomy of an Event
{
type: ‘buttonCreated’,
streamId: ‘cj2qaa7sm0016muuaa1icupmb’,
streamType: ‘button’,
streamVersion: 1,
userId: ‘cj2qaa7smcanyouseemeaa1icupmb’
correlationId: ‘cj2qaa7k50012muuas9oh7g8k’,
payload: { ‘arbitrary’: ‘things’ },
createdAt: 1494917942033,
}
HOw do we make a useful user interface?
{
type: “countIncremented”,
streamId: 1,
}
{
type: “buttonCreated”,
streamId: 1,
}
{
type: “countIncremented”,
streamId: 1,
}
{
type: “countIncremented”,
streamId: 1,
}
We’d prefer something like
Event stream vs. displayable data
What we have:
[� { type: 'buttonCreated', streamId: '1', streamType: 'button' },� { type: 'buttonClicked', streamId: '1', streamType: 'button' },� { type: 'buttonCreated', streamId: '2', streamType: 'button' },� { type: 'buttonCreated', streamId: '3', streamType: 'button' },�]
What we’d like to have:
{
‘1’: { clicks: 1 },
‘2’: { clicks: 0 },
‘3’: { clicks: 0 },
}
Do we have something that can take a collection of things and turn it into a single thing?
“Current State is a
Left Fold of previous behaviours.”
-- Greg Young
“Current State is a
Left Fold of previous behaviours.”
-- Greg Young
“Left fold” is what reduce is called in functional programming circles
To the code!
Let’s reduce some things.
API
send-email
API
send-email
event stream (*not an Airstream)
Different views of the same state
{
type: “countIncremented”,
streamId: 1,
}
{
type: “buttonCreated”,
streamId: 1,
}
{
type: “countIncremented”,
streamId: 1,
}
{
type: “countIncremented”,
streamId: 1,
}
For sending to the client
[
{ id: ‘1’, clicks: 3 }
]
{
type: “countIncremented”,
streamId: 1,
}
{
type: “buttonCreated”,
streamId: 1,
}
{
type: “countIncremented”,
streamId: 1,
}
{
type: “countIncremented”,
streamId: 1,
}
For sending to the client
[
{ id: ‘1’, clicks: 3 }
]
For dealing with emails
[
{
id: ‘1’,
needsEmail: true,
emailTriggerCorrelationId: ‘foo’
}
]
Almost a free lunch
Multiple streams
Multiple streams
Some key points
Conclusions
Additional resources
People to follow:
Scott Bellware - https://twitter.com/sbellware
Nathan Ladd - https://twitter.com/realntl
Greg Young on event sourcing - https://www.youtube.com/watch?v=JHGkaShoyNs?t=2062
CQRS in Node - https://www.youtube.com/watch?v=4k7bLtqXb8c
The Bubble Game - http://www.kongregate.com/games/mouseit/the-bubble-game