<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ian Carlson</title>
    <description>The latest articles on DEV Community by Ian Carlson (@ian_carlson_0c77f977f7790).</description>
    <link>https://dev.to/ian_carlson_0c77f977f7790</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2040598%2Ff7046b9a-a32f-4a52-85a8-7fc13dd3f39f.jpg</url>
      <title>DEV Community: Ian Carlson</title>
      <link>https://dev.to/ian_carlson_0c77f977f7790</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ian_carlson_0c77f977f7790"/>
    <language>en</language>
    <item>
      <title>No Red Pills, Just Hygiene – A Dating Guide for Single Male Engineers</title>
      <dc:creator>Ian Carlson</dc:creator>
      <pubDate>Sun, 28 Dec 2025 20:11:32 +0000</pubDate>
      <link>https://dev.to/ian_carlson_0c77f977f7790/no-red-pills-just-hygiene-a-dating-guide-for-single-male-engineers-4e3p</link>
      <guid>https://dev.to/ian_carlson_0c77f977f7790/no-red-pills-just-hygiene-a-dating-guide-for-single-male-engineers-4e3p</guid>
      <description>&lt;p&gt;I never thought I'd be writing about this topic, yet here we are. I feel like this issue has become so endemic to young male culture that the obvious must be clearly stated. &lt;/p&gt;

&lt;p&gt;These tips are solely for young single men who are frustrated with dating women. I'm not an expert. This isn't professional advice. I'm a white, male, married engineer who dated for many years, and I have known many engineers who struggle with this issue. I feel like I have some practical advice to give that doesn't involve Andrew Tate or Red Pill culture.&lt;/p&gt;

&lt;h3&gt;The Engineering Approach to Dating&lt;/h3&gt;

&lt;p&gt;The crux of the problem is that many single men do not put in the required effort to attract a woman (or any person, for that matter). Some of it is laziness—we've all been there. Some of it is genetics. Some of it is circumstance. Generally, you don't have control over all those things, so you have to let them go and focus on things that truly serve your long-term goals. Only you can truly decide what those are and start moving in that direction.&lt;/p&gt;

&lt;p&gt;In a way, you can address the courtship problem with an engineering mind. Dating is a system. To get the desired outputs, you need to determine the correct inputs. This is traditionally done through trial and error. However, it seems like instead of experimentation, men are giving up entirely. Sometimes it's conscious, sometimes not.&lt;/p&gt;

&lt;p&gt;Regardless, there are some basic things you can try, which will probably also make you a happier person:&lt;/p&gt;

&lt;p&gt;Hygiene – Bro, brush your teeth, use mouthwash, shower regularly, use soap. It's not that hard.&lt;/p&gt;

&lt;p&gt;Get a good-paying job – Harder, but doable.&lt;/p&gt;

&lt;p&gt;Sleep as best as you can – Even harder, but doable.&lt;/p&gt;

&lt;p&gt;Exercise – At least 3 times a week at a gym or studio with other people.&lt;/p&gt;

&lt;p&gt;Eat well.&lt;/p&gt;

&lt;p&gt;Get some decent clothes and shoes. Shoes are important.&lt;/p&gt;

&lt;p&gt;Do activities that involve women – This is a pretty big topic. Weirdly, I don't think the gym is great for meeting women, especially if they're working out by themselves with headphones on. However, if it's a group fitness class, that's usually a better bet. (It is still important to stay healthy, so a gym with no babes is still worthwhile). Salsa or swing classes are usually pretty good. Yoga classes as well. Try in-person speed dating if possible.&lt;/p&gt;

&lt;p&gt;Cut back on "Bro/Video game" time – You may need to reduce this. It's ok; it's not the end of the world. Balance is good.&lt;/p&gt;

&lt;p&gt;Make some friends who are women – Age doesn't matter. Just don't be too weird.&lt;/p&gt;

&lt;p&gt;Get a dog or cat – But actually take care of it.&lt;/p&gt;

&lt;p&gt;You don't need to do all of these things, but I would say most of them are pretty important. They all require effort. I know, it's tough. I'm partially saying this in jest, but I also believe it. You don't have to be a pickup artist or a model to go on dates. I'm not a swinger, just a married man who dated in the past and sees many men struggling.&lt;/p&gt;

