Refactoring a monolith to serverless can be intimidating, but there are discrete steps that you can take to simplify the process. In this chalk talk, we outline eight steps for successfully refactoring your monolith and highlight key decision points such as language and tooling choices. Through real-world examples of successful migrations, we uncover common mistakes, useful techniques for identifying components for migration and service boundaries, and processes for migrating large amounts of data without downtime. Bring your refactoring challenges to this interactive session to see how these techniques can be applied in the context of your own application.
3. Agenda
Eight steps to refactor a monolith to serverless
Walkthrough of a real-world example
Live discussion
4. Related breakouts
SVS215-R Build observability into a serverless application
SVS215-R1 Build observability into a serverless application
API313 Nondisruptive strategies for application migration
API315-R Application integration patterns for microservices
API315-R1 Application integration patterns for microservices
API315-R2 Application integration patterns for microservices
CMY301 Performing chaos engineering in a serverless world
7. Step 1: Reverse Conway’s maneuver
• Conway’s law: “Organizations which design systems . . . are constrained to produce designs
which are copies of the communication structures of these organizations.”
• Structure your organization to match the software you want to produce
• Create small, autonomous teams that are empowered and entrusted to run their services
• Recall Amazon’s mantra of “two pizza teams”
• Trust, but verify
• Provide guidance and context over centralized control and gatekeeping
• Create a success story first, a pathfinder
• Accept that your teams would need to skill up
8. Step 2: Identify service boundaries
• Start with low-risk, noncritical business processes
• Identify boundaries within the monolith and carve them out into separate services
• A service should be the authority of some business process
• Services are autonomous
• Services have clear boundaries
• Services own their data and are the authoritative sources for those data
• Services are loosely coupled through shared contracts and schema
• Beware the “entity service“ antipattern
12. Step 3: Organize your codebase
• Do not have one repo per function
• One repo per service
• One deployment stack (both functions and other resources)
• One CI/CD pipeline
• Shared infrastructure in separate repo
• Reference shared resources through CFN outputs/exports, SSM parameters, etc.
• Share code through shared libraries (NPM, Maven, NuGet, etc.)
• Shared code vs. shared service
• Monorepo
• Great for small teams; prioritizes speed of iteration
• Requires discipline and good tooling
13. Step 4: Pick your tools
• Deployment frameworks, CI tool, monitoring, alerting, etc.
• There is no “best tool for X”; pick the best one for you and stick to it
• Maximize institutional knowledge
• Use deployment framework for AWS Lambda; don’t build your own
• Serverless
• AWS Serverless Application Model (AWS SAM)
• AWS Cloud Development Kit
• . . .
• How you deploy your code should be consistent across all your projects
14. Step 5: Keep functions simple
• Follow the single responsibility principle
• It’s easy to see what a function does
• Single-purposed functions are more secure
• Single-purposed functions have better cold-start performance
15. Step 6: Move to new services gracefully
• Maintain application programming interface (API) compatibility
• Switch traffic to new service gradually
• Services should own their data, but you should remove risks in the migration process
• Move ownership of the business function to the new service first
• Migrate data to the new database later
• Prefer synchronizing data over synchronous API calls
19. Step 6: Move to new services gracefully
• Maintain API compatibility
• Switch traffic to new service gradually
• Services should own their data, but you should remove risks in the migration process
• Move ownership of the business function to the new service first
• Migrate data to the new database later
• Prefer synchronizing data over synchronous API calls
• Be mindful of GDPR
20. Step 7: Rethink testing
• Different failure modes to a monolith
• Unit tests have low return on investment
• Focus on integration tests
• Use temporary stacks for end-to-end tests
21. Step 8: Build resilience into the system
• Build observability into the system
• Use short and adaptive timeouts
• Use queues to amortize traffic spikes between services
• Use sagas to manage distributed transactions
• Use circuit breaks to prevent cascade failures
• Use bulkheads to isolate blast radius
• Employ chaos engineering practices to understand your system’s weaknesses
24. 8 Steps to refactor a monolith to serverless
1. Apply Reverse Conway’s Maneuver
2. Identify service boundaries
3. Organize your codebase
4. Pick your tools
5. Keep your functions simple
6. Move to new services gracefully
7. Rethink testing
8. Build resilience into the system