{"value":"When designing an application, you must integrate and combine several AWS services in the most optimized way for an effective and efficient architecture:\n\n- Optimize for performance by reducing the latency between services\n- Optimize for costs operability and sustainability, by avoiding unnecessary components and reducing workload footprint\n- Optimize for resiliency by removing potential point of failures\n- Optimize for security by minimizing the attack surface\n\nAs stated in the [Serverless Application Lens](https://docs.aws.amazon.com/wellarchitected/latest/serverless-applications-lens/welcome.html) of the [Well-Architected Framework](https://aws.amazon.com/architecture/well-architected/), “If your [AWS Lambda](https://aws.amazon.com/lambda/) function is not performing custom logic while integrating with other AWS services, chances are that it may be unnecessary.” In addition, [Amazon API Gateway](https://aws.amazon.com/api-gateway/), [AWS AppSync](https://aws.amazon.com/appsync/), [AWS Step Functions](https://aws.amazon.com/step-functions), [Amazon EventBridge](https://aws.amazon.com/eventbridge/), and Lambda Destinations can directly integrate with a number of services. These optimizations can offer you more value and less operational overhead.\n\nThis blog post will show how to optimize an architecture with direct integration.\n### **Workflow example and initial architecture**\n\nFigure 1 shows a typical workflow for the creation of an online bank account. The customer fills out a registration form with personal information and adds a picture of their ID card. The application then validates ID and address, and scans if there is already an existing user by that name. If everything checks out, a backend application will be notified to create the account. Finally, the user is notified of successful completion.\n\n![image.png](https://dev-media.amazoncloud.cn/cb3a0189f61e41c59dac6ad8a41ad50f_image.png)\n\nFigure 1. Bank account application workflow\n\nThe workflow architecture is shown in Figure 2 (click on the picture to get full resolution).\n\n![image.png](https://dev-media.amazoncloud.cn/a1013478af6a4cf2a7c075c29040f095_image.png)\n\nFigure 2. Initial account creation architecture\n\nThis architecture contains 13 Lambda functions. If you look at the code on [GitHub](https://github.com/aws-samples/step-functions-direct-integrations), you can see that:\n\nFive of these Lambda functions are basic and perform simple operations:\n- One function to execute the Step Functions state machine\n- Two functions to perform create, read, update, and delete (CRUD) operations on [Amazon DynamoDB](https://aws.amazon.com/cn/dynamodb/)\n- Two functions to send messages on [Amazon Simple Queue Service (Amazon SQS)](https://aws.amazon.com/cn/sqs/) or EventBridge\n\n Additional Lambda functions perform other tasks, such as verification and validation:\n- One function generates a presigned URL to upload ID card pictures to [Amazon Simple Storage Service (Amazon S3)](https://aws.amazon.com/cn/s3/)\n- One function uses the [Amazon Textract](https://aws.amazon.com/cn/textract/) API to extract information from the ID card\n- One function verifies the identity of the user against the information extracted from the ID card\n- One function performs simple HTTP request to a third-party API to validate the address\n\nFinally, four functions concern the websocket ( ```connect``` , ```message``` , and ```disconnect``` ) and notifications to the user.\n\n### **Opportunities for improvement**\nIf you further analyze the code of the five basic functions (see ```startWorkflow```on GitHub, for example), you will notice that there are actually three lines of fundamental code that start the workflow. The others 38 lines involve imports, input validation, error handling, logging, and tracing. Remember that all this code must be tested and maintained.\n\nPython\n```import os\nimport json\nimport boto3\nfrom aws_lambda_powertools import Tracer\nfrom aws_lambda_powertools import Logger\nimport re\n\nlogger = Logger()\ntracer = Tracer()\n\nsfn = boto3.client('stepfunctions')\n\nPATTERN = re.compile(r\"^arn:(aws[a-zA-Z-]*)?:states:[a-z]{2}((-gov)|(-iso(b?)))?-[a-z]+-\\d{1}:\\d{12}:stateMachine:[a-zA-Z0-9-_]+$\")\n\nif ('STATE_MACHINE_ARN' not in os.environ\n or os.environ['STATE_MACHINE_ARN'] is None\n or not PATTERN.match(os.environ['STATE_MACHINE_ARN'])):\n raise RuntimeError('STATE_MACHINE_ARN env var is not set or incorrect')\n\nSTATE_MACHINE_ARN = os.environ['STATE_MACHINE_ARN']\n\n@logger.inject_lambda_context\n@tracer.capture_lambda_handler\ndef handler(event, context):\n try:\n event['requestId'] = context.aws_request_id\n\n sfn.start_execution(\n stateMachineArn=STATE_MACHINE_ARN,\n input=json.dumps(event)\n )\n\n return {\n 'requestId': event['requestId']\n }\n except Exception as error:\n logger.exception(error)\n raise RuntimeError('Internal Error - cannot start the creation workflow') from error\n```\nAfter running this workflow several times and reviewing the [AWS X-Ray](https://aws.amazon.com/cn/xray/) traces (Figure 3), we can see that it takes about 2–3 seconds when functions are warmed:\n\n![image.png](https://dev-media.amazoncloud.cn/4f9709ee7dd2488d97f17c8032f01940_image.png)\n\nFigure 3. X-Ray traces when Lambda functions are warmed\n\nBut the process takes around 10 seconds with cold starts, as shown in Figure 4:\n\n![image.png](https://dev-media.amazoncloud.cn/e174c56a80314b868fd9bbc7fe502ec9_image.png)\n\nFigure 4. X-Ray traces when Lambda functions are cold\n\nWe use an asynchronous architecture to avoid waiting time for the user, as this can be a long process. We also use WebSockets to notify the user when it’s finished. This adds some complexity, new components, and additional costs to the architecture. Now let’s look at how we can optimize this architecture.\n\n### **Improving the initial architecture**\n#### *Direct integration with Step Functions*\nStep Functions can directly [integrate with some AWS services,](https://docs.aws.amazon.com/step-functions/latest/dg/connect-supported-services.html) including DynamoDB, Amazon SQS, and EventBridge, and [more than 10,000 APIs](https://docs.aws.amazon.com/step-functions/latest/dg/supported-services-awssdk.html#supported-services-awssdk-list) from 200+ AWS services. With these integrations, you can replace Lambda functions when they do not provide value. We recommend using Lambda functions to transform data, not to transport data from one service to another.\n\nIn our bank account creation use case, there are four Lambda functions we can replace with direct service integrations (see large arrows in Figure 5):\n\n- Query a DynamoDB table to search for a user\n- Send a message to an SQS queue when the extraction fails\n- Create the user in DynamoDB\n- Send an event on EventBridge to notify the backend\n\n ![image.png](https://dev-media.amazoncloud.cn/11ac81636b034210a1390ff313be1f4a_image.png)\n\nFigure 5. Lambda functions that can be replaced\n\nIt is not as clear that we need to replace the other Lambda functions. Here are some considerations:\n\n- To extract information from the ID card, we use Amazon Textract. It is available through the SDK integration in Step Functions. However, the API’s response provides too much information. We recommend using a library such as [amazon-textract-response-parser](https://github.com/aws-samples/amazon-textract-response-parser) to parse the result. For this, you’ll need a Lambda function.\n- The identity cross-check performs a simple comparison between the data provided in the web form and the one extracted in the ID card. We can perform this comparison in Step Functions using a Choicestate and several conditions. If the business logic becomes more complex, consider using a Lambda function.\n- To validate the address, we query a third-party API. Step Functions cannot directly call a third-party HTTP endpoint, but because it’s integrated with API Gateway, we can [create a proxy for this endpoint](https://jeromevdl.medium.com/step-functions-with-api-gateway-integration-good-idea-8cbe9fff63ef).\nIf you only need to retrieve data from an API or make a simple API call, use the direct integration. If you need to implement some logic, use a Lambda function.\n\n#### *Direct integration with API Gateway*\nAPI Gateway also provides service integrations. In particular, we can start the workflow without using a Lambda function. In the console, select the integration type “AWS Service”, the AWS service “Step Functions”, the action “StartExecution”, and “POST” method, as shown in Figure 6.\n\n![image.png](https://dev-media.amazoncloud.cn/98662e4d400a4ab598972fce9caff172_image.png)\n\nFigure 6. API Gateway direct integration with Step Functions\n\nAfter that, use a [mapping template](https://docs.aws.amazon.com/apigateway/latest/developerguide/models-mappings.html) in the integration request to define the parameters as shown here:\n\n```\n{\n \"stateMachineArn\":\"arn:aws:states:eu-central-1:123456789012:stateMachine: accountCreationWorkflow\",\n \"input\":\"$util.escapeJavaScript($input.json('$'))\"\n}\n```\nWe can go further and remove the websockets and associated Lambda functions ```connect```,```message```, and ```disconnect```\n. By using [Synchronous Express Workflows](https://aws.amazon.com/cn/blogs/compute/new-synchronous-express-workflows-for-aws-step-functions/) and the ```StartSyncExecution```\n API, we can start the workflow and wait for the result in a synchronous fashion. API Gateway will then directly return the result of the workflow to the client.\n\n### **Final optimized architecture**\nAfter applying these optimizations, we have the updated architecture shown in Figure 7. It uses only two Lambda functions out of the initial 13. The rest have been replaced by direct service integrations or implemented in Step Functions.\n\n![image.png](https://dev-media.amazoncloud.cn/f3660e8e64de4a62a70ee13406e26451_image.png)\n\nFigure 7. Final optimized architecture\n\nWe were able to remove 11 Lambda functions and their associated fees. In this architecture, the cost is mainly driven by Step Functions, and the main price difference will be your use of [Express Workflows instead of Standard Workflows](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-standard-vs-express.html). If you need to keep some Lambda functions, use [AWS Lambda Power Tuning](https://github.com/alexcasalboni/aws-lambda-power-tuning) to configure your function correctly and benefit from the best price/performance ratio.\n\nOne of the main benefits of this architecture is performance. With the final workflow architecture, it now takes about 1.5 seconds when the Lambda function is warmed and 3 seconds on cold starts (versus up to 10 seconds previously), see Figure 8:\n\n![image.png](https://dev-media.amazoncloud.cn/dd03e56cbdd34c7ab39a65378c7269bd_image.png)\n\nFigure 8. X-Ray traces for the final architecture\n\nThe process can now be synchronous. It reduces the complexity of the architecture and vastly improves the user experience.\n\nAn added benefit is that by reducing the overall complexity and removing the unnecessary Lambda functions, we have also reduced the risk of failures. These can be errors in the code, memory or timeout issues due to bad configuration, lack of permissions, network issues between components, and more. This increases the resiliency of the application and eases its maintenance.\n\n### **Testing**\nTestability is an important consideration when building your workflow. Unit testing a Lambda function is straightforward, and you can use your preferred testing framework and validate methods. Adopting a hexagonal architecture also helps remove dependencies to the cloud.\n\nWhen removing functions and using an approach with direct service integrations, you are by definition directly connected to the cloud. You still must verify that the overall process is working as expected, and validate these integrations.\n\nYou can achieve this kind of tests locally using Step Functions Local, and the recently announced Mocked Service Integrations. By mocking service integrations, for example, retrieving an item in DynamoDB, you can validate the different paths of your state machine.\n\nYou also have to perform integration tests, but this is true whether you use direct integrations or Lambda functions.\n\n### **Conclusion**\nThis post describes how to simplify your architecture and optimize for performance, resiliency, and cost by using direct integrations in Step Functions and API Gateway. Although many Lambda functions were reduced, some remain useful for handling more complex business logic and data transformation. Try this out now by visiting the GitHub repository.\n\n**For further reading:**\n- [Building well-architected serverless applications: Optimizing application performance – part 3](https://aws.amazon.com/cn/blogs/compute/building-well-architected-serverless-applications-optimizing-application-performance-part-3/)\n- [AWS Step Functions Supports 200 AWS Services To Enable Easier Workflow Automation](https://aws.amazon.com/cn/blogs/aws/now-aws-step-functions-supports-200-aws-services-to-enable-easier-workflow-automation/)\n\n #### **Jerome Van Der Linden**\n![image.png](https://dev-media.amazoncloud.cn/56bf4578a8bc4676925a719c80220a72_image.png)\n\nJerome is a Solutions Architect at AWS, where he works for different customers in Switzerland, helping them on their journey to the cloud. As a former developer, he built a strong experience on software craftsmanship and devops practices. He's also passionate about serverless. In his spare time, and when snow is here, he enjoys skiing with his kids. Reach out to him on twitter: @jeromevdl.","render":"<p>When designing an application, you must integrate and combine several AWS services in the most optimized way for an effective and efficient architecture:</p>\n<ul>\n<li>Optimize for performance by reducing the latency between services</li>\n<li>Optimize for costs operability and sustainability, by avoiding unnecessary components and reducing workload footprint</li>\n<li>Optimize for resiliency by removing potential point of failures</li>\n<li>Optimize for security by minimizing the attack surface</li>\n</ul>\n<p>As stated in the <a href=\"https://docs.aws.amazon.com/wellarchitected/latest/serverless-applications-lens/welcome.html\" target=\"_blank\">Serverless Application Lens</a> of the <a href=\"https://aws.amazon.com/architecture/well-architected/\" target=\"_blank\">Well-Architected Framework</a>, “If your <a href=\"https://aws.amazon.com/lambda/\" target=\"_blank\">AWS Lambda</a> function is not performing custom logic while integrating with other AWS services, chances are that it may be unnecessary.” In addition, <a href=\"https://aws.amazon.com/api-gateway/\" target=\"_blank\">Amazon API Gateway</a>, <a href=\"https://aws.amazon.com/appsync/\" target=\"_blank\">AWS AppSync</a>, <a href=\"https://aws.amazon.com/step-functions\" target=\"_blank\">AWS Step Functions</a>, <a href=\"https://aws.amazon.com/eventbridge/\" target=\"_blank\">Amazon EventBridge</a>, and Lambda Destinations can directly integrate with a number of services. These optimizations can offer you more value and less operational overhead.</p>\n<p>This blog post will show how to optimize an architecture with direct integration.</p>\n<h3><a id=\"Workflow_example_and_initial_architecture_10\"></a><strong>Workflow example and initial architecture</strong></h3>\n<p>Figure 1 shows a typical workflow for the creation of an online bank account. The customer fills out a registration form with personal information and adds a picture of their ID card. The application then validates ID and address, and scans if there is already an existing user by that name. If everything checks out, a backend application will be notified to create the account. Finally, the user is notified of successful completion.</p>\n<p><img src=\"https://dev-media.amazoncloud.cn/cb3a0189f61e41c59dac6ad8a41ad50f_image.png\" alt=\"image.png\" /></p>\n<p>Figure 1. Bank account application workflow</p>\n<p>The workflow architecture is shown in Figure 2 (click on the picture to get full resolution).</p>\n<p><img src=\"https://dev-media.amazoncloud.cn/a1013478af6a4cf2a7c075c29040f095_image.png\" alt=\"image.png\" /></p>\n<p>Figure 2. Initial account creation architecture</p>\n<p>This architecture contains 13 Lambda functions. If you look at the code on <a href=\"https://github.com/aws-samples/step-functions-direct-integrations\" target=\"_blank\">GitHub</a>, you can see that:</p>\n<p>Five of these Lambda functions are basic and perform simple operations:</p>\n<ul>\n<li>One function to execute the Step Functions state machine</li>\n<li>Two functions to perform create, read, update, and delete (CRUD) operations on <a href=\"https://aws.amazon.com/cn/dynamodb/\" target=\"_blank\">Amazon DynamoDB</a></li>\n<li>Two functions to send messages on <a href=\"https://aws.amazon.com/cn/sqs/\" target=\"_blank\">Amazon Simple Queue Service (Amazon SQS)</a> or EventBridge</li>\n</ul>\n<p>Additional Lambda functions perform other tasks, such as verification and validation:</p>\n<ul>\n<li>One function generates a presigned URL to upload ID card pictures to <a href=\"https://aws.amazon.com/cn/s3/\" target=\"_blank\">Amazon Simple Storage Service (Amazon S3)</a></li>\n<li>One function uses the <a href=\"https://aws.amazon.com/cn/textract/\" target=\"_blank\">Amazon Textract</a> API to extract information from the ID card</li>\n<li>One function verifies the identity of the user against the information extracted from the ID card</li>\n<li>One function performs simple HTTP request to a third-party API to validate the address</li>\n</ul>\n<p>Finally, four functions concern the websocket ( <code>connect</code> , <code>message</code> , and <code>disconnect</code> ) and notifications to the user.</p>\n<h3><a id=\"Opportunities_for_improvement_39\"></a><strong>Opportunities for improvement</strong></h3>\n<p>If you further analyze the code of the five basic functions (see <code>startWorkflow</code>on GitHub, for example), you will notice that there are actually three lines of fundamental code that start the workflow. The others 38 lines involve imports, input validation, error handling, logging, and tracing. Remember that all this code must be tested and maintained.</p>\n<p>Python</p>\n<pre><code class=\"lang-import\">import json\nimport boto3\nfrom aws_lambda_powertools import Tracer\nfrom aws_lambda_powertools import Logger\nimport re\n\nlogger = Logger()\ntracer = Tracer()\n\nsfn = boto3.client('stepfunctions')\n\nPATTERN = re.compile(r"^arn:(aws[a-zA-Z-]*)?:states:[a-z]{2}((-gov)|(-iso(b?)))?-[a-z]+-\\d{1}:\\d{12}:stateMachine:[a-zA-Z0-9-_]+$")\n\nif ('STATE_MACHINE_ARN' not in os.environ\n or os.environ['STATE_MACHINE_ARN'] is None\n or not PATTERN.match(os.environ['STATE_MACHINE_ARN'])):\n raise RuntimeError('STATE_MACHINE_ARN env var is not set or incorrect')\n\nSTATE_MACHINE_ARN = os.environ['STATE_MACHINE_ARN']\n\n@logger.inject_lambda_context\n@tracer.capture_lambda_handler\ndef handler(event, context):\n try:\n event['requestId'] = context.aws_request_id\n\n sfn.start_execution(\n stateMachineArn=STATE_MACHINE_ARN,\n input=json.dumps(event)\n )\n\n return {\n 'requestId': event['requestId']\n }\n except Exception as error:\n logger.exception(error)\n raise RuntimeError('Internal Error - cannot start the creation workflow') from error\n</code></pre>\n<p>After running this workflow several times and reviewing the <a href=\"https://aws.amazon.com/cn/xray/\" target=\"_blank\">AWS X-Ray</a> traces (Figure 3), we can see that it takes about 2–3 seconds when functions are warmed:</p>\n<p><img src=\"https://dev-media.amazoncloud.cn/4f9709ee7dd2488d97f17c8032f01940_image.png\" alt=\"image.png\" /></p>\n<p>Figure 3. X-Ray traces when Lambda functions are warmed</p>\n<p>But the process takes around 10 seconds with cold starts, as shown in Figure 4:</p>\n<p><img src=\"https://dev-media.amazoncloud.cn/e174c56a80314b868fd9bbc7fe502ec9_image.png\" alt=\"image.png\" /></p>\n<p>Figure 4. X-Ray traces when Lambda functions are cold</p>\n<p>We use an asynchronous architecture to avoid waiting time for the user, as this can be a long process. We also use WebSockets to notify the user when it’s finished. This adds some complexity, new components, and additional costs to the architecture. Now let’s look at how we can optimize this architecture.</p>\n<h3><a id=\"Improving_the_initial_architecture_96\"></a><strong>Improving the initial architecture</strong></h3>\n<h4><a id=\"Direct_integration_with_Step_Functions_97\"></a><em>Direct integration with Step Functions</em></h4>\n<p>Step Functions can directly <a href=\"https://docs.aws.amazon.com/step-functions/latest/dg/connect-supported-services.html\" target=\"_blank\">integrate with some AWS services,</a> including DynamoDB, Amazon SQS, and EventBridge, and <a href=\"https://docs.aws.amazon.com/step-functions/latest/dg/supported-services-awssdk.html#supported-services-awssdk-list\" target=\"_blank\">more than 10,000 APIs</a> from 200+ AWS services. With these integrations, you can replace Lambda functions when they do not provide value. We recommend using Lambda functions to transform data, not to transport data from one service to another.</p>\n<p>In our bank account creation use case, there are four Lambda functions we can replace with direct service integrations (see large arrows in Figure 5):</p>\n<ul>\n<li>Query a DynamoDB table to search for a user</li>\n<li>Send a message to an SQS queue when the extraction fails</li>\n<li>Create the user in DynamoDB</li>\n<li>Send an event on EventBridge to notify the backend</li>\n</ul>\n<p><img src=\"https://dev-media.amazoncloud.cn/11ac81636b034210a1390ff313be1f4a_image.png\" alt=\"image.png\" /></p>\n<p>Figure 5. Lambda functions that can be replaced</p>\n<p>It is not as clear that we need to replace the other Lambda functions. Here are some considerations:</p>\n<ul>\n<li>To extract information from the ID card, we use Amazon Textract. It is available through the SDK integration in Step Functions. However, the API’s response provides too much information. We recommend using a library such as <a href=\"https://github.com/aws-samples/amazon-textract-response-parser\" target=\"_blank\">amazon-textract-response-parser</a> to parse the result. For this, you’ll need a Lambda function.</li>\n<li>The identity cross-check performs a simple comparison between the data provided in the web form and the one extracted in the ID card. We can perform this comparison in Step Functions using a Choicestate and several conditions. If the business logic becomes more complex, consider using a Lambda function.</li>\n<li>To validate the address, we query a third-party API. Step Functions cannot directly call a third-party HTTP endpoint, but because it’s integrated with API Gateway, we can <a href=\"https://jeromevdl.medium.com/step-functions-with-api-gateway-integration-good-idea-8cbe9fff63ef\" target=\"_blank\">create a proxy for this endpoint</a>.<br />\nIf you only need to retrieve data from an API or make a simple API call, use the direct integration. If you need to implement some logic, use a Lambda function.</li>\n</ul>\n<h4><a id=\"Direct_integration_with_API_Gateway_118\"></a><em>Direct integration with API Gateway</em></h4>\n<p>API Gateway also provides service integrations. In particular, we can start the workflow without using a Lambda function. In the console, select the integration type “AWS Service”, the AWS service “Step Functions”, the action “StartExecution”, and “POST” method, as shown in Figure 6.</p>\n<p><img src=\"https://dev-media.amazoncloud.cn/98662e4d400a4ab598972fce9caff172_image.png\" alt=\"image.png\" /></p>\n<p>Figure 6. API Gateway direct integration with Step Functions</p>\n<p>After that, use a <a href=\"https://docs.aws.amazon.com/apigateway/latest/developerguide/models-mappings.html\" target=\"_blank\">mapping template</a> in the integration request to define the parameters as shown here:</p>\n<pre><code class=\"lang-\">{\n "stateMachineArn":"arn:aws:states:eu-central-1:123456789012:stateMachine: accountCreationWorkflow",\n "input":"$util.escapeJavaScript($input.json('$'))"\n}\n</code></pre>\n<p>We can go further and remove the websockets and associated Lambda functions <code>connect</code>,<code>message</code>, and <code>disconnect</code><br />\n. By using <a href=\"https://aws.amazon.com/cn/blogs/compute/new-synchronous-express-workflows-for-aws-step-functions/\" target=\"_blank\">Synchronous Express Workflows</a> and the <code>StartSyncExecution</code><br />\nAPI, we can start the workflow and wait for the result in a synchronous fashion. API Gateway will then directly return the result of the workflow to the client.</p>\n<h3><a id=\"Final_optimized_architecture_137\"></a><strong>Final optimized architecture</strong></h3>\n<p>After applying these optimizations, we have the updated architecture shown in Figure 7. It uses only two Lambda functions out of the initial 13. The rest have been replaced by direct service integrations or implemented in Step Functions.</p>\n<p><img src=\"https://dev-media.amazoncloud.cn/f3660e8e64de4a62a70ee13406e26451_image.png\" alt=\"image.png\" /></p>\n<p>Figure 7. Final optimized architecture</p>\n<p>We were able to remove 11 Lambda functions and their associated fees. In this architecture, the cost is mainly driven by Step Functions, and the main price difference will be your use of <a href=\"https://docs.aws.amazon.com/step-functions/latest/dg/concepts-standard-vs-express.html\" target=\"_blank\">Express Workflows instead of Standard Workflows</a>. If you need to keep some Lambda functions, use <a href=\"https://github.com/alexcasalboni/aws-lambda-power-tuning\" target=\"_blank\">AWS Lambda Power Tuning</a> to configure your function correctly and benefit from the best price/performance ratio.</p>\n<p>One of the main benefits of this architecture is performance. With the final workflow architecture, it now takes about 1.5 seconds when the Lambda function is warmed and 3 seconds on cold starts (versus up to 10 seconds previously), see Figure 8:</p>\n<p><img src=\"https://dev-media.amazoncloud.cn/dd03e56cbdd34c7ab39a65378c7269bd_image.png\" alt=\"image.png\" /></p>\n<p>Figure 8. X-Ray traces for the final architecture</p>\n<p>The process can now be synchronous. It reduces the complexity of the architecture and vastly improves the user experience.</p>\n<p>An added benefit is that by reducing the overall complexity and removing the unnecessary Lambda functions, we have also reduced the risk of failures. These can be errors in the code, memory or timeout issues due to bad configuration, lack of permissions, network issues between components, and more. This increases the resiliency of the application and eases its maintenance.</p>\n<h3><a id=\"Testing_156\"></a><strong>Testing</strong></h3>\n<p>Testability is an important consideration when building your workflow. Unit testing a Lambda function is straightforward, and you can use your preferred testing framework and validate methods. Adopting a hexagonal architecture also helps remove dependencies to the cloud.</p>\n<p>When removing functions and using an approach with direct service integrations, you are by definition directly connected to the cloud. You still must verify that the overall process is working as expected, and validate these integrations.</p>\n<p>You can achieve this kind of tests locally using Step Functions Local, and the recently announced Mocked Service Integrations. By mocking service integrations, for example, retrieving an item in DynamoDB, you can validate the different paths of your state machine.</p>\n<p>You also have to perform integration tests, but this is true whether you use direct integrations or Lambda functions.</p>\n<h3><a id=\"Conclusion_165\"></a><strong>Conclusion</strong></h3>\n<p>This post describes how to simplify your architecture and optimize for performance, resiliency, and cost by using direct integrations in Step Functions and API Gateway. Although many Lambda functions were reduced, some remain useful for handling more complex business logic and data transformation. Try this out now by visiting the GitHub repository.</p>\n<p><strong>For further reading:</strong></p>\n<ul>\n<li><a href=\"https://aws.amazon.com/cn/blogs/compute/building-well-architected-serverless-applications-optimizing-application-performance-part-3/\" target=\"_blank\">Building well-architected serverless applications: Optimizing application performance – part 3</a></li>\n<li><a href=\"https://aws.amazon.com/cn/blogs/aws/now-aws-step-functions-supports-200-aws-services-to-enable-easier-workflow-automation/\" target=\"_blank\">AWS Step Functions Supports 200 AWS Services To Enable Easier Workflow Automation</a></li>\n</ul>\n<h4><a id=\"Jerome_Van_Der_Linden_172\"></a><strong>Jerome Van Der Linden</strong></h4>\n<p><img src=\"https://dev-media.amazoncloud.cn/56bf4578a8bc4676925a719c80220a72_image.png\" alt=\"image.png\" /></p>\n<p>Jerome is a Solutions Architect at AWS, where he works for different customers in Switzerland, helping them on their journey to the cloud. As a former developer, he built a strong experience on software craftsmanship and devops practices. He’s also passionate about serverless. In his spare time, and when snow is here, he enjoys skiing with his kids. Reach out to him on twitter: @jeromevdl.</p>\n"}