AWS Cloud Development Kit (CDK) Launches Refactor

Wait 5 sec.

We are excited to announce a new AWS Cloud Development Kit (CDK) feature that makes it easier and safer to refactor your infrastructure as code. CDK Refactor aims to preserve your AWS resources as you rename constructs, move resources between stacks, and reorganize your CDK applications – operations that previously risked resource replacement. When writing infrastructure as code with the CDK, developers occasionally need to rename Constructs or move them between Stacks or directories. Whether they need to better organize their code, adhere to coding best practices, or take advantage of object-oriented programming patterns like class inheritance, these changes can be risky in environments with deployed resources, because they change the CDK-generated logical ID of those resources. During a CDK deploy, AWS CloudFormation interprets these changes as new resources, which often requires deletion of the existing resource and creation of a new resource with the new logical ID. For stateful resources, this could cause potential downtime and even data loss. To mitigate this effect of ID changes, developers had to stage their changes to create new resources, create a data or network migration plan, and then delete the old resources to prevent these refactoring effects. Sometimes, developers decide the risk of these changes outweigh the benefit of the refactor and choose not perform the refactor at all. Today, developers can use the new CDK refactor command to detect, review, confirm, and safely apply refactored changes to their resources without resource replacement. This feature leverages the recently-launched AWS CloudFormation refactor feature, but the CDK automatically computes the mappings that CloudFormation needs to redefine the refactored resources, providing a layer of abstraction that allows developers to focus on code rather than resource configuration. Let’s walk through an example to demonstrate the benefits of this refactor capability. Prerequisites Along with the usual CDK prerequisites, if you bootstrapped your CDK project before this launch, you need to re-bootstrap your environment to obtain the new permissions associated with the CDK refactor capabilities before attempting your refactor. Monolith to micro-service example For this example, let’s say that we have a legacy CDK App that deploys a monolithic Stack with Amazon DynamoDB tables for users, products, and orders, and an AWS Lambda function that implements CRUD operations on all entities. Monolithic application function monolithApp() { const monolith = new CdkAppStack(app, monolithStackName, {env}); const usersTable = makeTable(monolith, 'users'); const productsTable = makeTable(monolith, 'products'); const ordersTable = makeTable(monolith, 'orders'); // We have a single Lambda function in our application const func = new Function(monolith, `MonolithFunction`, { code: Code.fromInline(`Some code that accesses all three tables`), runtime: Runtime.NODEJS_22_X, handler: 'index.handler', }); usersTable.grantReadWriteData(func); productsTable.grantReadWriteData(func); ordersTable.grantReadWriteData(func); // This function creates a REST API, resources, methods, and links // everything together to the functions. Right now, we are passing // the same function in three places. makeApi(monolith, { usersFunction: func, productsFunction: func, ordersFunction: func, });}monolithApp(); We’ve been asked to adhere to Well Architected Framework best practices and break up the monolith into separate Lambda functions so they can scale independently. Because they’re so similar, we’re also going to create an inheritable Lambda class that we can reuse to improve readability and maintainability of the code, and avoid having to re-define Lambda configuration settings that are consistent across all of the functions. Finally, the monolith uses only L1 CDK Constructs. To further abstract our code and take advantage of helper functions, we’re going to start using L2 CDK Constructs for DynamoDB, Lambda, and API Gateway. This change will allow the IAM Roles and permissions to be defined automatically, further simplifying our code. Proposed refactored application into separate stacks for each domain. Without the refactor feature, CloudFormation would delete and re-create the Lambda and DynamoDB resources, which would cause all of the data in the latter to be lost. Alternatively, you could create net-new Lambdas and Amazon DynamoDB tables in one deployment, execute an out-of-band, point-in time and streaming data migration from the old tables to the new ones, update the API Gateway configuration to target the new Lambdas in a second deploy, and turn off the streaming migration process. With the refactor feature, we can move the resource definitions to new files, update them to L2 Constructs, and leave the stateful resources in place! Replace stateless resources First, let’s refactor our CDK code to break the monolithic Lambda into 3 domain-specific Lambdas. CloudFormation’s refactor capability doesn’t support creating new resources or updating configuration of existing resources, so we will deploy these changes as usual, without using the new refactor feature. All resources will stay inside the monolithic stack for now. Refactor stateless single lambda function into 3 functions as a prerequisite to the refactor of stateful DynamoDB tables. function singleStackMicroservicesApp() { // We still have a single stack const monolith = new CdkAppStack(app, monolithStackName, {env}); // makeFunctionAndTable creates a different Lambda function and a DynamoDB table // for each domain that is passed as a parameter. // In a real CDK application, you would probably define each of them independently. makeApi(monolith, { usersFunction: makeFunctionAndTable(monolith, 'users'), productsFunction: makeFunctionAndTable(monolith, 'products'), ordersFunction: makeFunctionAndTable(monolith, 'orders'), });}singleStackMicroservicesApp(); Refactor stateful resources Now we can refactor the stateful DynamoDB tables and their respective Lambdas to their own stacks, using cdk refactor to map their new IDs without replacing the resources. Before refactoring, though, we need to create the new stacks that will receive the functions and tables: singleStackMicroservicesApp(); const usersStack = new Stack(app, 'Users', {env}); const productsStack = new Stack(app, 'Products', {env}); const ordersStack = new Stack(app, 'Orders', {env}); Refactored Lambda functions and DynamoDB tables into their own separate stacks. function fullMicroservicesApp() { const monolith = new Stack(app, monolithStackName, {env}); const usersStack = new Stack(app, 'Users', {env}); const productsStack = new Stack(app, 'Products', {env}); const ordersStack = new Stack(app, 'Orders', {env}); makeApi(monolith, { // Now each pair function + table is in its own stack usersFunction: makeFunctionAndTable(usersStack, 'users'), productsFunction: makeFunctionAndTable(productsStack, 'products'), ordersFunction: makeFunctionAndTable(ordersStack, 'orders'), });}fullMicroservicesApp(); Running cdk refactor –unstable=refactor starts the process. (The unstable flag is required as this feature is still subject to breaking changes.) The CDK will compare the current state of your application (the deployed monolithic app) with the new state (the output of your refactored CDK application). CDK refactor confirmation dialog As expected, it shows a table of resources that were moved from the Monolith stack to their respective refactored stacks. By default, the CLI asks for confirmation before proceeding. Bypass the confirmation by passing the –force flag, or confirm the changes and execute the refactor: All resources, including the stateful tables, were safely moved to other stacks, and we now have our well-architected application. CDK refactor results Conclusion With the CDK refactor feature, developers can take full advantage of the object-oriented definition of AWS resources, including the ability to change the structure and layers of abstraction without orchestrating complex migration mechanisms or scheduled downtime. Since the CDK is open source, you can learn more about how the CDK automatically determines what resources need to be refactored via the README. Understanding when resources need to be replaced and refactored will help you plan your infrastructure as code roadmap and when you should use this new refactoring capability. If you’ve got a refactor that you’ve been waiting to execute, read more about the feature set in the CDK refactor documentation and start refactoring your own CDK App today! Authors Natalie White Natalie White is a Principal Solutions Architect at Amazon Web Services. She helps Healthcare and Life Sciences customers deploy solutions to AWS, and uses her software development background to accelerate infrastructure as code automation using the AWS Cloud Development Kit (CDK). She also consults engineering leaders on DevOps cultural transformations. Otavio Macedo Otavio Macedo is a Software Development Engineer at Amazon Web Services. He has been with the AWS Cloud Development Kit (CDK) team since 2021, helping deliver the unique experience that CDK provides for customers.