<?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: manojlingala</title>
    <description>The latest articles on DEV Community by manojlingala (@manojlingala).</description>
    <link>https://dev.to/manojlingala</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%2F1034302%2F93bb51e9-04e7-44e2-af34-014a9478b3be.jpg</url>
      <title>DEV Community: manojlingala</title>
      <link>https://dev.to/manojlingala</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/manojlingala"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>manojlingala</dc:creator>
      <pubDate>Sun, 09 Mar 2025 10:36:56 +0000</pubDate>
      <link>https://dev.to/manojlingala/-3a0g</link>
      <guid>https://dev.to/manojlingala/-3a0g</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/aws-builders" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&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%2Forganization%2Fprofile_image%2F2794%2F88da75b6-aadd-4ea1-8083-ae2dfca8be94.png" alt="AWS Community Builders " width="350" height="350"&gt;
      &lt;div class="ltag__link__user__pic"&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%2Fuser%2Fprofile_image%2F1034302%2F93bb51e9-04e7-44e2-af34-014a9478b3be.jpg" alt="" width="800" height="556"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/aws-builders/orchestrating-financial-transactions-with-aws-step-functions-3ilk" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Orchestrating Financial Transactions with AWS Step Functions&lt;/h2&gt;
      &lt;h3&gt;manojlingala for AWS Community Builders  ・ Mar 9&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#aws&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#stepfunctions&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#serverless&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>aws</category>
      <category>stepfunctions</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Orchestrating Financial Transactions with AWS Step Functions</title>
      <dc:creator>manojlingala</dc:creator>
      <pubDate>Sun, 09 Mar 2025 10:36:35 +0000</pubDate>
      <link>https://dev.to/aws-builders/orchestrating-financial-transactions-with-aws-step-functions-3ilk</link>
      <guid>https://dev.to/aws-builders/orchestrating-financial-transactions-with-aws-step-functions-3ilk</guid>
      <description>&lt;p&gt;In today's fast-paced financial sector, automation and precise orchestration of transactions can significantly boost efficiency and reliability. AWS Step Functions provides a powerful solution for managing complex workflows by integrating multiple AWS services seamlessly. In this article, we'll explore a real-world financial scenario—loan application processing—and demonstrate how AWS Step Functions can orchestrate these processes efficiently using C#.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario: Loan Application Processing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a customer applies for a loan, various sequential steps must occur:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application submission&lt;/li&gt;
&lt;li&gt;Credit score verification&lt;/li&gt;
&lt;li&gt;Risk assessment&lt;/li&gt;
&lt;li&gt;Decision making&lt;/li&gt;
&lt;li&gt;Notification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AWS Step Functions can orchestrate these steps with clear visualization and robust error handling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's define our workflow:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Start&lt;/p&gt;

&lt;p&gt;Verify Credit Score (AWS Lambda)&lt;br&gt;
Perform Risk Assessment (AWS Lambda)&lt;br&gt;
Decision Logic (AWS Lambda)&lt;br&gt;
Notify Customer (AWS Lambda)&lt;/p&gt;

&lt;p&gt;End&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementing the Workflow with AWS Step Functions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Step 1: Define State Machine&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"StartAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VerifyCreditScore"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"States"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"VerifyCreditScore"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:region:account-id:function:VerifyCreditScore"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RiskAssessment"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"RiskAssessment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:region:account-id:function:RiskAssessment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DecisionMaking"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"DecisionMaking"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Choice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Choices"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Variable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$.riskLevel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"StringEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Low"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ApproveLoan"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Variable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$.riskLevel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"StringEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"High"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DeclineLoan"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ApproveLoan"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:region:account-id:function:NotifyApproval"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"End"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"DeclineLoan"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:region:account-id:function:NotifyDecline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"End"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How Transitions Work Between Steps&lt;/p&gt;

&lt;p&gt;Transitions between steps in AWS Step Functions occur through clearly defined "Next" parameters. Each state explicitly specifies the next state it should transition to upon completion:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Task States:&lt;/em&gt;&lt;/strong&gt; Perform work using Lambda functions or other AWS services. Upon successful execution, they transition automatically to the next state defined by the "Next" parameter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Choice States:&lt;/em&gt;&lt;/strong&gt; Evaluate conditions to determine the next state. Choices are evaluated sequentially until a matching condition is found, then the workflow transitions to the corresponding state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;End States:&lt;/em&gt;&lt;/strong&gt; If a state has "End": true, it signifies the termination of the workflow.&lt;/p&gt;

&lt;p&gt;AWS Step Functions uses JSON paths to pass output data from one state as input to the next, enabling seamless data flow through the workflow.&lt;/p&gt;

&lt;p&gt;C# Implementation (Lambda Functions)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Verify Credit Score&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreditCheck&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CreditResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LoanRequest&lt;/span&gt; &lt;span class="n"&gt;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;// Simulate fetching credit score&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;creditScore&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;GetCreditScoreAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CreditResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;CreditScore&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;creditScore&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;p&gt;&lt;strong&gt;2. Risk Assessment&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RiskAssessment&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;RiskResponse&lt;/span&gt; &lt;span class="nf"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CreditResponse&lt;/span&gt; &lt;span class="n"&gt;creditResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;riskLevel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;creditResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreditScore&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;700&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"Low"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"High"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;RiskResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;RiskLevel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;riskLevel&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;p&gt;&lt;strong&gt;3. Notify Customer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Approval Notification&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NotifyApproval&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LoanRequest&lt;/span&gt; &lt;span class="n"&gt;request&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="n"&gt;EmailService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendApprovalAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerEmail&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;p&gt;Decline Notification&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NotifyDecline&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LoanRequest&lt;/span&gt; &lt;span class="n"&gt;request&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="n"&gt;EmailService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendDeclineAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerEmail&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;p&gt;&lt;strong&gt;Benefits&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visibility:&lt;/strong&gt;&lt;br&gt;
AWS Step Functions provides visual monitoring of each step, simplifying troubleshooting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reliability:&lt;/strong&gt;&lt;br&gt;
Automatic retries and error handling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scalability:&lt;/strong&gt;&lt;br&gt;
Easy integration with various AWS services.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>stepfunctions</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Single Table Design in AWS DynamoDB</title>
      <dc:creator>manojlingala</dc:creator>
      <pubDate>Sat, 27 Jul 2024 02:57:57 +0000</pubDate>
      <link>https://dev.to/aws-builders/single-table-design-in-aws-dynamodb-ld8</link>
      <guid>https://dev.to/aws-builders/single-table-design-in-aws-dynamodb-ld8</guid>
      <description>&lt;p&gt;As a developer working with AWS DynamoDB, I recently learnt and implemented Single Table Design in my projects. Single Table Design is a powerful and efficient approach to data modeling that has transformed the way I structure and query data in DynamoDB. &lt;/p&gt;

&lt;p&gt;In this article, I want to share my learning experience, demonstrate the concepts I've grasped, and showcase the benefits of Single Table Design through real-world examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Single Table Design
&lt;/h2&gt;