&lt;h3&gt;Reading the Signals&lt;/h3&gt;

&lt;p&gt;Also, remember: it's not rude to ask someone out for coffee if you're already having a good chat and she is showing signs of interest. Let's go into some basic signs of interest from her, shall we?&lt;/p&gt;

&lt;p&gt;She is contributing to the conversation.&lt;/p&gt;

&lt;p&gt;She appears to be happy in your presence.&lt;/p&gt;

&lt;p&gt;She is touching any part of your body.&lt;/p&gt;

&lt;p&gt;I know this sounds ridiculously obvious to some people, but you'd be surprised how clueless some men can be. I was at one time. If she's not demonstrating any of those things, then you should probably end the conversation respectfully, or just treat them like any other respectful person. No harm, no foul, no biggie.&lt;/p&gt;

&lt;p&gt;In the post-Me Too era, many men may think that any show of interest is bad. Quite the contrary. It's ok to show interest. Just do it respectfully.&lt;/p&gt;

</description>
      <category>dating</category>
      <category>lifestyle</category>
    </item>
    <item>
      <title>New AWS Lambda Durable Functions – Do they replace Step Functions?</title>
      <dc:creator>Ian Carlson</dc:creator>
      <pubDate>Sun, 14 Dec 2025 16:06:37 +0000</pubDate>
      <link>https://dev.to/ian_carlson_0c77f977f7790/new-aws-lambda-durable-functions-do-they-replace-step-functions-2c5i</link>
      <guid>https://dev.to/ian_carlson_0c77f977f7790/new-aws-lambda-durable-functions-do-they-replace-step-functions-2c5i</guid>
      <description>&lt;p&gt;The serverless landscape just shifted beneath our feet. With the release of &lt;strong&gt;AWS Lambda durable functions&lt;/strong&gt; this December 2025, Amazon has introduced a new feature that developers have been asking for since the dawn of FaaS (function as a service).&lt;/p&gt;

&lt;p&gt;In short, durable functions allow you to write stateful, long-running workflows entirely within your lambda code using familiar &lt;code&gt;await&lt;/code&gt; syntax. You can pause execution for days, weeks, or even up to a year without paying for idle compute, and pick right back up where you left off with local state intact.&lt;/p&gt;

&lt;p&gt;Currently available exclusively in the &lt;strong&gt;us-east-2 (Ohio)&lt;/strong&gt; region, this feature is slated for a wider global rollout in Q2 of 2026. But even with its limited availability, it poses a big question for cloud architects: With the ability to handle retries, waits, and complex state management directly in code, is the reign of AWS Step Functions over?&lt;/p&gt;

&lt;p&gt;This article breaks down the new functional overlap, the distinct differences in developer ergonomics and pricing, and where each tool belongs in your 2026 serverless stack.&lt;/p&gt;




&lt;h3&gt;
  
  
  A Quick History Lesson
&lt;/h3&gt;

&lt;p&gt;To understand why this update is such a big deal, we have to look at history. AWS Lambda and AWS Step Functions have been staples of serverless architectures for years. Lambda provided the raw compute, and Step Functions provided the orchestration and low-code interface.&lt;/p&gt;

&lt;p&gt;Step Functions was originally introduced to solve a specific pain point: the infamous "Lambda calling Lambda" anti-pattern. Chaining functions together manually in code was brittle, hard to debug, and surprisingly expensive. Step Functions offered a robust, managed alternative designed to handle long-running, multi-step, transactional workloads. It took the burden of state tracking, error handling, and retry logic out of your code and into a managed service platform.&lt;/p&gt;

&lt;p&gt;For years, the separation of responsibilies was clear. If you needed business logic, you wrote a Lambda. If you needed to coordinate that logic with a low-code interface, you built a Step Function state machine. This approach was particularly empowering for non-programmers or operations teams because Step Functions uses a configuration-based workflow (ASL - Amazon States Language) paired with an excellent visual editor. It allows you to drag-and-drop hundreds of zero-code integrations—connecting S3 events to DynamoDB puts to SQS queues—without writing a single line of Python or Node.js.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Friction of State Machines
&lt;/h3&gt;

