Migrating existing monolith to serverless in 8 steps

Yan Cui
Yan CuiSpeaker at Self
Refactoring a monolith
to serverless in 8 steps
Yan Cui @theburningmonk
@theburningmonk theburningmonk.com
@theburningmonk theburningmonk.com
FASTER
CH€AP€R
SCALABLE
RESILIENT
SECURE
@theburningmonk theburningmonk.com
Migrating existing monolith to serverless in 8 steps
@theburningmonk theburningmonk.com
@theburningmonk theburningmonk.com
**** me, that’s pretty far..
@theburningmonk theburningmonk.com
6 months, 6 devs
@theburningmonk theburningmonk.com
95% cost saving compared to
existing EC2-based solution
@theburningmonk theburningmonk.com
velocity went from months to days
Yan Cui
http://theburningmonk.com
@theburningmonk
AWS user for 10 years
http://bit.ly/yubl-serverless
Yan Cui
http://theburningmonk.com
@theburningmonk
Developer Advocate @
Migrating existing monolith to serverless in 8 steps
Yan Cui
http://theburningmonk.com
@theburningmonk
Independent Consultant
advisetraining delivery
theburningmonk.com/courses
realworldserverless.com
Learn GraphQL and AppSync by building a
Twitter clone with these technologies
appsyncmasterclass.com
@theburningmonk theburningmonk.com
you can do it too, but you have to first create the
conditions where success is allowed to happen
Step 1.
Reverse Conway’s Maneuver
@theburningmonk theburningmonk.com
“organizations which design systems ... are constrained
to produce designs which are copies of the
communication structures of these organizations”
Conway’s Law
“we’re doing serverless,
but why aren’t thing
going faster?”
@theburningmonk theburningmonk.com
@theburningmonk theburningmonk.com
centralised team
Team A Team B Team C Team D …
@theburningmonk theburningmonk.com
centralised team
Team A Team B Team C Team D …
bottoleneck
@theburningmonk theburningmonk.com
“but the developers don’t understand AWS and how
our infrastructure is set up”
@theburningmonk theburningmonk.com
“but the developers don’t understand AWS and how
our infrastructure is set up”
let’s solve this
problem instead!
@theburningmonk theburningmonk.com
the best way to improve system reliability is to put its
developers on the on-call rota
@theburningmonk theburningmonk.com
Reverse Conway’s Maneuver
“sturcture your organization to match the software
you intent to produce”
@theburningmonk theburningmonk.com
“we want software that are made up of small,
loosely-coupled components, that can be
deployed and scaled indepedently, and can
fail indepedently affecting each other”
@theburningmonk theburningmonk.com
small, autonomous teams that can innovate
and move quickly, and fail in isolation
@theburningmonk theburningmonk.com
trust, but verify
@theburningmonk theburningmonk.com
provide guidance and context over
centralized control & gatekeeping
@theburningmonk theburningmonk.com
align teams with problems, not solutions
@theburningmonk theburningmonk.com
don’t let everyone start all at once!
@theburningmonk theburningmonk.com
find your Pioneers and Settlers
create a success story first
http://bit.ly/398gv5e
@theburningmonk theburningmonk.com
accept that your teams need to skill up
@theburningmonk theburningmonk.com
https://www.jeremydaly.com/newsletter
Step 2.
Identify service boundaries
be a toe-dipper
@theburningmonk theburningmonk.com
@theburningmonk theburningmonk.com
start with low-risk, non-critical business processes
@theburningmonk theburningmonk.com
incrementally migrate the legacy system by gradually
replacing pieces of functionalities to the new system
Strangler Pattern
@theburningmonk theburningmonk.com
@theburningmonk theburningmonk.com
@theburningmonk theburningmonk.com
@theburningmonk theburningmonk.com
@theburningmonk theburningmonk.com
@theburningmonk theburningmonk.com
@theburningmonk theburningmonk.com
Services…
are autonomous
@theburningmonk theburningmonk.com
Services…
are autonomous
have clear boundaries
@theburningmonk theburningmonk.com
Services…
are autonomous
have clear boundaries
own their data
@theburningmonk theburningmonk.com
Services…
are autonomous
have clear boundaries
own their data
are loosely coupled through shared contracts
@theburningmonk theburningmonk.com
beware the “entity service” anti-pattern
@theburningmonk theburningmonk.com
Step 3.
Organize your codebase
@theburningmonk theburningmonk.com
github
repo
github
repo
github
repo
github
repo
github
repo
github
repo
github
repo
github
repo
github
repo
@theburningmonk theburningmonk.com
github
repo
github
repo
github
repo
github
repo
github
repo
github
repo
github
repo
github
repo
github
repo
@theburningmonk theburningmonk.com
monorepo
@theburningmonk theburningmonk.com
github
repo
@theburningmonk theburningmonk.com
@theburningmonk theburningmonk.com
share code through symlinks + webpack
@theburningmonk theburningmonk.com
one CI/CD that deploys them all (in parallel)
@theburningmonk theburningmonk.com
@theburningmonk theburningmonk.com
good for small teams/startups
@theburningmonk theburningmonk.com
All the benefits,
none of the downsides (yet)
@theburningmonk theburningmonk.com
one repo per service
@theburningmonk theburningmonk.com
github
repo
github
repo
github
repo
github
repo
user-api
timeline-api
relationship-api
search-api
@theburningmonk theburningmonk.com
@theburningmonk theburningmonk.com
one CI/CD pipeline per service
@theburningmonk theburningmonk.com
shared infrastructure (VPCs, etc.) in separate repo
@theburningmonk theburningmonk.com
ref shared infra via CFN output, SSM param, etc.
@theburningmonk theburningmonk.com
share code through shared libs (NPM, maven, etc.)
@theburningmonk theburningmonk.com
shared code vs shared service
@theburningmonk theburningmonk.com
https://theburningmonk.com/2018/02/aws-lambda-how-best-to-manage-shared-code-and-shared-infrastructure/
Step 4.
Pick your tools
@theburningmonk theburningmonk.com
deployment framework, CI, monitoring, etc.
@theburningmonk theburningmonk.com
there’s NO “best tool” for X
pick the best one for YOU and stick to it
@theburningmonk theburningmonk.com
@theburningmonk theburningmonk.com
https://lumigo.io/blog/comparison-of-lambda-deployment-frameworks
@theburningmonk theburningmonk.com
don’t write your own deployment framework
@theburningmonk theburningmonk.com
standardization maximizes instituational
knowledge sharing
Step 5.
Keep functions simple
@theburningmonk theburningmonk.com
what got you here won’t get you there
@theburningmonk theburningmonk.com
if (path == “/user” && method == “GET”) {
return getUser(…);
} else if (path == “/user” && method == “DELETE”) {
return deleteUser(…);
} else if (path == “/user” && method == “POST”) {
return createUser(…);
} else if ….
Monolithic Functions
@theburningmonk theburningmonk.com
GET /user
POST /user
DELETE /user
Single-Purposed Functions
@theburningmonk theburningmonk.com
author: yan.cui
feature: user-api
user-api-dev
Monolithic Single-Purposed
author: yan.cui
feature: user-api
user-api-dev-get-user
author: yan.cui
feature: user-api
user-api-dev-create-user
author: yan.cui
feature: user-api
user-api-dev-delete-user
@theburningmonk theburningmonk.com
author: yan.cui
feature: user-api
user-api-dev
Monolithic Single-Purposed
author: yan.cui
feature: user-api
user-api-dev-get-user
author: yan.cui
feature: user-api
user-api-dev-create-user
author: yan.cui
feature: user-api
user-api-dev-delete-user
find related
functions by prefix
@theburningmonk theburningmonk.com
author: yan.cui
feature: user-api
user-api-dev
Monolithic Single-Purposed
author: yan.cui
feature: user-api
user-api-dev-get-user
author: yan.cui
feature: user-api
user-api-dev-create-user
author: yan.cui
feature: user-api
user-api-dev-delete-user
discoverability
(without having to dig into the code)
@theburningmonk theburningmonk.com
author: yan.cui
feature: user-api
user-api-dev
Monolithic Single-Purposed
author: yan.cui
feature: user-api
user-api-dev-get-user
author: yan.cui
feature: user-api
user-api-dev-create-user
author: yan.cui
feature: user-api
user-api-dev-delete-user
what does it do?
@theburningmonk theburningmonk.com
author: yan.cui
feature: user-api
user-api-dev
Monolithic Single-Purposed
author: yan.cui
feature: user-api
user-api-dev-get-user
author: yan.cui
feature: user-api
user-api-dev-create-user
author: yan.cui
feature: user-api
user-api-dev-delete-user
dynamodb:GetItem
dynamodb:PutItem
dynamodb:DeleteItem
@theburningmonk theburningmonk.com
author: yan.cui
feature: user-api
user-api-dev
Monolithic Single-Purposed
author: yan.cui
feature: user-api
user-api-dev-get-user
author: yan.cui
feature: user-api
user-api-dev-create-user
author: yan.cui
feature: user-api
user-api-dev-delete-user
dynamodb:GetItem
dynamodb:PutItem
dynamodb:DeleteItem
no least privilege…
@theburningmonk theburningmonk.com
author: yan.cui
feature: user-api
user-api-dev
Monolithic Single-Purposed
author: yan.cui
feature: user-api
user-api-dev-get-user
author: yan.cui
feature: user-api
user-api-dev-create-user
author: yan.cui
feature: user-api
user-api-dev-delete-user
require(x)
require(y)
require(z)
@theburningmonk theburningmonk.com
author: yan.cui
feature: user-api
user-api-dev
Monolithic Single-Purposed
author: yan.cui
feature: user-api
user-api-dev-get-user
author: yan.cui
feature: user-api
user-api-dev-create-user
author: yan.cui
feature: user-api
user-api-dev-delete-user
require(x)
require(y)
require(z)
@theburningmonk theburningmonk.com
@theburningmonk theburningmonk.com
more dependecies equals
slower cold start
@theburningmonk theburningmonk.com
author: yan.cui
feature: user-api
user-api-dev
Monolithic Single-Purposed
author: yan.cui
feature: user-api
user-api-dev-get-user
author: yan.cui
feature: user-api
user-api-dev-create-user
author: yan.cui
feature: user-api
user-api-dev-delete-user
require(x)
require(y)
require(z)
worse cold start
performance
@theburningmonk theburningmonk.com
keep functions simple, and single-purposed
Step 6.
Migrate to new service
@theburningmonk theburningmonk.com
Monolith DB
Feature A
Feature C
Feature B
Feature D
Feature E Feature F
Monolith
@theburningmonk theburningmonk.com
Monolith DB
Feature A
Feature C
Feature B
Feature D
Feature E Feature F
Monolith
@theburningmonk theburningmonk.com
Monolith DB
Monolith
Feature A
Feature C
Feature B
Feature D
Feature EFeature F
Service
DB
@theburningmonk theburningmonk.com
Monolith DB
Monolith
Feature A
Feature C
Feature B
Feature D
Feature EFeature F
Service
DB
@theburningmonk theburningmonk.com
Monolith DB
Monolith
Feature A
Feature C
Feature B
Feature D
Feature EFeature F
Service
DB
requires challenging &
risky coordinated update!
@theburningmonk theburningmonk.com
Monolith DB
Monolith
Feature A
Feature C
Feature B
Feature D
Feature EFeature F
Service
@theburningmonk theburningmonk.com
Monolith DB
Monolith
Feature A
Feature C
Feature B
Feature D
Feature EFeature F
Service
migrate the least
critical component first
@theburningmonk theburningmonk.com
Monolith DB
Monolith
Feature A
Feature C
Feature B
Feature D
Feature EFeature F
Service
@theburningmonk theburningmonk.com
Monolith DB
Monolith
Feature A
Feature C
Feature B
Feature D
Feature EFeature F
Service
@theburningmonk theburningmonk.com
Monolith DB
Monolith
Feature A
Feature C
Feature B
Feature D
Feature EFeature F
Service
DB
@theburningmonk theburningmonk.com
Monolith DB
Monolith
Feature A
Feature C
Feature B
Feature D
Feature EFeature F
Service
DB
if your system can tolerate a small downtime,
then do the data migration with a downtime!
@theburningmonk theburningmonk.com
Monolith DB
Monolith
Feature A
Feature C
Feature B
Feature D
Feature EFeature F
Service
DB
if not… consider this approach
@theburningmonk theburningmonk.com
Monolith DB
Monolith
Feature A
Feature C
Feature B
Feature D
Feature EFeature F
Service
DB
write
read
treat new DB as a read-through/
write-through cache
@theburningmonk theburningmonk.com
Monolith DB
Monolith
Feature A
Feature C
Feature B
Feature D
Feature EFeature F
Service
DB
write
read
migration
also run one-off migration job
in the background
@theburningmonk theburningmonk.com
Monolith DB
Monolith
Feature A
Feature C
Feature B
Feature D
Feature EFeature F
Service
DB
context is king
start up
STABILITY
@theburningmonk theburningmonk.com
maintain API compatibility
(all versioning schema sucks…)
@theburningmonk theburningmonk.com
prefer synchronizing data over synchronous API calls
@theburningmonk theburningmonk.com
System A
System B
System C
System D
User
User
System EUser
structural weakness
@theburningmonk theburningmonk.com
System A
System B
System C
System D
User
User
System EUser
cascade failures
cascade failures
cascade failures
@theburningmonk theburningmonk.com
System C
System DUser
upsert
@theburningmonk theburningmonk.com
be mindful of GDPR!
avoid synchronousing PII data
Step 7.
Rethink testing
@theburningmonk theburningmonk.com
acceptance
integration
unit
no. of tests
in the monolith…
@theburningmonk theburningmonk.com
most Lambda functions are simple and have a single purpose, the
risk of shipping broken software has largely shifted to how they
integrate with other services
@theburningmonk theburningmonk.com
acceptance
integration
unit
won’t catch many
integration problems
Paul Johnston
The serverless approach to
testing is different and may
actually be easier.
http://bit.ly/2t5viwK
LambdaAPI Gateway DynamoDB
LambdaAPI Gateway DynamoDB
Unit Tests
LambdaAPI Gateway DynamoDB
Unit Tests
Mock/Stub
is our request correct?
is the request mapping
set up correctly?is the API resources
configured correctly?
are we assuming the
correct schema?
LambdaAPI Gateway DynamoDB
is Lambda proxy
configured correctly?
is IAM policy set
up correctly?
is the table created?
what unit tests will not tell you…
@theburningmonk theburningmonk.com
a passing test is not a guarantee that something works
@theburningmonk theburningmonk.com
optimize for working software, not your feedback loop
(feedback loop is an important ingredient, but not the goal!)
@theburningmonk theburningmonk.com
avoid local simulation, they’re more work than is worth
it, and hides common failure modes such as
misconfigured permissions and resource policies
pro tip #1
@theburningmonk theburningmonk.com
prefer high-level functional tests
pro tip #2
@theburningmonk theburningmonk.com
integration tests exercise
system’s Integration with its
external dependencies
my code
@theburningmonk theburningmonk.com
acceptance tests exercise
system End-to-End from
the outside
my code
Migrating existing monolith to serverless in 8 steps
Migrating existing monolith to serverless in 8 steps
@theburningmonk theburningmonk.com
only use mocks for AWS services to simulate
hard-to-create failure cases
pro tip #3
@theburningmonk theburningmonk.com
but always mock your own APIs during
integration testing - they’re not as stable as
AWS services and you know it!
pro tip #4
@theburningmonk theburningmonk.com
use temporary stacks to run e2e tests
pro tip #5
https://theburningmonk.com/2019/09/why-you-should-use-temporary-stacks-when-you-do-serverless
@theburningmonk theburningmonk.com
https://theburningmonk.com/2019/09/how-to-include-sns-and-kinesis-in-your-e2e-tests
How to include SNS and Kinesis in your e2e tests
Step 8.
Resilience as a service
@theburningmonk theburningmonk.com
observability, observability, observability
@theburningmonk theburningmonk.com
use queues to amortize traffic spikes between services
@theburningmonk theburningmonk.com
use sagas to manage distributed transactions
@theburningmonk theburningmonk.com
use circuit breakers to prevent cascade failures
@theburningmonk theburningmonk.com
use bulkheads to isolate blast radius
@theburningmonk theburningmonk.com
go multi-region, active-active
@theburningmonk theburningmonk.com
#1 apply Reverse Conway’s Maneuver
#2 identify service boundaries
#3 organize your codebase
#4 pick your tools
#5 keep functions simple
#6 migrate to new service (gracefully)
#7 rethink testing
#8 resilience as a service
Migrating existing monolith to serverless in 8 steps
https://theburningmonk.com/hire-me
AdviseTraining Delivery
“Fundamentally, Yan has improved our team by increasing our
ability to derive value from AWS and Lambda in particular.”
Nick Blair
Tech Lead
Learn GraphQL and AppSync by building a
Twitter clone with these technologies
appsyncmasterclass.com
@theburningmonk
theburningmonk.com
github.com/theburningmonk
1 of 156

More Related Content

Similar to Migrating existing monolith to serverless in 8 steps(20)

Recently uploaded(20)

ThroughputThroughput
Throughput
Moisés Armani Ramírez25 views
CXL at OCPCXL at OCP
CXL at OCP
CXL Forum158 views
[2023] Putting the R! in R&D.pdf[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf
Eleanor McHugh31 views
ChatGPT and AI for Web DevelopersChatGPT and AI for Web Developers
ChatGPT and AI for Web Developers
Maximiliano Firtman143 views
ISWC2023-McGuinnessTWC16x9FinalShort.pdfISWC2023-McGuinnessTWC16x9FinalShort.pdf
ISWC2023-McGuinnessTWC16x9FinalShort.pdf
Deborah McGuinness80 views

Migrating existing monolith to serverless in 8 steps