&lt;p&gt;Let's explore how to implement Single Table Design using a real-world example of a blog application. We'll consider scenarios such as creating users, articles, comments, and likes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdkv9zqfurjpt43jqkyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdkv9zqfurjpt43jqkyg.png" alt="Single Table Design Overview" width="800" height="246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Scenario 1: Creating a User&lt;/strong&gt;&lt;br&gt;
When creating a user, we store the user information in the table with the following structure:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pk"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USER#789"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sk"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PROFILE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"user_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"john.doe@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2023-05-20"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The PK is set to USER#, uniquely identifying the user.&lt;/li&gt;
&lt;li&gt;The SK is set to a constant value, such as PROFILE, to indicate that this item represents the user's profile information.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Scenario 2: Creating an Article&lt;/strong&gt;&lt;br&gt;
When a user creates an article, we store the article information in the table with the following structure:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pk"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USER#789"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sk"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ARTICLE#123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Introduction to Single Table Design"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Single Table Design is a powerful technique in DynamoDB..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2023-05-20"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The PK is set to USER#, indicating the user who created the article.&lt;/li&gt;
&lt;li&gt;The SK is set to ARTICLE#, uniquely identifying the article within the user's partition.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To query all articles created by a specific user, we can use the following query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"789"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;QueryRequest&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;TableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"BlogApplication"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"pk = :user_id AND begins_with(sk, :article_prefix)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ExpressionAttributeValues&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AttributeValue&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;":user_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AttributeValue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"USER#&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;":article_prefix"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AttributeValue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ARTICLE#"&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;dynamoDbClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;QueryAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;articles&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Scenario 3: User Commenting on an Article&lt;/strong&gt;&lt;br&gt;
When a user comments on an article, we store the comment information in the table with the following structure:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pk"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USER#789"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sk"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INTERACTION#COMMENT#ARTICLE#123#456"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"interaction_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"COMMENT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Great article! Thanks for sharing."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"article_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ARTICLE#123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2023-05-21"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The PK is set to USER#, indicating the user who made the comment.&lt;/li&gt;
&lt;li&gt;The SK is set to INTERACTION#COMMENT#ARTICLE##, uniquely identifying the comment within the user's partition and associating it with the article.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To query all comments made by a specific user, we can use the following query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"789"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;QueryRequest&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;TableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"BlogApplication"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"pk = :user_id AND begins_with(sk, :comment_prefix)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ExpressionAttributeValues&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AttributeValue&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;":user_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AttributeValue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"USER#&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;":comment_prefix"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AttributeValue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"INTERACTION#COMMENT#"&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;dynamoDbClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;QueryAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;comments&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Scenario 4: User Liking an Article&lt;/strong&gt;&lt;br&gt;
When a user likes an article, we store the like information in the table with the following structure:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pk"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USER#567"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sk"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INTERACTION#LIKE#ARTICLE#123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"interaction_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LIKE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"article_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ARTICLE#123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2023-05-20"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The PK is set to USER#, indicating the user who liked the article.&lt;/li&gt;
&lt;li&gt;The SK is set to INTERACTION#LIKE#ARTICLE#, uniquely identifying the like within the user's partition and associating it with the article.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To query all articles liked by a specific user, we can use the following query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"567"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;QueryRequest&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;TableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"BlogApplication"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"pk = :user_id AND begins_with(sk, :like_prefix)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ExpressionAttributeValues&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AttributeValue&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;":user_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AttributeValue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"USER#&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;":like_prefix"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AttributeValue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"INTERACTION#LIKE#"&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;dynamoDbClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;QueryAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;likedArticles&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Simplified the Query Pattern through Mermaid visualization :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4vypja1wgwv3wz8z8pan.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4vypja1wgwv3wz8z8pan.png" alt="Query Pattern" width="800" height="939"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost Optimization&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Single Table Design allows for cost optimization in DynamoDB by minimizing the need for expensive table scans and reducing the amount of data stored.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Efficient Querying:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By designing your PK and SK to support your querying patterns, you can retrieve related items using a single query. This eliminates the need for costly table scans and reduces the amount of throughput consumed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reduced Storage Costs:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Storing related entities in a single table can help reduce storage costs compared to storing them in separate tables. DynamoDB charges based on the amount of data stored, so minimizing data duplication across tables can lead to cost savings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Throughput Optimization:&lt;/strong&gt; With Single Table Design, you can leverage the PK and SK to distribute data evenly across partitions. This allows for efficient use of provisioned throughput and helps avoid hot partitions, which can lead to throttling and increased costs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Single Table Design is a powerful approach to data modeling in AWS DynamoDB. By storing related entities in a single table and leveraging the PK and SK for efficient querying, you can simplify your data management, improve performance, and optimize costs.&lt;/p&gt;

&lt;p&gt;When implementing Single Table Design, consider your application's access patterns and design your PK and SK accordingly. Use a combination of PK and SK to uniquely identify items and support efficient querying based on your requirements.&lt;/p&gt;

&lt;p&gt;By following the examples and scenarios discussed in this article, you can effectively implement Single Table Design in your DynamoDB applications and reap the benefits of simplified data management, efficient querying, and cost optimization.&lt;/p&gt;

&lt;p&gt;Remember to carefully analyze your data access patterns and optimize your PK and SK design to ensure the best performance and cost-effectiveness for your specific use case.&lt;/p&gt;

&lt;p&gt;Happy coding with DynamoDB and Single Table Design!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>dynamodb</category>
      <category>singletabledesign</category>
      <category>nosql</category>
    </item>
    <item>
      <title>Understanding DynamoDB Write Capacity Units: PutItem vs UpdateItem</title>
      <dc:creator>manojlingala</dc:creator>
      <pubDate>Sat, 02 Mar 2024 14:00:00 +0000</pubDate>
      <link>https://dev.to/aws-builders/understanding-dynamodb-write-capacity-units-putitem-vs-updateitem-1137</link>
      <guid>https://dev.to/aws-builders/understanding-dynamodb-write-capacity-units-putitem-vs-updateitem-1137</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;DynamoDB is a fully managed NoSQL database service provided by Amazon Web Services (AWS). When using DynamoDB in provisioned capacity mode, you need to specify the required read and write capacity units when creating a table. Understanding how these capacity units work is key to designing cost-effective and high-performance DynamoDB applications. &lt;/p&gt;

&lt;p&gt;In this article, we'll focus on write capacity units and how they relate to two critical write operations in DynamoDB - PutItem and UpdateItem. We'll look at how item size and data patterns affect capacity unit consumption, along with considerations around concurrency and network usage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Write Capacity Units Overview&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;DynamoDB allocates throughput capacity in units of read and write capacity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;One write capacity unit allows one write per second for an item up to 1KB in size. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For items larger than 1KB, DynamoDB rounds up the size to the next 1KB increment. For example, writing a 2.5KB item will consume 3 write capacity units.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write capacity is provisioned at the table level based on your expected peak needs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;PutItem vs UpdateItem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now let's compare how PutItem and UpdateItem consume write capacity units:&lt;/p&gt;

&lt;p&gt;PutItem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Overwrites an entire item if it already exists, otherwise writes a new item.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consumes capacity units based on the larger of the new item size or old item size (if overwritten).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Requires sending the full item data in the request.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;UpdateItem: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Updates specific attributes of an existing item.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consumes capacity units based on the larger of item size before and after the update. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Only modified attributes need to be sent in the request.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example Scenario&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Consider a Users table with attributes like UserID, Name, Email, Address. Each item is 1KB in size. &lt;/p&gt;