&lt;p&gt;However, Step Functions hasn't been perfect. For a long time, it was strictly stateless between steps, meaning you had to pass-through large JSON payloads from one state to the next just to keep track of context.&lt;/p&gt;

&lt;p&gt;Furthermore, the "configuration-first" nature of Step Functions created a barrier for pure software engineering workflows. You cannot easily execute a complex Step Function on your laptop. Debugging often involves deploying to the cloud, running an execution, checking the console logs, tweaking the ASL JSON, and redeploying. It works, but the feedback loop is painfully slow compared to local unit testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where They Now Overlap
&lt;/h3&gt;

&lt;p&gt;Functionally, Lambda Durable Functions and Step Functions now occupy the same neighborhood. If you look at their capabilities on paper, the lines are blurry. Both services now offer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero Cost for Waiting:&lt;/strong&gt; Both services allow you to pause execution for up to a year without paying for idle compute time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in Resilience:&lt;/strong&gt; Both have robust mechanisms to catch errors with exponential backoff and retry failed steps or sub-routines automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State Persistence:&lt;/strong&gt; Both "remember" exactly where they left off after a sleep period or an unexpected crash, ensuring workflows complete reliably.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If both tools can wait for a month and retry a failed API call, how do you choose?&lt;/p&gt;

&lt;h3&gt;
  
  
  The Great Divide: Code vs. Config
&lt;/h3&gt;

&lt;p&gt;The real difference lies in &lt;strong&gt;ergonomics&lt;/strong&gt; and the &lt;strong&gt;development lifecycle&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS Lambda Durable Functions is unapologetically code-first.&lt;/strong&gt; It brings workflow orchestration &lt;em&gt;inside&lt;/em&gt; the function. You use standard programming constructs—&lt;code&gt;if&lt;/code&gt; statements, &lt;code&gt;for&lt;/code&gt; loops, and &lt;code&gt;try/catch&lt;/code&gt; blocks—to manage your flow. If you want to wait for a week, you don't drag a "Wait State" box onto a canvas; you simply write &lt;code&gt;await context.wait({ seconds: 30 })&lt;/code&gt; in your code.&lt;/p&gt;

&lt;p&gt;This unlocks the holy grail of serverless development: &lt;strong&gt;Local Debugging&lt;/strong&gt;. Because it is just code, you can use standard unit testing frameworks (like Jest or Pytest), mock the durable steps, and step through your entire orchestration logic with breakpoints locally on your machine before ever touching the cloud. You can share libraries, use distinct variable scoping, and manage complexity using standard software engineering patterns. You can also perform full integration testing from your laptop – by generating temporary keys from the AWS console, you can securely interact with cloud services over authenticated and encrypted connections to AWS services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS Step Functions remains configuration-first.&lt;/strong&gt; Where it shines is in &lt;strong&gt;Visual Observability&lt;/strong&gt;. When a complex business process fails at 3 AM, an on-call engineer (who may not be a coder) can look at the Step Functions graph in the AWS Console, see exactly which green box turned red, inspect the input and output data at that exact moment, and understand the failure.&lt;/p&gt;

&lt;p&gt;It also excels at &lt;strong&gt;Integration&lt;/strong&gt;. If your workflow is mostly "gluing" AWS services together—e.g., &lt;em&gt;Take file from S3 -&amp;gt; Transcribe it -&amp;gt; Save results to DynamoDB -&amp;gt; Email user via SES&lt;/em&gt;—Step Functions lets you do this with essentially zero code. Doing the same in Durable Functions would require importing the AWS SDK for four different services and writing boilerplate code for every single step.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Pricing Equation
&lt;/h3&gt;

