Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JCCONF 2023 Refactoring to Serverless

Kim Kao
October 06, 2023

JCCONF 2023 Refactoring to Serverless

In this talk, Kim introduced the concept on how to refactor the legacy systems to serverless architecture. In order to remove the "integration/glue" code from application code, we can well utilize the platform capabilities to do. Lambda destination, Step Function Pipe are classic features could help on this. Suggest each one developer could re-think about how to leverage platform vendor offered services to build up solutions but keep a clean & simplified architecture design. Credits to Gregor Hohpe and ServerlessLand Community contributors to share the knowledge.

Kim Kao

October 06, 2023
Tweet

More Decks by Kim Kao

Other Decks in Technology

Transcript

  1. Automation – 100 years ago Courtesy of the National Automotive

    History Collection, Detroit Public Library
  2. 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)); } }
  3. AWS CDK = Infrastructure as actual Code DEV PREVIEW Familiar

    Your language Classes and methods Abstraction Sane defaults Reusable classes Tool Support AutoComplete Inline documentation
  4. Serverless automation • Granularity • Dependencies across elements • Wiring

    between elements (sync, async) • Managed service interactions • Data or control flow
  5. Cloud automation blurs the line between application code and automation

    code. A Modern Cloud Automation Architect " "
  6. Refactoring A controlled technique for improving the design of an

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

    serverless applications by replacing application code with equivalent automation code. - The Serverless Field Community " "
  8. 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
  9. Application needs evolve AWS capabilities evolve Improve runtime characteristics Motivations

    for Serverless Refactoring Leverage platform capability Reduce cost
  10. 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.
  11. 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
  12. 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
  13. 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.
  14. 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
  15. 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
  16. 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
  17. 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)
  18. 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 ?
  19. 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.
  20. “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.
  21. 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.
  22. 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 “ “