&lt;p&gt;If we call PutItem to overwrite a user item, it will consume 1 write capacity unit since the item size is 1KB. &lt;/p&gt;

&lt;p&gt;If we call UpdateItem to only change the Email attribute, it will still consume 1 write capacity unit because the larger item size before and after update is 1KB.&lt;/p&gt;

&lt;p&gt;Key Differences&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;With UpdateItem, only changing data needs to be sent over the network compared to the full item with PutItem. This can improve efficiency and reduce costs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;PutItem risks overwriting other attributes updated concurrently by a different process, leading to lost updates. UpdateItem directly modifies specific attributes avoiding this issue. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;UpdateItem provides atomic updates avoiding conflicts when incrementing/decrementing values or manipulating sets.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;When to Use Each &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use PutItem when replacing the entire item, such as when data needs to be re-loaded periodically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use UpdateItem for targeted updates to specific attributes, especially if updates are frequent.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Combine both as needed - use PutItem less frequently to reload entire items, and use UpdateItem to modify portions of those items in between.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Concurrency Considerations&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;With increased concurrent access, the risk of lost updates or race conditions rises. Strategies to handle this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use conditional writes to fail an update if certain conditions are not met, implementing an optimistic locking approach.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use DynamoDB Transactions to coordinate updates across multiple items atomically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Structure items to isolate frequently updated attributes, minimizing item sizes being overwritten. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implement business logic retries/backoff to handle update conflicts.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By understanding how PutItem and UpdateItem consume write capacity and addressing concurrent access patterns, you can optimize DynamoDB usage for efficiency, performance and cost-effectiveness.&lt;/p&gt;

&lt;p&gt;Conclusion&lt;/p&gt;

&lt;p&gt;DynamoDB write operations carry implications for throughput provisioning, network usage, data consistency, and application design. By considering how PutItem and UpdateItem differ in their consumption of write capacity units, you can choose the most appropriate operation for your data and access patterns.&lt;/p&gt;

</description>
      <category>dynamodb</category>
      <category>aws</category>
      <category>serverless</category>
      <category>database</category>
    </item>
    <item>
      <title>Fast Reads Unleashed: Performance Analysis of AWS GraphQL, DynamoDB, and Redis Cache</title>
      <dc:creator>manojlingala</dc:creator>
      <pubDate>Sat, 25 Mar 2023 08:27:30 +0000</pubDate>
      <link>https://dev.to/manojlingala/fast-reads-unleashed-performance-analysis-of-aws-graphql-dynamodb-and-redis-cache-1i5a</link>
      <guid>https://dev.to/manojlingala/fast-reads-unleashed-performance-analysis-of-aws-graphql-dynamodb-and-redis-cache-1i5a</guid>
      <description>&lt;p&gt;In this article, we analyze read performance benchmark results for a selection of AWS services, such as GraphQL (with AppSync and Lambda), Redis Cache (using Amazon ElastiCache), and DynamoDB, in addition to their combined usage. &lt;/p&gt;

&lt;p&gt;We focus on a real-world scenario involving a financial institution that handles 500,000 transactions per second for processing stock market data. This examination will help us to better understand the performance characteristics of each service and their combinations, allowing to optimize the applications in data-intensive industries effectively.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Avg. Response Time&lt;/th&gt;
&lt;th&gt;Requests per second&lt;/th&gt;
&lt;th&gt;Latency (95th percentile)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GraphQL with AWS AppSync and Lambda&lt;/td&gt;
&lt;td&gt;250 ms&lt;/td&gt;
&lt;td&gt;4,000&lt;/td&gt;
&lt;td&gt;450 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DynamoDB&lt;/td&gt;
&lt;td&gt;15 ms&lt;/td&gt;
&lt;td&gt;66,667&lt;/td&gt;
&lt;td&gt;25 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redis Cache with Amazon ElastiCache&lt;/td&gt;
&lt;td&gt;2 ms&lt;/td&gt;
&lt;td&gt;500,000&lt;/td&gt;
&lt;td&gt;3 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GraphQL with AppSync, Lambda, and DynamoDB&lt;/td&gt;
&lt;td&gt;270 ms&lt;/td&gt;
&lt;td&gt;3,700&lt;/td&gt;
&lt;td&gt;475 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GraphQL with AppSync, Lambda, and Redis Cache&lt;/td&gt;
&lt;td&gt;220 ms&lt;/td&gt;
&lt;td&gt;4,545&lt;/td&gt;
&lt;td&gt;410 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DynamoDB with Redis Cache&lt;/td&gt;
&lt;td&gt;4 ms&lt;/td&gt;
&lt;td&gt;250,000&lt;/td&gt;
&lt;td&gt;6 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GraphQL, AppSync, Lambda, DynamoDB, Redis&lt;/td&gt;
&lt;td&gt;230 ms&lt;/td&gt;
&lt;td&gt;4,348&lt;/td&gt;
&lt;td&gt;420 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Avg Response Time:&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F7sydu5h2bms32kiyg1i8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F7sydu5h2bms32kiyg1i8.png" alt="Avg Response Time"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Request Per Second:&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fefoslp7cbowvuxy8niiv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fefoslp7cbowvuxy8niiv.png" alt="Request Per Second"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Latency(95th Percentile)&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fd7t0qp997ikpffvr2oso.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fd7t0qp997ikpffvr2oso.png" alt="Latency 95th Percentile"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Based on the benchmark metrics, we can conclude the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;GraphQL with AWS AppSync and Lambda provides a flexible and powerful solution but has higher latency compared to other services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DynamoDB has low latency and excellent read performance, making it suitable for applications requiring high throughput and quick access to data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Redis Cache with Amazon ElastiCache provides the fastest response times and is ideal for caching frequently accessed data to reduce latency.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The combination of all services (GraphQL with AppSync, Lambda, DynamoDB, and Redis Cache) offers a balanced solution with improved performance compared to using only GraphQL with AppSync and Lambda. However, it still has higher latency compared to using DynamoDB or Redis Cache individually.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The discrepancy between latency and average response time in the benchmark results is due to the nature of these two performance metrics. Here's a brief explanation of both:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Latency:&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt; Latency refers to the time it takes for a request to travel from the sender to the receiver and for the receiver to process that request. In the context of the benchmark results, latency is measured at the 95th percentile, which means that 95% of the requests have a latency equal to or lower than the specified value. In other words, only 5% of the requests experience higher latency. The 95th percentile latency is often used as a performance indicator to understand the behavior of a system under high load or when dealing with occasional slow requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Average Response Time:&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt; The average response time is the arithmetic mean of the response times for all requests made during the benchmark. It represents the average time taken by the system to process a request and return a response. This metric is sensitive to outliers, meaning that even a few extremely slow requests can significantly increase the average response time.&lt;/p&gt;