&lt;p&gt;Finally, let's talk about the wallet, because the billing models are fundamentally different.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step Functions (Standard Workflows):&lt;/strong&gt; You are billed based on &lt;strong&gt;State Transitions&lt;/strong&gt;. Roughly $25 per million transitions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lambda Durable Functions:&lt;/strong&gt; You are billed based on &lt;strong&gt;Requests + Compute Duration&lt;/strong&gt;. You pay for the time your code is actually executing on the CPU.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's look at a basic example: &lt;strong&gt;A workflow that loops 10,000 times to process small items.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In Step Functions:&lt;/strong&gt; You pay for every single step in that loop. A loop with just 3 states (Task, Choice, Wait) running 10,000 times equals 30,000 state transitions. That bill can climb surprisingly fast for high-throughput looping.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In Lambda Durable Functions:&lt;/strong&gt; You pay for the aggregate compute time it takes to run the loop's logic. Since modern Lambda runtimes pause and resume incredibly efficiently, iterating through a loop in memory with short bursts of CPU activity is virtually free compared to the cost of 30,000 discrete state transitions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conversely, for a workflow that consists solely of "Wait 6 months, then send one email," Step Functions is incredibly cheap (only a few transitions), while Durable Functions is also cheap (zero compute during wait), but involves slightly more overhead for management.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;So, does AWS Lambda Durable Functions replace Step Functions?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you are a developer: Yes, mostly.&lt;/strong&gt;&lt;br&gt;
If you live in your IDE and value unit testing, fast local debugging cycles, and managing complex logic through code constructs rather than JSON configuration, Durable Functions is the tool you have been waiting for. It removes the context-switching tax of managing ASL files and lets you build complex, durable backends using the languages you already love.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you are an architect or ops-focused: No.&lt;/strong&gt;&lt;br&gt;
Step Functions remains the king of high-level infrastructure orchestration. Its superior visual observability, hundreds of zero-code integrations, and ability to be easily audited by non-technical stakeholders make it indispensable for "macro" workflows that tie together disparate AWS services.&lt;/p&gt;

&lt;p&gt;The sheer number of AWS services can be overwhelming, but a lot of that is just due to how software naturally evolves and the need to keep old things working—which businesses definitely appreciate. But for me personally, I'll be choosing Durable Functions over Step Functions in most cases going forward because I'm a developer first.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>aws</category>
      <category>architecture</category>
      <category>news</category>
    </item>
    <item>
      <title>Mastering AWS CDK Dependencies: How to Avoid the "Stuck Stack" Deadlock</title>
      <dc:creator>Ian Carlson</dc:creator>
      <pubDate>Sat, 06 Dec 2025 16:59:42 +0000</pubDate>
      <link>https://dev.to/ian_carlson_0c77f977f7790/mastering-aws-cdk-dependencies-how-to-avoid-the-stuck-stack-deadlock-2o34</link>
      <guid>https://dev.to/ian_carlson_0c77f977f7790/mastering-aws-cdk-dependencies-how-to-avoid-the-stuck-stack-deadlock-2o34</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcnahuvppbd3r6ko59gag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcnahuvppbd3r6ko59gag.png" alt="Image of aws cdk technology" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mastering AWS CDK Dependencies: How to Avoid the "Stuck Stack" Deadlock
&lt;/h2&gt;

&lt;p&gt;As applications built with the AWS Cloud Development Kit (CDK) grow in complexity, developers often encounter a specific, frustrating architectural hurdle: the CloudFormation export deadlock.&lt;/p&gt;

&lt;p&gt;It usually begins innocently. You might have a &lt;code&gt;DatabaseStack&lt;/code&gt; and an &lt;code&gt;ApiStack&lt;/code&gt;. To allow the API to access the database, you pass the DynamoDB table object from one stack to the other. Behind the scenes, CDK creates a CloudFormation export/import relationship.&lt;/p&gt;

&lt;p&gt;Months later, when you attempt to rename a resource or refactor the &lt;code&gt;DatabaseStack&lt;/code&gt;, the deployment fails with a blocking error:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Export Output:MyTableExport is in use by stack ApiStack&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You are now in a dependency deadlock. You cannot update the producer (Database) because the consumer (API) is referencing the export. Conversely, you cannot update the consumer to stop using the export because the deployment process relies on the valid state of the producer.&lt;/p&gt;

&lt;p&gt;There are robust architectural patterns to prevent this (Consolidation and Runtime Decoupling), but first, we must address the immediate operational issue: &lt;em&gt;How do you resolve an active deadlock?&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Immediate Remediation: Breaking the Deadlock
&lt;/h2&gt;

&lt;p&gt;If you are currently facing this error, standard deployments will not work because CloudFormation enforces strict referential integrity. You must manually break the dependency chain using a multi-step deployment process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Sever the Dependency (The "Detach" Deploy)
&lt;/h3&gt;

