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. Refactoring to
    Serverless
    Kim, Kao
    Co-organizer, DDDesign Taiwan Community
    Sr. DevAx Solutions Architect, Amazon Web Services

    View full-size slide

  2. Join at
    slido.com
    #1628 054

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  5. Decomposing automation
    Endpoint

    View full-size slide

  6. 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));
    }
    }

    View full-size slide

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

    View full-size slide

  8. Infrastructure as Code
    Much more than actual

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  11. Refactoring to Serverless

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  15. An Example:
    Extract send message

    View full-size slide

  16. Lambda Function SQS
    Incoming
    Request/event

    View full-size slide

  17. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  20. 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.

    View full-size slide

  21. 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

    View full-size slide

  22. 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

    View full-size slide

  23. 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.

    View full-size slide

  24. Considerations

    View full-size slide

  25. 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

    View full-size slide

  26. 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

    View full-size slide

  27. An Example:
    Replace Lambda with Service
    Integration

    View full-size slide

  28. 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

    View full-size slide

  29. 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)

    View full-size slide

  30. An Example:
    Replace sending event with
    EventBridge Pipes

    View full-size slide

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

    View full-size slide

  32. 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 ?

    View full-size slide

  33. Integrating refactoring to
    serverless into your
    development flow

    View full-size slide

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


    View full-size slide

  35. 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.

    View full-size slide

  36. “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.

    View full-size slide

  37. 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.

    View full-size slide

  38. 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


    View full-size slide

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

    View full-size slide

  40. Thank You!
    @KimKao
    @YikaiKao

    View full-size slide