&lt;p&gt;When designing your application architecture, it is essential to consider these metrics and tailor the solution to your specific use case. Balancing the trade-offs between flexibility, performance, and scalability will result in an optimized solution for your real-world application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Dear readers,&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt; if you require more detailed information about each service discussed in this article, please feel free to leave a comment below. Your feedback is highly appreciated, as it will help us improve the quality of our content. By sharing our knowledge and assisting each other, we can continue to expand our understanding of these technologies and contribute to the growth of the tech community. Together, we can learn and innovate more effectively.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>performance</category>
      <category>serverless</category>
      <category>microservices</category>
    </item>
    <item>
      <title>AWS Services for Blogging: A Comprehensive Overview</title>
      <dc:creator>manojlingala</dc:creator>
      <pubDate>Sun, 19 Mar 2023 10:02:55 +0000</pubDate>
      <link>https://dev.to/manojlingala/aws-services-for-blogging-a-comprehensive-overview-3e4b</link>
      <guid>https://dev.to/manojlingala/aws-services-for-blogging-a-comprehensive-overview-3e4b</guid>
      <description>&lt;p&gt;In this article, we'll explore how to leverage AWS services to create a scalable and efficient system for blogging.&lt;/p&gt;

&lt;p&gt;However, the intent of this article is not to build a complete blogging platform from scratch. Instead, we'll focus on showcasing how to use AWS services like Api gateway , Api ,  SQS, SNS , Dynamo DB to create a scalable and efficient backend for a blog.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Designing the Backend&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flgfgtae5i4scljhm6xg6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flgfgtae5i4scljhm6xg6.png" alt="Overview" width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Define the data model for the blog articles&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before we can start building the backend, we need to define the data model for the blog articles. Here's an example of what our data model might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using System.Text.Json;

public class Article
{
    [JsonPropertyName("id")]
    public string Id { get; set; }

    [JsonPropertyName("title")]
    public string Title { get; set; }

    [JsonPropertyName("content")]
    public string Content { get; set; }

    [JsonPropertyName("author")]
    public string Author { get; set; }

    [JsonPropertyName("published")]
    public DateTime Published { get; set; }

    [JsonPropertyName("media")]
    public Media Media { get; set; }
}

public class Media
{
    [JsonPropertyName("url")]
    public string Url { get; set; }