&lt;p&gt;Modify your Consumer Stack (e.g., &lt;code&gt;ApiStack&lt;/code&gt;) to stop referencing the Producer Stack's output.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;The Code Change:&lt;/em&gt; Temporarily hard-code the value you were previously importing. For example, replace the imported Table Object with a string literal: &lt;code&gt;const tableName = "my-actual-table-name"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;The Deploy:&lt;/em&gt; Deploy only the Consumer Stack (&lt;code&gt;cdk deploy ApiStack&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;The Result:&lt;/em&gt; CloudFormation updates the API stack. It removes the Import reference, freeing the Export.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Update the Producer
&lt;/h3&gt;

&lt;p&gt;With the export no longer "in use," you are free to modify the Producer Stack.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;The Code Change:&lt;/em&gt; Apply your intended refactor, rename, or deletion in the &lt;code&gt;DatabaseStack&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;The Deploy:&lt;/em&gt; Deploy the Producer Stack (&lt;code&gt;cdk deploy DatabaseStack&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;The Result:&lt;/em&gt; The deployment succeeds.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3: Re-bind the Resources
&lt;/h3&gt;

&lt;p&gt;Now that the infrastructure is in a clean state, you can restore the connection using one of the sustainable strategies outlined below.&lt;/p&gt;




&lt;h2&gt;
  
  
  Strategy 1: The Simplest Solution (Stack Consolidation)
&lt;/h2&gt;

&lt;p&gt;Before implementing complex decoupling patterns, it is worth evaluating whether multiple stacks are necessary for your use case.&lt;/p&gt;

&lt;p&gt;Historically, developers split applications into &lt;code&gt;NetworkStack&lt;/code&gt;, &lt;code&gt;DatabaseStack&lt;/code&gt;, and &lt;code&gt;ApiStack&lt;/code&gt; to avoid hitting the CloudFormation limit of 200 resources per stack. AWS has since increased this limit to 500 resources. Consequently, most medium-sized applications can comfortably fit within a single stack context.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Case for Consolidation
&lt;/h3&gt;

&lt;p&gt;When resources exist in the same stack, CloudFormation manages dependencies internally using Direct References rather than Export/Imports.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Eliminates Deadlocks:&lt;/strong&gt; CloudFormation automatically determines the correct order of operations for updates and replacements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Atomic Deployments:&lt;/strong&gt; The entire application either deploys successfully or rolls back completely, preventing inconsistent states.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplified Code:&lt;/strong&gt; There is no need to pass properties between stack classes or manage complex interface contracts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For single teams managing individual services, consolidation is often the most pragmatic approach.&lt;/p&gt;




&lt;h2&gt;
  
  
  Strategy 2: The Scalable Solution (Runtime Decoupling)
&lt;/h2&gt;

&lt;p&gt;If organizational boundaries or lifecycle differences (e.g., stateful vs. stateless resources) require you to maintain multiple stacks, you must decouple them to avoid future deadlocks.&lt;/p&gt;

&lt;p&gt;To do this, we shift from Deploy-time dependencies (hard CloudFormation Exports) to Runtime dependencies.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Stack A writes a configuration value (e.g., a Table Name) to a specialized store, such as AWS Systems Manager (SSM) Parameter Store.&lt;/li&gt;
&lt;li&gt; Stack B provides its Lambda function with the &lt;em&gt;key&lt;/em&gt; to that parameter.&lt;/li&gt;
&lt;li&gt; The Lambda fetches the value at runtime.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this model, the stacks are unaware of each other's existence; they share only a contract regarding the parameter key.&lt;/p&gt;




&lt;h2&gt;
  
  
  Implementation: The SSM Parameter Store Pattern
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: The Contract (Shared Configuration)
&lt;/h3&gt;

&lt;p&gt;Define the parameter name in a shared constant file. This ensures both the producer and consumer reference the exact same location in the Parameter Store.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/config.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TABLE_PARAM_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/my-app/prod/dynamodb-table-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: The Producer (Database Stack)
&lt;/h3&gt;

&lt;p&gt;Create the resource and publish its identifier to SSM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/database-stack.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;dynamodb&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-dynamodb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ssm&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-ssm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TABLE_PARAM_KEY&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DatabaseStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 1. Create the resource&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyTable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;partitionKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AttributeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;billingMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BillingMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PAY_PER_REQUEST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Publish the value to Parameter Store&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StringParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TableNameParam&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;parameterName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TABLE_PARAM_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;stringValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: The Consumer (API Stack)
&lt;/h3&gt;

&lt;p&gt;The API stack does not import the &lt;code&gt;DatabaseStack&lt;/code&gt;. It simply passes the parameter key to the Lambda environment and grants the necessary read permissions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/api-stack.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-lambda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ssm&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-ssm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TABLE_PARAM_KEY&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApiStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 1. Create the Lambda Function&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ApiHandler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODEJS_18_X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lambda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.handler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Pass the KEY, not the value&lt;/span&gt;
        &lt;span class="na"&gt;TABLE_CONFIG_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TABLE_PARAM_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Grant Permissions&lt;/span&gt;
    &lt;span class="c1"&gt;// Construct a reference to the parameter to grant specific access&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;param&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ssm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StringParameter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromStringParameterName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TableParamRef&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="nx"&gt;TABLE_PARAM_KEY&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;grantRead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;apiHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Runtime Logic with Caching
&lt;/h3&gt;

&lt;p&gt;Fetching parameters from SSM involves an API call, which introduces latency and cost. To optimize this, we utilize the Lambda Execution Context to cache the value. Variables defined outside the handler persist between invocations as long as the execution environment remains active ("warm").&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lambda/index.mjs&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SSMClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;GetParameterCommand&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-sdk/client-ssm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DynamoDBClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PutItemCommand&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-sdk/client-dynamodb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ssmClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SSMClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dynamoClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DynamoDBClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// GLOBAL CACHE&lt;/span&gt;
&lt;span class="c1"&gt;// These variables persist across warm invocations&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cachedTableName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cacheTimestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CACHE_TTL_MS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Cache for 5 minutes&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getTableName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. Check if cache is valid&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cachedTableName&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;cacheTimestamp&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;CACHE_TTL_MS&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Using cached table name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cachedTableName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. If not, fetch from SSM&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cache expired or empty. Fetching from SSM...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GetParameterCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TABLE_CONFIG_KEY&lt;/span&gt; 
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ssmClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Update Cache&lt;/span&gt;
  &lt;span class="nx"&gt;cachedTableName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Parameter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;cacheTimestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cachedTableName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getTableName&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PutItemCommand&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user_123&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;some data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;dynamoClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Written to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Beyond Parameter Store: Advanced Decoupling
&lt;/h2&gt;

&lt;p&gt;While SSM is the standard solution, specific requirements may dictate alternative stores.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Sensitive Data: AWS Secrets Manager
&lt;/h3&gt;

&lt;p&gt;If the shared value is sensitive (e.g., database credentials, API keys), do not use SSM Parameter Store. AWS Secrets Manager is the appropriate tool. The implementation pattern remains identical: the Producer writes the secret, and the Consumer fetches it at runtime using the SDK, ensuring data remains encrypted and rotatable.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Service Discovery: AWS Cloud Map
&lt;/h3&gt;

&lt;p&gt;For more complex, dynamic architectures, AWS Cloud Map offers a robust alternative to SSM. It allows you to register abstract resources (like S3 buckets or Event Buses) as "services" with custom attributes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Why Cloud Map?&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Logical Naming:&lt;/strong&gt; Resolve &lt;code&gt;my-app/user-service&lt;/code&gt; to dynamic endpoints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Health Checks:&lt;/strong&gt; Unlike SSM, Cloud Map can verify a resource's health before returning its address.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata:&lt;/strong&gt; Attach rich metadata (version, region, protocol) to the resource registration.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Dependency deadlocks in CloudFormation are a common rite of passage for CDK engineers, but they are not inevitable.&lt;/p&gt;

&lt;p&gt;If your architecture allows, Strategy 1 (Consolidation) is the most efficient path, resolving dependencies natively within the CloudFormation engine. For distributed systems requiring modularity, Strategy 2 (Runtime Decoupling) provides the flexibility needed to evolve stacks independently without fear of "locking" your infrastructure.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>aws</category>
      <category>cdk</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
