Slide 1

Slide 1 text

Refactoring to Serverless Kim, Kao Co-organizer, DDDesign Taiwan Community Sr. DevAx Solutions Architect, Amazon Web Services

Slide 2

Slide 2 text

Join at slido.com #1628 054

Slide 3

Slide 3 text

Automation – 100 years ago Courtesy of the National Automotive History Collection, Detroit Public Library

Slide 4

Slide 4 text

Cloud − Automation = Just another data center An opinionated architect " "

Slide 5

Slide 5 text

Decomposing automation Endpoint

Slide 6

Slide 6 text

Automation Languages Document-Oriented (JSON/YAML) CloudFormation TerraForm Functional (Haskell, Clojure, F#) Pulumi with F#, GCL, Jsonnet, CUE Object-Oriented / Procedural (Java, Python, TypeScript, etc.) AWS CDK Pulumi Resources: S3Bucket: Type: 'AWS::S3::Bucket' Description: Amazon S3 bucket Properties: BucketName: some-bucket-name VersioningConfiguration: Status: Enabled BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 (ns hello-world.main (:require [“@pulumi/pulumi” :as pulumi] [“@pulumi/aws” :as aws] [pulumi-cljs.core :as p])) (defn ^:export stack “Create the Pulumi stack” [] (let [bucket (p/resource aws/s3.Bucket “test-bkt” nil {:bucket (p/cfg “bucket-name”)})] (p/prepare-output {:bucket bucket}))) class SqsSnsStack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const queue = new sqs.Queue(this, “MySqsQueue”, { visibilityTimeout: Duration. Minutes(5); }); const topic = new sns.Topic(this, “MySnsTopic”); topic.addSubscription( new SqsSubscription(queue)); } }

Slide 7

Slide 7 text

AWS CDK = Infrastructure as actual Code DEV PREVIEW Familiar Your language Classes and methods Abstraction Sane defaults Reusable classes Tool Support AutoComplete Inline documentation

Slide 8

Slide 8 text

Infrastructure as Code Much more than actual

Slide 9

Slide 9 text

Serverless automation • Granularity • Dependencies across elements • Wiring between elements (sync, async) • Managed service interactions • Data or control flow

Slide 10

Slide 10 text

Cloud automation blurs the line between application code and automation code. A Modern Cloud Automation Architect " "

Slide 11

Slide 11 text

Refactoring to Serverless

Slide 12

Slide 12 text

What is serverless? Automatic scaling No infrastructure provisioning, no management Pay for value Highly available and secure

Slide 13

Slide 13 text

Refactoring A controlled technique for improving the design of an existing code base through behavior-preserving transformations. - Martin Fowler, refactoring.com " "

Slide 14

Slide 14 text

Serverless Refactoring A controlled technique for improving the design of serverless applications by replacing application code with equivalent automation code. - The Serverless Field Community " "

Slide 15

Slide 15 text

An Example: Extract send message

Slide 16

Slide 16 text

Lambda Function SQS Incoming Request/event

Slide 17

Slide 17 text

Original new Function(this, 'orderPizza', { functionName: `OrderPizza`, runtime: Runtime.NODEJS_16_X, code: Code.fromAsset(‘..'), handler: 'orderPizza.handler’, onSuccess:new SqsDestination(this.pizzaQueue) }); exports.handler = async (event) => { results = //some logic const params = { QueueUrl: process.env.ORDER_QUEUE_URL, MessageBody: results }; await sqs.sendMessage(params).promise(); } exports.handler = async (event) => { results = // some logic return {message: results}; }; û Topology hidden in environment variable û Mix of logic and dependencies in application code ü No external dependencies in application code ü Topology defined in automation code ü Automated permission grant Refactored Application Code (AWS Lambda) Application Code (AWS Lambda) Automation Code (AWS CDK) Refactoring: Extract send message

Slide 18

Slide 18 text

Lambda Function SQS Incoming Request/event IaC resolve integration issue onSuccess // logics …

Slide 19

Slide 19 text

Application needs evolve AWS capabilities evolve Improve runtime characteristics Motivations for Serverless Refactoring Leverage platform capability Reduce cost

Slide 20

Slide 20 text

Application needs evolve AWS capabilities evolve Improve runtime characteristic Refactoring Pattern Catalog Leverage platform capability Pattern Name Description Extract Send Message to Lambda Destination Instead of sending Amazon SQS messages via code, use AWS Lambda Destinations. Extract Function Invocation Instead of calling one AWS Lambda function directly from another, use Lambda Destination. Extract Message Filter Instead of conditional statements at the consumer, eliminate unwanted messages with Amazon EventBridge. Extract Send Message to DynamoDB Stream Instead of a Lambda function sending a message after updating DynamoDB, use DynamoDB Streams plus EventBridge Pipes.

Slide 21

Slide 21 text

Application needs evolve AWS capabilities evolve Improve runtime characteristic Refactoring Pattern Catalog Leverage platform capability Pattern Name Description Replace Lambda with Service Integration Service integration allows direct calls to any API from AWS Step Function without the need for an additional AWS Lambda function Direct database access Replace a Lambda function that only reads from Amazon DynamoDB with Step Functions' getItem task

Slide 22

Slide 22 text

Application needs evolve AWS capabilities evolve Improve runtime characteristic Refactoring Pattern Catalog Leverage platform capability Pattern Name Description Replace Event Pattern with Lambda If an event pattern can no longer be implemented in Amazon EventBridge, build it in AWS Lambda instead

Slide 23

Slide 23 text

Application needs evolve AWS capabilities evolve Improve runtime characteristic Refactoring Pattern Catalog Leverage platform capability Pattern Name Description Replace Polling with ‘Wait for Callback’ Instead of polling for results, use AWS Step Function’s ‘Wait for Callback’ to pause the workflow until a task token is returned. Replace Map with Scatter-Gather Instead of making parallel invocations from a Step Function’s Map state, send a message to SNS. Convert Choreography to Orchestration Replace routing messages through multiple components with a central Step Functions workflow that invokes each component explicitly. Convert Orchestration to Choreography Replace a central Step Functions workflow with a messages flowing through multiple components.

Slide 24

Slide 24 text

Considerations

Slide 25

Slide 25 text

Original new Function(this, 'orderPizza', { functionName: `OrderPizza`, runtime: Runtime.NODEJS_14_X, code: Code.fromAsset(‘..'), handler: 'orderPizza.handler’, onSuccess:new SqsDestination(this.pizzaQueue) }); exports.handler = async (event) => { results = //some logic const params = { QueueUrl: process.env.ORDER_QUEUE_URL, MessageBody: results }; await sqs.sendMessage(params).promise(); } exports.handler = async (event) => { results = // some logic return {message: results}; }; Refactored Application Code (AWS Lambda) Application Code (AWS Lambda) Automation Code (AWS CDK) Refactoring: Extract send message

Slide 26

Slide 26 text

Did the refactoring preserve behavior? Only works with Asynchronous function invocation Invocation occurs at the end of function execution SQS Message using Code SQS Message using Lambda Destination Result is wrapped in an Event Envelope

Slide 27

Slide 27 text

An Example: Replace Lambda with Service Integration

Slide 28

Slide 28 text

Refactoring: Replace Lambda with Service Integration AWS Step Functions workflow AWS Step Functions workflow Amazon S3 Image Bucket Amazon Rekognition image Amazon Rekognition image Lambda function Amazon S3 Image Bucket Original Refactored

Slide 29

Slide 29 text

const detectObject = new tasks.CallAwsService(this,'Detect’,{ service: 'rekognition’, action: 'detectLabels’, parameters: { Image: { S3Object: { Bucket: imageBucket.bucketName, Name: this.IMAGE_TO_LABEL }} }, iamResources:['*'], additionalIamStatements: [ new iam.PolicyStatement({ actions: ['s3:getObject’], resources: [`${imageBucket.bucketArn}/${this.IMAGE_TO_LABEL}`] })] }); Refactored Original exports.handler = async (event) => { var params = { Image: { S3Object: { Bucket:event.bucketName, Name: event.imageName }}, }; const result = await rekognition.detectLabels(params). promise(); callback(null, result); } const detectObjectInImageLambda = new lambda.Function(this, 'detectObjectInImage', { functionName: 'detectObjectInImage’, runtime: lambda.Runtime.NODEJS_14_X, code: lambda.Code.fromAsset('lambda-fns’), handler: 'detectObjectInImage.handler' }); const rekognitionPolicy = new iam.PolicyStatement({ actions: ["s3:GetObject", "rekognition:DetectLabels"], resources: ['*'] //rekognition requires 'all’ }) detectObjectInImageLambda.addToRolePolicy(rekognitionPolicy) const detectObject = new tasks.LambdaInvoke(this,'Detect', { lambdaFunction: detectObjectInImageLambda, payload: sfn.TaskInput.fromObject({ s3Bucket: imageBucket.bucketName, imageName: this.IMAGE_TO_LABEL }), outputPath: "$.Payload” }); ü No application code to maintain ü Topology defined in automation code û Application code just for service integration Application Code (AWS Lambda) Automation Code (AWS CDK) Automation Code (AWS CDK)

Slide 30

Slide 30 text

An Example: Replace sending event with EventBridge Pipes

Slide 31

Slide 31 text

Refactoring: Replace Send Event with DynamoDB Streams and EventBridge Pipes Original

Slide 32

Slide 32 text

Refactoring: Replace Send Event with DynamoDB Streams and EventBridge Pipes Original Refactored https://architectelevator.com/cloud/cloud-decoupling-cost/ Data Persistence & Emit Domain Event Atomic Transaction ? ERR Hanlding ? Exponential Retry ?

Slide 33

Slide 33 text

Integrating refactoring to serverless into your development flow

Slide 34

Slide 34 text

If it hurts, do it more often. Martin Fowler https://martinfowler.com/bliki/FrequencyReducesDifficulty.html Time between actions Pain “ “

Slide 35

Slide 35 text

Refactoring is software delivery Good test coverage makes refactoring easy. It also assures that your development cycle accommodates constant change. Read: “if refactoring is hard, there’s likely something amiss in your process”. AWS keeps evolving based on customer needs. There’s a good chance that what you had to code before is now available inside the platform. Additional functionality can increase your application’s complexity. Refactoring moderates it so you can maintain velocity.

Slide 36

Slide 36 text

“Serverless Teams Should Embrace Continuous Refactoring” Turn engineering needs into business goals. Circulate the results broadly. If refactoring gain a few milliseconds in latency, convert it into a measurable customer satisfaction metric. Make it a technology motivator Schedule a renewal with the change of seasons: a sprint or two every quarter dedicated to engineering activities, incl. refactoring. Make it a recurring part of your development process Refactoring involves learning new skills, using new services, and implementing new patterns, all great tech motivators. https://betterprogramming.pub/why-serverless-teams-should-embrace-continuous-refactoring-217d4e67db5b Sheen Brisals The LEGO Group. AWS Serverless Hero. Keep a refactoring backlog Prioritize and consider the list during their goal-setting or OKR meetings.

Slide 37

Slide 37 text

Possible hurdles(障礙) / misconceptions “I’ll just write this real quick.” That’s how virtually all legacy software started. Code is a liability, not an asset. “It’ll be easier to understand in code.” Locally, perhaps. An application topology that’s scattered in application code is more brittle and harder to performance- tune, though. Don’t fall for local optimization. “Coding it out makes it more portable.” Success before portability. You came to the cloud (and especially serverless!) so you can focus on application logic. Let the platform do the rest for you.

Slide 38

Slide 38 text

Cloud automation isn’t an afterthought. It impacts your architecture choices and blurs the lines between application and platform code. A Modern Cloud Automation Application Architect “ “

Slide 39

Slide 39 text

Want to learn more? https://serverlessland.com/refactoring-serverless/intro Gregor Hohpe @ghohpe www.linkedin.com/in/ghohpe ArchitectElevator.com

Slide 40

Slide 40 text

Thank You! @KimKao @YikaiKao