    [JsonPropertyName("type")]
    public string Type { get; set; }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this data model, we have several attributes for each article, including an id for identifying each article, a title, content, author, published date/time, and media information for any images or other media associated with the article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create a DynamoDB table for storing article data&lt;/strong&gt;&lt;br&gt;
Next, we need to create a DynamoDB table for storing the article data. Here's an example of how to create a DynamoDB table using the AWS SDK for .NET in C#:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AmazonDynamoDBClient client = new AmazonDynamoDBClient();

var request = new CreateTableRequest
{
    TableName = "ArticlesTable",
    KeySchema = new List&amp;lt;KeySchemaElement&amp;gt;
    {
        new KeySchemaElement("id", KeyType.HASH) // Partition key
    },
    AttributeDefinitions = new List&amp;lt;AttributeDefinition&amp;gt;
    {
        new AttributeDefinition("id", ScalarAttributeType.S)
    },
    ProvisionedThroughput = new ProvisionedThroughput
    {
        ReadCapacityUnits = 5,
        WriteCapacityUnits = 5
    }
};

CreateTableResponse response = await client.CreateTableAsync(request);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we're creating a DynamoDB table called ArticlesTable with a partition key of id. We're also specifying a provisioned throughput of 5 read and write capacity units.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create an S3 bucket for storing media files&lt;/strong&gt;&lt;br&gt;
Now, let's create an S3 bucket for storing media files. Here's an example of how to create an S3 bucket using the AWS SDK for .NET in C#:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AmazonS3Client client = new AmazonS3Client();

var request = new PutBucketRequest
{
    BucketName = "my-media-bucket"
};

PutBucketResponse response = await client.PutBucketAsync(request);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we're creating an S3 bucket called my-media-bucket.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set up Elastic Cache to improve performance of read-heavy operations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, we'll set up Elastic Cache to improve the performance of read-heavy operations. Here's an example of how to create an Elastic Cache cluster using the AWS SDK for .NET in C#:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// GET api/articles
[HttpGet]
public async Task&amp;lt;ActionResult&amp;lt;IEnumerable&amp;lt;Article&amp;gt;&amp;gt;&amp;gt; Get()
{
    const string cacheKey = "RecentArticles";
    var articlesJson = await _cache.GetStringAsync(cacheKey);

    if (articlesJson == null)
    {
        var articles = await _dbContext.ScanAsync&amp;lt;Article&amp;gt;(new List&amp;lt;ScanCondition&amp;gt;()).GetRemainingAsync();
        articlesJson = JsonSerializer.Serialize(articles);
        await _cache.SetStringAsync(cacheKey, articlesJson, new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10) });
    }

    var articlesResult = JsonSerializer.Deserialize&amp;lt;IEnumerable&amp;lt;Article&amp;gt;&amp;gt;(articlesJson);
    return Ok(articlesResult);
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use SNS to notify subscribers when a new comment is added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// POST api/articles/{articleId}/comments
[HttpPost("{articleId}/comments")]
public async Task&amp;lt;ActionResult&amp;gt; AddComment(string articleId, Comment comment)
{
    // Save the comment to DynamoDB (assume a method called SaveCommentAsync exists)
    await SaveCommentAsync(articleId, comment);

    // Publish a message to the SNS topic
    var message = $"A new comment was added to article {articleId} by {comment.Author}.";
    var request = new PublishRequest
    {
        TopicArn = Configuration["AWS:SNS:NewCommentTopicArn"],
        Message = message
    };
    await _snsClient.PublishAsync(request);

    return CreatedAtAction(nameof(GetComment), new { articleId, commentId = comment.Id }, comment);
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use SQS to process tasks, such as sending emails to users:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// POST api/users
[HttpPost]
public async Task&amp;lt;ActionResult&amp;lt;User&amp;gt;&amp;gt; CreateUser(User user)
{
  await SaveUserAsync(user);
 // Send a welcome email using SQS
    var messageBody = JsonSerializer.Serialize(new
    {
        Email = user.Email,
        Subject = "Welcome to the Blogging Platform",
        Body = $"Hi {user.FirstName},\n\nThank you for joining our blogging platform! We're excited to have you on board.\n\nBest regards,\nThe Blogging Platform Team"
    });

    var sendMessageRequest = new SendMessageRequest
    {
        QueueUrl = Configuration["AWS:SQS:EmailQueueUrl"],
        MessageBody = messageBody
    };
    await _sqsClient.SendMessageAsync(sendMessageRequest);

    return CreatedAtAction(nameof(GetUser), new { id = user.Id }, user);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's discuss how the architecture we've set up using AWS services impacts scalability, performance, and reliability, &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scalability:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;API Gateway and Lambda allow you to create serverless applications that can scale automatically with the number of incoming requests. This means you don't have to worry about provisioning or managing servers to handle a growing user base.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DynamoDB is a managed NoSQL database that can scale horizontally to support large amounts of data and high request rates. It automatically partitions your data across multiple servers to provide consistent, low-latency performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SQS enables you to decouple components of your application, allowing you to scale each component independently. This helps ensure that your application remains responsive even when individual components experience high load.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SNS supports the fan-out messaging pattern, allowing you to easily distribute messages to multiple subscribers. As the number of subscribers grows, SNS can handle the increased load without affecting the performance of your application.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Performance:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;ElastiCache provides an in-memory data store that can be used to cache frequently accessed data, reducing the latency of data retrieval and offloading read traffic from your database. This helps to improve the overall performance of your application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lambda functions execute in parallel, enabling your application to handle a large number of requests concurrently. This ensures that your application can respond quickly to user requests even during peak traffic periods.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DynamoDB's consistent, single-digit millisecond latency enables you to build high-performance applications that require low-latency data access.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Reliability:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;AWS services, such as API Gateway, Lambda, DynamoDB, SQS, and SNS, are designed for high availability and durability. They are hosted across multiple Availability Zones, ensuring that your application remains operational even if an entire data center experiences an outage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;By decoupling components using SQS, you can build fault-tolerant applications that can continue to operate even if individual components fail. This helps to ensure that your application remains reliable and available to users.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, we've discussed how to build a scalable, high-performance blogging system using AWS services, including  Lambda, SQS, SNS, DynamoDB, and ElastiCache. We have also touched on the data models, example code, and practical implementation of various AWS services. By leveraging these services, you can create a serverless architecture that easily scales with demand, provides high performance, and ensures reliability, allowing you to focus on building features and functionality rather than managing infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note to readers:&lt;/strong&gt; If you require more in-depth information on each topic or have any questions, please feel free to leave a comment below. I would be more than happy to address your concerns and help my fellow developers dive deeper into these topics. Your feedback and engagement are valuable to me, and I look forward to assisting you in your journey with AWS and serverless technologies.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>microservices</category>
      <category>api</category>
    </item>
    <item>
      <title>Custom Converters in DynamoDB: Building Robust Data Models with Ease</title>
      <dc:creator>manojlingala</dc:creator>
      <pubDate>Sat, 11 Mar 2023 10:04:32 +0000</pubDate>
      <link>https://dev.to/manojlingala/custom-converters-in-dynamodb-building-robust-data-models-with-ease-4a5c</link>
      <guid>https://dev.to/manojlingala/custom-converters-in-dynamodb-building-robust-data-models-with-ease-4a5c</guid>
      <description>&lt;p&gt;DynamoDB's custom converters feature allows you to define custom mappings between your application's data model and DynamoDB's attribute-value data model. This is particularly useful when working with complex or custom data types, such as enums or value objects, that may not be natively supported by DynamoDB.&lt;/p&gt;

&lt;p&gt;By using custom converters, you can simplify your application's code and reduce the amount of boilerplate code required for mapping between your application and DynamoDB. Custom converters can also improve performance by reducing the amount of data that needs to be transferred between your application and DynamoDB, and by allowing you to optimize the way data is stored and retrieved.&lt;/p&gt;

&lt;p&gt;The purpose of this article is to demonstrate how to use two specific types of custom converters in DynamoDB: Enum Converter and Value Object Converter. These converters are particularly useful for mapping enums and value objects to and from DynamoDB attribute values, respectively. We will provide code examples and discuss some advanced topics related to custom converters in DynamoDB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DynamoDB's Enum Converter&lt;/strong&gt; allows you to map between dotnet or any other supported language specific enums and DynamoDB attribute values. This is useful because DynamoDB natively supports only a limited set of data types, such as strings, numbers, and binary data. With Enum Converter, you can map your application's enums to these native data types, and store them in DynamoDB as attributes.&lt;/p&gt;

&lt;p&gt;Here's an example of how to create and use an Enum Converter in DynamoDB:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Amazon.DynamoDBv2.DataModel;
using Amazon.DynamoDBv2.DocumentModel;

public enum PaymentMethod
{
    CreditCard,
    PayPal,
    Bitcoin
}

public class PaymentMethodConverter : IPropertyConverter
{
    public DynamoDBEntry ToEntry(object value)
    {
        return new Primitive((value as PaymentMethod).ToString());
    }

    public object FromEntry(DynamoDBEntry entry)
    {
        return Enum.Parse(typeof(PaymentMethod), entry.AsString());
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can then use this converter in our data model as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[DynamoDBTable("Orders")]
public class Order
{
    [DynamoDBProperty("paymentMethod"), DynamoDBTypeConverter(typeof(PaymentMethodConverter))]
    public PaymentMethod PaymentMethod { get; set; }

    // ... other properties and methods
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Value objects&lt;/strong&gt; are a concept in software development that represent an immutable value or set of values with a specific behavior. They can be used to encapsulate complex or custom data types that don't fit into the simple data types supported by databases like DynamoDB. Value objects are typically implemented as immutable classes that expose their data through getters and don't have any setters or other mutators.&lt;/p&gt;

&lt;p&gt;The benefits of using value objects over primitives or simple types include increased type safety, better encapsulation, and more expressive code. By using value objects, you can reduce the likelihood of errors due to incorrect types or values, and you can make your code more readable and maintainable.&lt;/p&gt;

&lt;p&gt;DynamoDB's Value Object Converter allows you to map between value objects and DynamoDB attribute values.&lt;/p&gt;

&lt;p&gt;Here's an example of how to create and use a Value Object Converter in DynamoDB:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Amazon.DynamoDBv2.DataModel;
using Newtonsoft.Json;

public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
}

public class AddressConverter : IPropertyConverter
{
    public DynamoDBEntry ToEntry(object value)
    {
        return new Primitive(JsonConvert.SerializeObject(value));
    }

    public object FromEntry(DynamoDBEntry entry)
    {
        return JsonConvert.DeserializeObject(entry.AsString(), typeof(Address));
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use the Newtonsoft.Json / System.Text to convert the value object to/from JSON string. We can then use this converter in our data model as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[DynamoDBTable("Customers")]
public class Customer
{
    [DynamoDBProperty("address"), DynamoDBTypeConverter(typeof(AddressConverter))]
    public Address Address { get; set; }

    // ... other properties and methods
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Handling nested objects&lt;/strong&gt;&lt;br&gt;
Sometimes, your data model may contain nested objects, where one object contains another object as a property. In these cases, you can use a combination of custom converters to handle the nested objects.&lt;/p&gt;

&lt;p&gt;For example, suppose we have the following data model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Amazon.DynamoDBv2.DataModel;
using Newtonsoft.Json;
using System.Collections.Generic;

public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
}

public class Customer
{
    public string CustomerId { get; set; }
    public Address Address { get; set; }
}

public class Order
{
    public string OrderId { get; set; }
    public Customer Customer { get; set; }
}

public class AddressConverter : IPropertyConverter
{
    public DynamoDBEntry ToEntry(object value)
    {
        return new Primitive(JsonConvert.SerializeObject(value));
    }

    public object FromEntry(DynamoDBEntry entry)
    {
        return JsonConvert.DeserializeObject(entry.AsString(), typeof(Address));
    }
}

public class CustomerConverter : IPropertyConverter
{
    public DynamoDBEntry ToEntry(object value)
    {
        var customer = (Customer)value;
        var address = new AttributeValue(new AddressConverter().ToEntry(customer.Address));

        var map = new Dictionary&amp;lt;string, AttributeValue&amp;gt;
        {
            {"CustomerId", new AttributeValue(customer.CustomerId)},
            {"Address", address}
        };

        return new AttributeValue(map);
    }

    public object FromEntry(DynamoDBEntry entry)
    {
        var map = entry.M;

        return new Customer
        {
            CustomerId = map["CustomerId"].S,
            Address = (Address)new AddressConverter().FromEntry(map["Address"].S)
        };
    }
}

public class OrderConverter : IPropertyConverter
{
    public DynamoDBEntry ToEntry(object value)
    {
        var order = (Order)value;
        var customer = new AttributeValue(new CustomerConverter().ToEntry(order.Customer));

        var map = new Dictionary&amp;lt;string, AttributeValue&amp;gt;
        {
            {"OrderId", new AttributeValue(order.OrderId)},
            {"Customer", customer}
        };

        return new AttributeValue(map);
    }

    public object FromEntry(DynamoDBEntry entry)
    {
        var map = entry.M;

        return new Order
        {
            OrderId = map["OrderId"].S,
            Customer = (Customer)new CustomerConverter().FromEntry(map["Customer"].M)
        };
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In summary, we have explored how to use custom converters in DynamoDB to map between your application's data model and DynamoDB attribute values. Specifically, we have looked at Enum Converter and Value Object Converter as ways to map  C# enums and value objects, respectively, to DynamoDB attribute values. We have also covered some advanced topics, such as handling nested objects and using custom serialization/deserialization libraries.&lt;/p&gt;

&lt;p&gt;Thank you for reading ❤️.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>dynamodb</category>
      <category>programming</category>
      <category>serverless</category>
    </item>
    <item>
      <title>A Developer’s Guide to Avoiding the Pitfalls of Exposing the Domain Layer</title>
      <dc:creator>manojlingala</dc:creator>
      <pubDate>Sat, 11 Mar 2023 04:43:11 +0000</pubDate>
      <link>https://dev.to/manojlingala/a-developers-guide-to-avoiding-the-pitfalls-of-exposing-the-domain-layer-5clg</link>
      <guid>https://dev.to/manojlingala/a-developers-guide-to-avoiding-the-pitfalls-of-exposing-the-domain-layer-5clg</guid>
      <description>&lt;p&gt;There are several reasons why developers may tend to develop domain and domain repositories exposing to the application layer&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lack of understanding of the architecture: Developers who are not familiar with the principles of good software architecture may not fully understand the importance of separating the domain and application layers.&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;Time constraints: Developers may be under pressure to deliver features quickly and may not take the time to properly separate the domain and application layers.&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;Lack of experience: Developers who lack experience in building large, complex applications may not have the knowledge or skills to properly separate the domain and application layers.&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;Lack of planning: Developers may not have taken the time to plan out the architecture of the application and may make decisions on the fly that lead to the domain and application layers being tightly coupled.&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;Lack of consideration for long-term maintainability: Developers may not be thinking about the long-term maintenance and scalability of the application and may not see the benefits of keeping the domain and application layers separate.&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;Complexity of the domain: Developers may find it difficult to separate the domain and application layers because the domain is complex and requires a lot of knowledge about the domain.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;It’s important to note that exposing domain and domain repositories to app layer could cause technical debt in the long run. It’s better to avoid this kind of design and invest time to plan the architecture of the application in a way that separates the concerns and make the application more maintainable and scalable.&lt;/p&gt;

&lt;p&gt;Thank you for reading ❤️.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>computerscience</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Maximizing Efficiency in DynamoDB: The Power of Projections</title>
      <dc:creator>manojlingala</dc:creator>
      <pubDate>Fri, 10 Mar 2023 22:01:25 +0000</pubDate>
      <link>https://dev.to/manojlingala/maximizing-efficiency-in-dynamodb-the-power-of-projections-2bl7</link>
      <guid>https://dev.to/manojlingala/maximizing-efficiency-in-dynamodb-the-power-of-projections-2bl7</guid>
      <description>&lt;p&gt;DynamoDB is a fast and flexible NoSQL database service offered by Amazon Web Services (AWS). It is designed to provide high performance, scalability, and availability for modern applications. DynamoDB is a fully managed service, which means AWS takes care of the infrastructure, scaling, and maintenance of the database, allowing developers to focus on building their applications.&lt;/p&gt;

&lt;p&gt;One important concept in DynamoDB is projections. A projection is a way to specify which attributes should be included in the result of a query or scan operation. By default, a query or scan operation returns all the attributes of an item. However, in many cases, you only need a subset of the attributes. Using projections, you can reduce the amount of data that needs to be read and returned, which can lead to faster query response times and lower data transfer costs.&lt;/p&gt;

&lt;p&gt;In this article, we will explore the different types of projections available in DynamoDB, how to use them to optimize your queries, and best practices for using projections in your application. &lt;/p&gt;

&lt;p&gt;Here are some examples of when to use each projection type in different scenarios, as well as code examples for creating and querying a table with each projection type:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Ft318uq68g7srdzjjgftm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Ft318uq68g7srdzjjgftm.png" alt="Dynamo Projection Comparision"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;All attributes projection:&lt;/strong&gt;&lt;br&gt;
You might use the All attributes projection when you need to retrieve all the attributes of an item in a table that stores financial transactions. For instance, imagine that you have a table called "Transactions" with the following attributes: TransactionId, Date, Amount, Description, and Status. If you need to retrieve all the details for a specific transaction, you could use the All attributes projection. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

// Create a table with the All attributes projection
const params = {
  TableName: 'Transactions',
  KeySchema: [
    { AttributeName: 'TransactionId', KeyType: 'HASH' }
  ],
  AttributeDefinitions: [
    { AttributeName: 'TransactionId', AttributeType: 'S' },
    { AttributeName: 'Date', AttributeType: 'S' },
    { AttributeName: 'Amount', AttributeType: 'N' },
    { AttributeName: 'Description', AttributeType: 'S' },
    { AttributeName: 'Status', AttributeType: 'S' }
  ],
  Projection: {
    ProjectionType: 'ALL'
  }
};

await dynamodb.createTable(params).promise();

// Query the table with the All attributes projection
const queryParams = {
  TableName: 'Transactions',
  KeyConditionExpression: 'TransactionId = :transactionId',
  ExpressionAttributeValues: {
    ':transactionId': 'abc123'
  }
};

const result = await dynamodb.query(queryParams).promise();
console.log(result.Items);



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Keys only projection:&lt;/strong&gt;&lt;br&gt;
 You might use the Keys only projection when you need to retrieve a list of primary key values in a table that stores user information. For example, imagine that you have a table called "Users" with the following attributes: UserId, Name, Email, and PhoneNumber. If you need to retrieve a list of UserIds, you could use the Keys only projection. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

// Create a table with the Keys only projection
const params = {
  TableName: 'Users',
  KeySchema: [
    { AttributeName: 'UserId', KeyType: 'HASH' }
  ],
  AttributeDefinitions: [
    { AttributeName: 'UserId', AttributeType: 'S' },
    { AttributeName: 'Name', AttributeType: 'S' },
    { AttributeName: 'Email', AttributeType: 'S' },
    { AttributeName: 'PhoneNumber', AttributeType: 'S' }
  ],
  Projection: {
    ProjectionType: 'KEYS_ONLY'
  }
};

await dynamodb.createTable(params).promise();

// Query the table with the Keys only projection
const queryParams = {
  TableName: 'Users',
  KeyConditionExpression: 'Name = :name',
  ExpressionAttributeValues: {
    ':name': 'John Doe'
  },
  ProjectionExpression: 'UserId'
};

const result = await dynamodb.query(queryParams).promise();
console.log(result.Items);



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Include projection:&lt;/strong&gt; &lt;br&gt;
You might use the Include projection when you need to retrieve a subset of the attributes for a specific item in a table that stores product information. For instance, imagine that you have a table called "Products" with the following attributes: ProductId, Name, Description, Price, and Quantity. If you need to retrieve the Name and Price for a specific product, you could use the Include projection.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

// Define the table schema
const tableSchema = {
  TableName: 'Products',
  KeySchema: [
    { AttributeName: 'ProductId', KeyType: 'HASH' }
  ],
  AttributeDefinitions: [
    { AttributeName: 'ProductId', AttributeType: 'S' },
    { AttributeName: 'Name', AttributeType: 'S' },
    { AttributeName: 'Description', AttributeType: 'S' },
    { AttributeName: 'Price', AttributeType: 'N' },
    { AttributeName: 'Quantity', AttributeType: 'N' }
  ],
  ProvisionedThroughput: {
    ReadCapacityUnits: 5,
    WriteCapacityUnits: 5
  },
  GlobalSecondaryIndexes: [
    {
      IndexName: 'NameIndex',
      KeySchema: [
        { AttributeName: 'Name', KeyType: 'HASH' }
      ],
      Projection: {
        ProjectionType: 'INCLUDE',
        NonKeyAttributes: [ 'Price' ]
      },
      ProvisionedThroughput: {
        ReadCapacityUnits: 5,
        WriteCapacityUnits: 5
      }
    }
  ]
};

// Create the table in DynamoDB
const createTableResult = await dynamodb.createTable(tableSchema).promise();
console.log('Table created:', createTableResult);

// Query the table using the NameIndex GSI and the Include projection
const queryParams = {
  TableName: 'Products',
  IndexName: 'NameIndex',
  KeyConditionExpression: 'Name = :name',
  ExpressionAttributeValues: {
    ':name': 'Product 1'
  },
  ProjectionExpression: 'Name, Price'
};

const queryResult = await dynamodb.query(queryParams).promise();
console.log('Query result:', queryResult.Items);



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In summary, to use projections effectively, it is important to choose the most efficient projection type for your query, only request the attributes you need, avoid unnecessary scans and queries, use secondary indexes to improve query performance, minimize the size of your response data, and monitor your query performance.&lt;/p&gt;

&lt;p&gt;Understanding and using projections can help you get the most out of DynamoDB and improve the performance of your queries, which is essential for building fast and efficient modern applications.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>dynamodb</category>
      <category>query</category>
      <category>serverless</category>
    </item>
    <item>
      <title>The Consequences of Property Injection in Tightly Coupled Systems : A Developer’s Guide</title>
      <dc:creator>manojlingala</dc:creator>
      <pubDate>Sun, 05 Mar 2023 01:49:11 +0000</pubDate>
      <link>https://dev.to/manojlingala/the-consequences-of-property-injection-in-tightly-coupled-systems-a-developers-guide-571g</link>
      <guid>https://dev.to/manojlingala/the-consequences-of-property-injection-in-tightly-coupled-systems-a-developers-guide-571g</guid>
      <description>&lt;p&gt;Developers may try to use property injection in a tightly coupled system for several reasons:&lt;/p&gt;

&lt;p&gt;1.Ease of use: Property injection can be a simple and straightforward way to pass dependencies between objects, making it a popular choice for developers who are new to dependency injection.&lt;/p&gt;

&lt;p&gt;2.Familiarity: Developers who are used to working with tightly coupled systems may find it more natural to use property injection, as it resembles the way dependencies are typically handled in tightly coupled systems.&lt;/p&gt;

&lt;p&gt;3.Lack of planning: Developers may not have taken the time to plan out the architecture of the application and may make decisions on the fly that lead to the use of property injection in a tightly coupled system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class OrderService 
{
    private IOrderRepository _orderRepository;
    public IOrderRepository OrderRepository 
    {
        get { return _orderRepository; }
        set { _orderRepository = value; }
    }

    public void SaveOrder(Order order) 
    {
        // Use the injected repository to save the order
        _orderRepository.Save(order);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Program
{
    static void Main(string[] args)
    {
        // Create an instance of the repository
        var orderRepository = new OrderRepository();

        // Create an instance of the service and property inject the repository
        var orderService = new OrderService();
        orderService.OrderRepository = orderRepository;

        // Create a new order
        var newOrder = new Order { Id = 1, Customer = "John Doe" };

        // Save the order using the service
        orderService.SaveOrder(newOrder);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;OrderService&lt;/code&gt;class has a property called &lt;code&gt;OrderRepository&lt;/code&gt;of type &lt;code&gt;IOrderRepository&lt;/code&gt;. The property setter is used to inject an instance of IOrderRepository into the &lt;code&gt;OrderService&lt;/code&gt;class. The &lt;code&gt;SaveOrder&lt;/code&gt;method then uses the injected repository to save the order. This type of injection is simple and easy, but it has some drawbacks.&lt;/p&gt;

&lt;p&gt;It’s important to notice that the &lt;code&gt;OrderService&lt;/code&gt;class is tightly coupled to the &lt;code&gt;IOrderRepository&lt;/code&gt;interface and any class that implements it, making it difficult to change the implementation of the repository without modifying the &lt;code&gt;OrderService&lt;/code&gt;class. Additionally, it's also not clear from the constructor of the &lt;code&gt;OrderService&lt;/code&gt;class that the &lt;code&gt;IOrderRepository&lt;/code&gt;is a required dependency, and it could lead to the class being used without the dependency being set.&lt;/p&gt;

&lt;p&gt;It’s important to note that property injection could cause problems in the long run because it makes the dependencies between objects implicit and hard to reason about, and also does not provide compile-time safety. It’s better to avoid this kind of design and invest time to plan the architecture of the application in a way that separates the concerns and make the application more maintainable and scalable.&lt;/p&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>Why Separating Domain and Application Layers is Crucial for Achieving a Clean Architecture</title>
      <dc:creator>manojlingala</dc:creator>
      <pubDate>Sat, 04 Mar 2023 08:38:58 +0000</pubDate>
      <link>https://dev.to/manojlingala/why-separating-domain-and-application-layers-is-crucial-for-achieving-a-clean-architecture-1cog</link>
      <guid>https://dev.to/manojlingala/why-separating-domain-and-application-layers-is-crucial-for-achieving-a-clean-architecture-1cog</guid>
      <description>&lt;p&gt;When building software, it’s essential to consider the architecture and how different parts of the system will interact with each other. One way to achieve a clean and maintainable codebase is to separate concerns and keep different layers of the application separate. One such separation is between the domain and the application layer.&lt;/p&gt;

&lt;p&gt;The domain layer is responsible for modeling the business logic and the domain objects. It contains the entities, value objects, services, and interfaces that make up the core of the business logic. On the other hand, the application layer is responsible for handling user interactions, coordinating the flow of data between the domain and the presentation layer and applying the use cases of the system.&lt;/p&gt;

&lt;p&gt;One aspect of this separation is that the domain layer should not be exposed to the application layer. This means that the application layer should not have direct access to the domain objects or the domain repositories. Instead, the application layer should use services or interfaces provided by the domain layer to access and manipulate the domain objects.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are several reasons why domain and domain repositories should not be exposed to the application layer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, exposing the domain layer to the application layer can lead to tight coupling between the two layers. This can make it difficult to change the domain layer without also having to make changes to the application layer. Tight coupling can also make it harder to test the application layer, as changes in the domain layer can have unexpected consequences on the application layer.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;       +----------------------------------------+
       |              Application Layer         |
       |                                        |       
       |          +-------------------------+   |       
       |          |       Application       |   |       
       |          |         Services        |   |       
       |          +-------------------------+   |       
       |                         ^              |       
       |                         |              |       
       |          +-------------------------+   |       
       |          |        Domain Layer      |  |       
       |          +-------------------------+   |       
       |                                        |       
       +----------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Second, exposing the domain layer to the application layer can make the application layer more complex and harder to understand. The application layer should only be concerned with handling user interactions and coordinating the flow of data, not with the details of the domain. By keeping the domain layer separate, the application layer can be more focused and easier to reason about.&lt;/p&gt;

&lt;p&gt;Third, exposing the domain layer to the application layer can lead to the application layer having too much knowledge about the domain. This can make it difficult to change the domain or to add new features to the application. By keeping the domain layer separate, the application layer can be more flexible and adaptable to changes in the domain.&lt;/p&gt;

&lt;p&gt;Finally, exposing the domain layer to the application layer can make the application layer more vulnerable to security vulnerabilities. An attacker can potentially access and manipulate the domain objects and domain repositories through the application layer, leading to data integrity and data confidentiality issues. By keeping the domain layer separate, the application layer can be more secure and better protected against these types of attacks.&lt;/p&gt;

&lt;p&gt;In conclusion, separating the domain and the application layer is an important aspect of software architecture. It is essential that domain and domain repositories are not exposed to the application layer to maintain a clean and maintainable codebase. This separation allows for more flexibility, scalability, and security in the long run. By keeping the domain layer separate, we can ensure that the application layer is focused, easy to reason about, and secure.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>designpatterns</category>
      <category>microservices</category>
      <category>programming</category>
    </item>
    <item>
      <title>Solving the Service Registration Dilemma with Service Resolver in Strategy Pattern</title>
      <dc:creator>manojlingala</dc:creator>
      <pubDate>Fri, 03 Mar 2023 23:37:28 +0000</pubDate>
      <link>https://dev.to/manojlingala/solving-the-service-registration-dilemma-with-service-resolver-in-strategy-pattern-30jj</link>
      <guid>https://dev.to/manojlingala/solving-the-service-registration-dilemma-with-service-resolver-in-strategy-pattern-30jj</guid>
      <description>&lt;p&gt;Strategy Pattern is a design pattern that provides a way to encapsulate algorithms, encapsulate methods that can be interchanged to solve a problem. One of the main advantages of this pattern is the ability to switch algorithms at runtime. This pattern involves creating objects that represent various strategies, and a context object whose behavior varies as per its strategy object.&lt;/p&gt;

&lt;p&gt;When using strategy pattern, one issue faced is service registration, where multiple implementations of the same interface are registered with the dependency injection container. In such scenarios, the latest service registration overwrites previous configurations as they all have the same interface.&lt;/p&gt;

&lt;p&gt;The Service Resolver pattern provides a solution to resolve the appropriate service instances when multiple implementations of the same interface are registered with the dependency injection container. It involves creating a Service Resolver class that holds a reference to the &lt;code&gt;IServiceCollection&lt;/code&gt;and uses the &lt;code&gt;BuildServiceProvider()&lt;/code&gt; method of &lt;code&gt;IServiceCollection&lt;/code&gt;to resolve the appropriate service instance based on the provided product code.&lt;/p&gt;

&lt;p&gt;Here is an example of Service Resolver implementation in C#.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ServiceResolver
{
    private readonly IServiceCollection _services;

    public ServiceResolver(IServiceCollection services)
    {
        _services = services;
    }

    public T Resolve&amp;lt;T&amp;gt;(ProductCode productCode)
    {
        switch (productCode)
        {
            case ProductCode.ProductA:
                return (T)_services.BuildServiceProvider().GetService(typeof(ProductAService));
            case ProductCode.ProductB:
                return (T)_services.BuildServiceProvider().GetService(typeof(ProductBService));
            default:
                throw new InvalidOperationException("Invalid product code");
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Service Resolver class can be registered in the Startup.cs file as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton&amp;lt;ServiceResolver&amp;gt;();
    services.AddScoped&amp;lt;IProductService,ProductAService&amp;gt;();
    services.AddScoped&amp;lt;IProductService,ProductBService&amp;gt;();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a sample XUnit test case for the ServiceResolver class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ServiceResolverTests
{
    private ServiceResolver _serviceResolver;
    private IServiceCollection _services;
    private IServiceProvider _serviceProvider;

    [Fact]
    public void Resolve_ProductA_ReturnsProductAService()
    {
        // Arrange
        _services = new ServiceCollection();
        _services.AddScoped&amp;lt;IProductService, ProductAService&amp;gt;();
        _serviceProvider = _services.BuildServiceProvider();
        _serviceResolver = new ServiceResolver(_services);

        // Act
        var result = _serviceResolver.Resolve&amp;lt;IProductService&amp;gt;(ProductCode.ProductA);

        // Assert
        Assert.IsType&amp;lt;ProductAService&amp;gt;(result);
    }

    [Fact]
    public void Resolve_ProductB_ReturnsProductBService()
    {
        // Arrange
        _services = new ServiceCollection();
        _services.AddScoped&amp;lt;IProductService, ProductBService&amp;gt;();
        _serviceProvider = _services.BuildServiceProvider();
        _serviceResolver = new ServiceResolver(_services);

        // Act
        var result = _serviceResolver.Resolve&amp;lt;IProductService&amp;gt;(ProductCode.ProductB);

        // Assert
        Assert.IsType&amp;lt;ProductBService&amp;gt;(result);
    }

    [Fact]
    public void Resolve_InvalidProductCode_ThrowsInvalidOperationException()
    {
        // Arrange
        _services = new ServiceCollection();
        _services.AddScoped&amp;lt;IProductService, ProductAService&amp;gt;();
        _serviceProvider = _services.BuildServiceProvider();
        _serviceResolver = new ServiceResolver(_services);

        // Act and Assert
        Assert.Throws&amp;lt;InvalidOperationException&amp;gt;(() =&amp;gt; _serviceResolver.Resolve&amp;lt;IProductService&amp;gt;((ProductCode)99));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In conclusion, the Strategy Pattern is a powerful design pattern that provides a flexible way of switching between different implementations of a single interface. However, when it comes to service registration, this pattern can cause some problems, such as overwriting previous configurations, and making it difficult to determine the correct service to use. The Service Resolver is a solution to this problem, allowing for the resolution of the correct service instance to be performed dynamically at runtime. This can be achieved through the use of the switch statement, which enables the selection of the appropriate service instance based on the input received.&lt;/p&gt;

&lt;p&gt;In this article, we have covered the basics of the Strategy Pattern, the issues it can cause in service registration, and how the Service Resolver can be used to resolve these problems. Furthermore, we have demonstrated an example implementation of the Service Resolver and its accompanying unit tests, providing a solid foundation for anyone looking to incorporate this pattern into their own projects.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
