<?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>Forem: Coco</title>
    <description>The latest articles on Forem by Coco (@rrsai).</description>
    <link>https://forem.com/rrsai</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%2F676472%2F9ac32865-397c-4ef4-bc3f-1e5098563b90.jpeg</url>
      <title>Forem: Coco</title>
      <link>https://forem.com/rrsai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rrsai"/>
    <language>en</language>
    <item>
      <title>The Paradox of Simplicity and the Rise of Invisible Tech</title>
      <dc:creator>Coco</dc:creator>
      <pubDate>Sun, 23 Mar 2025 03:17:15 +0000</pubDate>
      <link>https://forem.com/rrsai/the-paradox-of-simplicity-and-the-rise-of-invisible-tech-2hcg</link>
      <guid>https://forem.com/rrsai/the-paradox-of-simplicity-and-the-rise-of-invisible-tech-2hcg</guid>
      <description>&lt;p&gt;Modern technology is supposed to make our lives easier, but sometimes it feels like it is actually making things inaccessible to those who need it most. Sometimes it hides the simple pleasures of life and distracts us from them. Modern tools demand a level of technical fluency that only engineers and enthusiasts will &lt;em&gt;comfortably&lt;/em&gt; navigate, leaving the rest of the world to either struggle or opt out entirely. &lt;/p&gt;

&lt;p&gt;But true innovation isn’t about adding complexity — it’s about making complexity invisible.&lt;/p&gt;

&lt;p&gt;Take ChatGPT as a positive example. On the surface, it’s just a text box. You type words in, and it responds. But behind that simple interface is an absurd amount of machinery—vast networks of servers, AI models layered on top of each other, content filtering, and more. It’s hyper-complex, yet completely accessible. This is part of why it has taken the world by storm. Anyone, regardless of their technical background, can verbally ask for a pie recipe and instantly get one, without needing to understand a single thing about LLMs or cloud computing or why a nuclear power plant needs to spin up to power OpenAI’s energy needs (see footnote 1).&lt;/p&gt;

&lt;p&gt;This is invisible tech—where complexity exists, but it never burdens the user. And this is where technology should be heading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serving the Revolution to Low-Tech Users
&lt;/h2&gt;

&lt;p&gt;Right now, technology is designed by engineers, for technophiles. Even when companies claim to focus on “user experience,” they’re usually just smoothing out the edges of already complex systems rather than rethinking how those systems could serve people with minimal technical literacy.  There is now a ton of opportunity to serve those people.&lt;/p&gt;

&lt;p&gt;Take my grandma, for instance. She doesn’t care about AWS Lambda, API Gateways, or microservices. She doesn’t need to know what Spotify is. What she cares about is getting the right information or response when she needs it. She would love to just ask her phone to deliver her a pizza and pay for it. She does not want to know about Domino’s new iOS pizza app, because that would require &lt;em&gt;knowing what an app is&lt;/em&gt;.&lt;br&gt;
In a way, I have to learn about tech and serverless solutions to enable her &lt;strong&gt;&lt;em&gt;not to have to&lt;/em&gt;&lt;/strong&gt;. I don’t want her to have to! Yet most tech solutions assume a level of digital fluency she—and millions of others—don’t have.&lt;/p&gt;

&lt;p&gt;If technology truly served people rather than just serving engineers’ impulse to tinker, we would see low-tech, low-barrier, high-impact interfaces—tools that feel as effortless as talking to another person. The best interfaces would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High fidelity – No clutter, no unnecessary features, just the essential functions&lt;/li&gt;
&lt;li&gt;Low complexity – No complex setup, no steep learning curves&lt;/li&gt;
&lt;li&gt;Low knowledge barrier – No manuals, no prerequisite skills needed&lt;/li&gt;
&lt;li&gt;High utility – Actually useful in real-world, everyday situations&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Role of AWS and Serverless in Invisible Tech
&lt;/h2&gt;

&lt;p&gt;The beauty of serverless computing is that it allows us to build high-powered applications with lightweight, accessible interfaces. AWS already provides many of the building blocks to create seamless, invisible tech experiences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amazon Lex &amp;amp; Polly – AI-driven voice interaction that can make services available through simple phone calls&lt;/li&gt;
&lt;li&gt;AWS Lambda – Event-driven, scalable backend logic without infrastructure concerns&lt;/li&gt;
&lt;li&gt;Amazon Connect – Cloud-based call centers that could act as automated helpers for people who struggle with traditional apps&lt;/li&gt;
&lt;li&gt;API Gateway &amp;amp; Step Functions – A way to chain together complex logic without forcing the user to navigate it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With these tools, we could build systems that let people interact with powerful tech using only voice commands, phone calls, or simple text input—no apps, no accounts, no friction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Invisible Tech Improvements for Underserved Communities
&lt;/h2&gt;

&lt;p&gt;Drawing from my recent experiences training as an EMT, I’ve encountered various individuals—particularly older adults, people battling substance use disorders, those managing pain, and those suffering from chronic conditions. Many of these individuals have minimal familiarity with complex technologies, yet their need for accessible, intuitive tech is deep.&lt;/p&gt;

&lt;p&gt;Imagine how invisible tech could make an impact in underserved communities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1. Accessibility-First Interfaces for Low-Sight Users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my local community, I’ve come across multiple individuals with sight accessibility issues. While I, as an engineer, can navigate complex user interfaces with multiple buttons, sliders, and options, these individuals struggle significantly with these designs. The tech world has made strides with voice-controlled tools like Amazon Alexa and Google Assistant, but there is room for improvement.&lt;/p&gt;

&lt;p&gt;Empowering tool: Imagine a purpose-built interface specifically designed for individuals with low or no sight. This could involve voice-activated and haptic feedback systems that guide the user through an app’s functions without requiring any visual interaction. By leveraging AWS Lex for voice recognition, we could offer an interface where individuals can escalate issues, get notifications, and access essential services through simple voice commands or touch-based gestures.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2. Algorithmic Content Customization for Accessibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Applications like TikTok, Spotify, and others use an algorithmic approach to generate content tailored to an individual’s interests. While this approach works well for people with full accessibility, it also holds potential for those with sight impairments. The algorithm doesn’t rely on the user interacting with a traditional interface, but rather on their interests and preferences over time, making it easier for users to engage without having to see every option.&lt;/p&gt;

&lt;p&gt;Empowerment tool: For individuals with sight limitations, an algorithm-based content stream could be designed to serve them better. For example, an app that curates their own calendar and task list over time to generate streams of upcoming events and todo items combined to give them a verbal/audio map of the possible day ahead for based on their calendar, their task list, and also algorithmically adjusting to their preferences over time and individualized specifically to what is happening with them. I am considering solutions in the AWS space, and here AWS Personalize is an engineering and serverless way to turn thin user behavior provided data via a recommendation engine into individualized recommendations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3. Emergency and Health Monitoring via Voice&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the context of healthcare, particularly in emergency medical situations, individual are often may be struggling with pain, confusion, or chronic conditions. We often get calls from life-alert necklaces in my area that patients never even knew they had triggered because the tech is silent about what it is doing. The need for tech that can respond to a voice command, especially when the person is in distress, becomes crucial.&lt;/p&gt;

&lt;p&gt;Empowerment tool: A voice-activated system designed for individuals with health concerns could integrate with wearables and sensors to allow users to request help, check vitals, or even get emergency instructions without needing to touch anything. This could be paired with AWS Lambda and API Gateway to provide real-time feedback and monitoring through an easily understandable voice interface. Imagine an elderly person at home experiencing chest pain: they could simply ask, “What should I do if my chest hurts?” and the system would respond with step-by-step questions, as well as alerting emergency services.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;4. Simple Communication Tools for Substance Recovery Patients&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many individuals in substance recovery face significant barriers when it comes to accessing complex healthcare technology. Even the traditional concept of “rehab“ requires a huge amount of effort and energy to go to a “rehab clinic“. What if we could bring rehab to the people who needed it, wherever they walked, wherever they drove, wherever they were? In situations where they may be struggling with their health or mental state, they need simple, intuitive tools to help them stay connected with their support systems.&lt;/p&gt;

&lt;p&gt;Empowerment tool: A low-barrier communication platform, like a voice-activated chatbot or a very simplified text interface, could allow these individuals to easily check in with healthcare providers, support groups, or have scheduled check-ins with family members. This system could use AWS Polly for natural language processing and allow users to send messages or receive advice without dealing with complicated forms or settings. It could be as simple as saying, “I need to talk to my sponsor,” or even just “I need to talk to SOMEONE” and the system would connect them to the right person for that time and place.&lt;/p&gt;

&lt;p&gt;Fragments of these tools are starting to exist in the world, but they remain locked behind some very substantial technical and societal barriers. Often one of the most substantial barriers is that they are being built by technophile engineers, for digitally fluent users. The challenge may not just be in building the technology, but in making the technology disappear.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building for Outcomes, Not Just Implementation
&lt;/h2&gt;

&lt;p&gt;As engineers, it’s easy to get obsessed with the underlying machinery—optimizing APIs, tweaking performance, debating monoliths vs. microservices. But none of that matters if the end result isn’t usable by real people.&lt;/p&gt;

&lt;p&gt;The real question isn’t how something is built—it’s who it’s built for. The best technology serves people without them ever needing to think about it.&lt;/p&gt;

&lt;p&gt;Invisible tech isn’t just a design goal. It’s a necessary shift if we want technology to truly serve humanity—not just the engineers building it and the younger generations being immersed in it.&lt;/p&gt;




&lt;h4&gt;
  
  
  Footnotes
&lt;/h4&gt;

&lt;p&gt;Footnote 1: Yes, I understand there’s a danger to hiding all that complexity. When we hide the complexity of a thing we get perverse outcomes. Even the example of someone using complex neural network technology and artificial intelligence just to get a pecan pie recipe could be considered a counter example, and a negative use of resources. I still personally do do that sometimes, I ask ChatGPT for a pie recipe that I could google…&lt;/p&gt;

&lt;p&gt;There is also the subtle side effect of how when you use AI and an LLM to get a pecan pie recipe, it decreases the incentive for someone out there on the Internet to &lt;em&gt;write that pecan pie recipe in the first place&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I leave these two problems as out of scope, for others far smarter than I to solve.&lt;/p&gt;

</description>
      <category>invisibletech</category>
      <category>nointerface</category>
      <category>voiceinterface</category>
    </item>
    <item>
      <title>How to quickly move from Exim4 server-ful email to AWS SES serverless email</title>
      <dc:creator>Coco</dc:creator>
      <pubDate>Thu, 20 Mar 2025 19:22:29 +0000</pubDate>
      <link>https://forem.com/rrsai/how-to-quickly-move-from-exim4-server-ful-email-to-aws-ses-serverless-email-45lc</link>
      <guid>https://forem.com/rrsai/how-to-quickly-move-from-exim4-server-ful-email-to-aws-ses-serverless-email-45lc</guid>
      <description>&lt;p&gt;Let's say you have Exim or another email app on a server that you have to maintain (and maintenance of email servers isn't easy).  You want to just hand off the work to AWS Simple Email Service.&lt;/p&gt;

&lt;p&gt;How many moving pieces do you need?&lt;/p&gt;

&lt;p&gt;Well, I love the low complexity of event driven architecture.  And in this case, since email will take a while to get to a person's inbox anyway, might as well make an event driven email.&lt;/p&gt;

&lt;p&gt;First you'll want to configure SES and start getting it out of sandbox mode (see details here):&lt;br&gt;
&lt;a href="https://dev.to/rrsai/moving-an-ec2-server-exim4-email-to-aws-email-systems-34me"&gt;setup for SES&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok, so assuming SES is on it's way, and you've added at least your own email to the whitelist on the sandbox, now we can get into the fun stuff:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a lambda with just a test event&lt;/li&gt;
&lt;li&gt;Create an EventBridge rule to trigger the lambda on certain events of detail-type&lt;/li&gt;
&lt;li&gt;Update the lambda contents to send out the email&lt;/li&gt;
&lt;li&gt;Create the event that will trigger the email sendout... ...from whatever codebase or language you want&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ok, more specifics:&lt;/p&gt;
&lt;h2&gt;
  
  
  Lambda Hello World
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create a hello world lambda, any will do for now, just log the event and leave the SES stuff for later.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  EventBridge Setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create an EventBus for your application:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv76729jy2tklbe2ru0sa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv76729jy2tklbe2ru0sa.png" alt="created a new event bus" width="800" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a rule against that new bus:
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvaqihmk78pr16ezm2khl.png" alt="Creating an event bus rule" width="800" height="309"&gt;
&lt;/li&gt;
&lt;li&gt;Sample Event:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhgpvadh0bs8s47z3u26f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhgpvadh0bs8s47z3u26f.png" alt="Sample Event Creation" width="800" height="309"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  {
    "version": "0",
    "id": "6a7e8feb-b491-4cf7-a9f1-bf3703467718",
    "detail-type": "CommandNWEmailRequest",
    "source": "aws.apigateway",
    "account": "123456789012",
    "time": "2017-12-22T18:43:48Z",
    "region": "us-west-1",
    "resources": ["arn:aws:apigateway:us-west-2::/domainnames/my.domain.com"],
    "detail": {
      "emailParams": {
        "to": "some-test-email@gmail.com",
        "from": "some-source-email@example.com",
        "subject": "Test event fired via lambda email sendout nwEmailSendout function",
        "text": "Raw text: of the email body that is sent in: Test event fired via lambda email sendout nwEmailSendout function",
        "html": "&amp;lt;h1&amp;gt;Hi You&amp;lt;/h1&amp;gt;          &amp;lt;div&amp;gt;           &amp;lt;p&amp;gt;           Raw text: of the email body that is sent in: Test event fired via lambda email sendout nwEmailSendout function &amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;"
      }
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create a matching pattern in the rule, I recommend on the detail-type for application events:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "detail-type": ["CommandNWEmailRequest"]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple is better, so just matching on detail-type is usually quite good enough.&lt;/p&gt;

&lt;p&gt;Run the [Test Pattern] button to make sure it matches what you want:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx5oq7oongrlthkn9ooy0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx5oq7oongrlthkn9ooy0.png" alt="Image description" width="198" height="54"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally just pick the EventBus for your application that you created earlier.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Back to the lambda, let's hook up the event rule to the lambda so that the lambda runs when the rule is triggered:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgcnnavp0iztfzvraj22n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgcnnavp0iztfzvraj22n.png" alt="Go to the lambda" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcj0d8tkzz19kcfl587o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcj0d8tkzz19kcfl587o.png" alt="pick the trigger" width="800" height="641"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the lambda with a trigger from the eventbridge:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq89rn4vwehipxqky8976.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq89rn4vwehipxqky8976.png" alt="Lambda triggered from eventbridge" width="800" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Send a test event to your newly created bus:&lt;br&gt;
&lt;a href="https://us-east-1.console.aws.amazon.com/events/home?region=us-east-1#/eventbuses/sendevents?eventBus=NWEventBus" rel="noopener noreferrer"&gt;https://us-east-1.console.aws.amazon.com/events/home?region=us-east-1#/eventbuses/sendevents?eventBus=NWEventBus&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx5z0k5rwot8sxf5c2py8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx5z0k5rwot8sxf5c2py8.png" alt="Sending a test event" width="800" height="953"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F37frm3msqg8j5ub2qcvz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F37frm3msqg8j5ub2qcvz.png" alt="sent event" width="800" height="953"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And see if your hello-world lambda logged anything.&lt;/p&gt;

&lt;p&gt;Once you have got your lambda being triggered, you're going to have to give the lambda access to the aws-sdk.  Use layers for this from the console (or cdk locally, which is out of scope of this).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
aws lambda publish-layer-version --layer-name aws-sdk --zip-file fileb://aws-sdk.zip --compatible-runtimes nodejs18.x --description "NW AWS SDK" --profile=YourProfileToUploadHere

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

&lt;/div&gt;



&lt;p&gt;Ok, hopefully you have the layer available, you'll need to attach it to the aws function:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foehttbncyl7stbcn4hy3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foehttbncyl7stbcn4hy3.png" alt="Image description" width="598" height="177"&gt;&lt;/a&gt; &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4n6r4sdqgicdqonvyxp6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4n6r4sdqgicdqonvyxp6.png" alt="Image description" width="168" height="84"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62lthe5yiohejpijmyhv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62lthe5yiohejpijmyhv.png" alt="Image description" width="800" height="684"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you should be able to just easily import &lt;code&gt;aws-sdk&lt;/code&gt; in modern js module files .mjs&lt;/p&gt;

&lt;p&gt;Here is a lambda for SES sending:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import aws from 'aws-sdk'
const ses = new aws.SES({ region: "us-east-1" });

const validate = (params)=&amp;gt;{
    if(!params || params?.length === 0){
        throw new Error('No params passed to lambda function to send the email.')
    }
    const shouldExist = {
        to: true,
        from: true,
        subject: true,
        html: true,
        text: true,
    };
    Object.keys(shouldExist).map((key)=&amp;gt;{
        if(typeof params?.[key] !== 'string' || params?.[key] === ''){
            throw new Error('Cannot send out email with missing or blank parameters')
        }
    });

}

export const handler = async(event) =&amp;gt; {
    console.info('Initial event', event);
    const incoming = event?.detail?.emailParams;
    validate(incoming)
    const {
        to,
        from,
        subject,
        html,
        text
    } = incoming;

  var params = {
    Destination: {
      ToAddresses: [to],
    },
    Message: {
      Body: {
        Html: {
              Charset: 'utf-8',
              Data: html,
        },
        Text: { Data: text},
      },

      Subject: { Data: subject },
    },
    Source: from,
  };

  return ses.sendEmail(params).promise()
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is a test event to fire against the lambda:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0923isp1w4yi4c0cxy6d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0923isp1w4yi4c0cxy6d.png" alt="Image description" width="800" height="1024"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
{
  "version": "0",
  "id": "6a7e8feb-b491-4cf7-a9f1-bf3703467718",
  "detail-type": "CommandNWEmailRequest",
  "source": "aws.apigateway",
  "account": "123456789012",
  "time": "2017-12-22T18:43:48Z",
  "region": "us-west-1",
  "resources": [
    "arn:aws:apigateway:us-west-2::/domainnames/my.domain.com"
  ],
  "detail": {
    "emailParams": {
      "to": "roy.ronalds@gmail.com",
      "from": "tchalvak@ninjawars.net",
      "subject": "Test event fired via lambda email sendout nwEmailSendout function",
      "text": "Raw text: of the email body that is sent in: Test event fired via lambda email sendout nwEmailSendout function",
      "html": "&amp;lt;h1&amp;gt;Hi Roy&amp;lt;/h1&amp;gt;          &amp;lt;div&amp;gt;           &amp;lt;p&amp;gt;           Raw text: of the email body that is sent in: Test event fired via lambda email sendout nwEmailSendout function &amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;"
    }
  }
}

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

&lt;/div&gt;



&lt;p&gt;You will also need to allow the lambda to run calls against SES, follow the instructions here for that:&lt;br&gt;
&lt;a href="https://aws.amazon.com/premiumsupport/knowledge-center/lambda-send-email-ses/" rel="noopener noreferrer"&gt;https://aws.amazon.com/premiumsupport/knowledge-center/lambda-send-email-ses/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In broad strokes, you'll need to add a policy like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ses:SendEmail",
                "ses:SendRawEmail"
            ],
            "Resource": "*"
        }
    ]
}


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

&lt;/div&gt;



&lt;p&gt;And attach it to a role, at least to the role that the lambda is using to run:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faa58n5x88shz98t4d1q6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faa58n5x88shz98t4d1q6.png" alt="Image description" width="712" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Email Sent And Received
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1k3gb4dwmshy29kpq8wu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1k3gb4dwmshy29kpq8wu.png" alt="Image description" width="800" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Powerful System
&lt;/h2&gt;

&lt;p&gt;You will have a full fledged system on serverless AWS with a ton of different powers coming from SES, including mail bounce measuring, trust measures of whether your email is being flagged as spam too often, and at many email volumes, low to no cost, all driven by event-based triggers.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>web3</category>
      <category>crypto</category>
      <category>offers</category>
    </item>
    <item>
      <title>The Subtle Case For and Against React</title>
      <dc:creator>Coco</dc:creator>
      <pubDate>Fri, 19 Apr 2024 07:41:07 +0000</pubDate>
      <link>https://forem.com/rrsai/the-subtle-case-for-and-against-react-apf</link>
      <guid>https://forem.com/rrsai/the-subtle-case-for-and-against-react-apf</guid>
      <description>&lt;ul&gt;
&lt;li&gt;What are the hidden downsides of React?
&lt;/li&gt;
&lt;li&gt;What if React makes everything much harder and more complex?
&lt;/li&gt;
&lt;li&gt;Why do we bother to use it at all, even if we know there are these major disadvantages?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A friend in a Slack group that I'm part of recently posted an evaluation of React as a staple of many software teams today.  Essentially they said: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Why is React everywhere, when..."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;It is extremely complex.  It adds complexity on top of javascript, which is already a nightmare of learning cliffs.  React now recommends using Next.js so you truly have to become an expert in html-&amp;gt;js-&amp;gt;react-&amp;gt;nextjs to work in the space.&lt;/li&gt;
&lt;li&gt;It is huge and probably slow compared to pure js and HTML, so why would we inflict that on ourselves?&lt;/li&gt;
&lt;li&gt;It makes development slow because the thinking and planning require so much hard work to build things with it, so shouldn't we avoid it?&lt;/li&gt;
&lt;li&gt;jQuery was the way to go before SPA frameworks, and it worked well, why trade down to something that's both slower and &lt;strong&gt;less&lt;/strong&gt; stable?&lt;/li&gt;
&lt;li&gt;Are people trying to get work done in React because it's standardized and common, not because it's &lt;strong&gt;effective&lt;/strong&gt;?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Essentially we can summarize the negative experience with this ironic meme image:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fak023eq1reqaf48yi4vl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fak023eq1reqaf48yi4vl.png" alt="Progressive Enhancement mental gymnastics" width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
(The image roughly sums up that friend's concerns, my position on the matter is different )&lt;/p&gt;

&lt;h2&gt;
  
  
  Fair Accusations give pause
&lt;/h2&gt;

&lt;p&gt;This all gave me pause.  These are not small concerns, and I agree with all of them and have the same concerns on the face of them.  So how could I still like or recommend React?  In fact I am even in the process of refactoring another old personal project &lt;strong&gt;away&lt;/strong&gt; from jQuery and towards React.  Why am I trying to do this if I can't articulate counterarguments to the above very apt points?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7o6ce3d1uxqtm5dono4o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7o6ce3d1uxqtm5dono4o.png" alt="are we the baddies" width="600" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Subtle Case for React
&lt;/h2&gt;

&lt;p&gt;So let's run through the points and see if I still can recommend React with a straight face at all, despite generally agreeing with the underlying concerns 1 - 5 against it.&lt;/p&gt;

&lt;h3&gt;
  
  
  1 - React complexity weighed as if it was ballast
&lt;/h3&gt;

&lt;p&gt;Lower complexity is &lt;strong&gt;usually&lt;/strong&gt; a good argument in software.  "That pull request will highly increase complexity." is a valid rationale to take another look and think through the cost.  But complexity in the case of React is also a double-edged sword. We can look at React, nextjs and say "That is too complex to learn and maintain and work with" because we are actually silently weighing it against the strawman of how easy we &lt;strong&gt;imagine&lt;/strong&gt; it would be to do on our own, solo, from scratch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3ki3fzxjwomra0sf6db.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3ki3fzxjwomra0sf6db.png" alt="how much can a button cost, michael" width="540" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have spent hours tweaking a single button.  Not a calendar widget (god forbid) or a cool custom widget, just the button that comes in html, which by default has this beautiful look:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshp87nd0wo1flycv9hs4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshp87nd0wo1flycv9hs4.png" alt="default-button-ui" width="387" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here are the variations that you'll have to encounter of how a button is rendered in a few different browsers (just a button, one of the simpler building blocks): (Chrome, Edge, Old IE 11, Safari)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ge4dhpb2ujamhqn9ml8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ge4dhpb2ujamhqn9ml8.png" alt="default button render in chrome" width="306" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fafcu47t9wbdv1n969kq9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fafcu47t9wbdv1n969kq9.png" alt="default button render in edge" width="306" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8vcnygd1fe3erg25ywqf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8vcnygd1fe3erg25ywqf.png" alt="default button render in ie 11" width="306" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgaqpqkbwku60y0h2nm1v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgaqpqkbwku60y0h2nm1v.png" alt="default button render in safari" width="355" height="134"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Over the course of my career I have found there to be similar or worse variations in &lt;code&gt;&amp;lt;button&amp;gt;, &amp;lt;select&amp;gt;, &amp;lt;ul&amp;gt;, &amp;lt;dl&amp;gt;, &amp;lt;abbr&amp;gt;, &amp;lt;small&amp;gt;, &amp;lt;iframe&amp;gt;, &amp;lt;input&amp;gt; types, of course with &amp;lt;audio&amp;gt; and &amp;lt;video&amp;gt;&lt;/code&gt; not to mention functional differences (and sometimes things just don't work as needed in different browsers without polyfills, like how &lt;code&gt;&amp;lt;abbr&amp;gt;&lt;/code&gt; need a polyfill on mobile browsers for definitions to be readable).&lt;/p&gt;

&lt;p&gt;The foundations of the web are pretty shaky to create app-based UI on top of.  Even with html5 we get the hint that it's really geared towards newspaper &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt;s and blog posts with &lt;code&gt;&amp;lt;asides&amp;gt;&lt;/code&gt;, it was not made for building web apps.  Especially to fulfill invisible and nonfunctional requirements like a11y and consistency, we need all the help we can get.  We can get that help by standing on the shoulders of giants; UI component libraries can crowdsource issues that we and others would encounter, and having composition via components helps avoid reinventing the wheel during the creation of each new widget of an app.&lt;/p&gt;

&lt;h3&gt;
  
  
  2 - HTML+JS vs React: Fight!
&lt;/h3&gt;

&lt;p&gt;Html is a breeze.  Javascript is fun. CSS is... ...well, I can barely think of a worse way to make UI, but with tailwind it's simple enough. React on the other hand is a pain. You build an application and it's thousands of lines of code and relies on hundreds or thousands of underlying npm packages as well.  In the end, you may have an application that is prone to errors (components within components) and browser errors (rendering complexities in different browsers are real).  So then here is my question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If someone hired &lt;em&gt;you&lt;/em&gt; to create a webpage (no framework involved, minimal js) today, would you take the job?  Can you even find feasibly find work at your pay scale where companies are looking to hire people to create webpages?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For my personal answer to the above, if someone offered me my current salary to &lt;em&gt;only&lt;/em&gt; work on web pages... simpler and easier work than what I currently do, I would... &lt;strong&gt;turn them down&lt;/strong&gt;.  That is not due to ego, it is because I have been down that road already.  As the meme image hinted, you can work on web stuff, visual design, web pages, companies can use that to keep you out of an engineering space by pushing you into an infinite treadmill of pixel perfection and throwaway marketing sites.  Being told that your passion for outcomes that require time to think through and create deep quality, because it would take too long, that sucks.  The space that we call "engineering", complete with companies that want engineering done, while a ton harder to work within than the raw web page space, is also a very creatively rewarding space to be within.  That is the space that React lives in, and the space that pure js apps can often exit from.  The problematic expectations in that space are often for speed over engineering and "you're just creating a webpage, that should only take a day, right?".&lt;/p&gt;

&lt;p&gt;[ lucille bluth how much is a banana file footage not found ]&lt;/p&gt;

&lt;p&gt;I'll go a step further and say that because engineering is usually an &lt;em&gt;entrance fee&lt;/em&gt; to React, you will often find yourself working with a team that share that engineering mindset.  That can sometimes lend itself to overengineering the whole team you'd work with in a React space will often be in an engineering mindset as well.&lt;/p&gt;

&lt;p&gt;As far as high paying work at companies, I haven't seen people looking for &lt;em&gt;just&lt;/em&gt; webpage edits in a long time.  That space has been eaten up by WordPress, squarespace, themeforest, free themes, 5 html templates for 0.000004 bitcoins, etc etc.  The game is over there. The space is saturated.  If you think it's difficult to compete with the tons of other people who also write React better than you and I, try competing with some of the people who make webpages out there.  It's insane what beautiful stuff they can visually create and how fast flat html pages can be created now.&lt;/p&gt;

&lt;p&gt;So React filters over from &lt;strong&gt;page creation&lt;/strong&gt; space into the &lt;strong&gt;engineering&lt;/strong&gt; space for people who don’t want to deal with React’s bull****, and that's good for me, because I don't want to compete with what's out there in the non-engineering space. There there be dragons.&lt;/p&gt;

&lt;h3&gt;
  
  
  3 - It makes things take longer to plan... ..isn't that bad?
&lt;/h3&gt;

&lt;p&gt;I would say that it takes &lt;strong&gt;longer&lt;/strong&gt; to plan and execute building things &lt;em&gt;with&lt;/em&gt; React than without React.  That's irony.  That seems like a bad outcome for the metric of speed?  Imagine the headlines: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fskthcw51zrb2k55rbqpt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fskthcw51zrb2k55rbqpt.jpg" alt="I'm going to change the world" width="680" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, reality takes so much more work and expertise to generate high quality than it seems.  We think we can and should take shortcuts, but we're better off letting go of that expectation of an easy win early on and settling in.&lt;/p&gt;

&lt;p&gt;It takes mastery to cut a hedge shrubbery correctly (I learned this to my dismay after dropping the hedge clippings into the hedge when they were green and having to manually painstakingly pull them out weeks later when the clippings turned brown).  It takes months to grow a carrot in a garden, yet it's one of life's great pleasures to grow plants.  Why do we want software to be done as fast as humanly possible? Sometimes that speed is to the detriment of long term quality. Good companies and good teams can absorb the stark reality that good stuff takes a long time and a lot of iterations.  Are you sure you want to work for the companies that can't accept that things might take time to get done to a high level of quality?&lt;/p&gt;

&lt;h3&gt;
  
  
  4 - jQuery and JS vs React, why bother if the first one will get the job done?
&lt;/h3&gt;

&lt;p&gt;I worked with jQuery back in the day, and I work with it on a legacy project today.  jQuery still has a place in my heart, only because I have a deep-rooted mistrust of browser compatibility due to being burned so many times in the past.  The main things that I needed jQuery for have been replaced by &lt;code&gt;document.querySelectorAll()&lt;/code&gt; and a &lt;code&gt;domready&lt;/code&gt; wrapper.  So we have the best bits of jQuery in browsers today.  &lt;strong&gt;However jQuery and  still not powerful enough.&lt;/strong&gt; Building the basic foundations is so difficult that people routinely think that they can rebuild Facebook over a weekend.  We think we can build a simple carousel component on our own (but we forget about the invisible accessibility non-functional requirements (&lt;a href="http://web-accessibility.carnegiemuseums.org/code/carousels/" rel="noopener noreferrer"&gt;http://web-accessibility.carnegiemuseums.org/code/carousels/&lt;/a&gt;) ).&lt;br&gt;
We need... dun dun dun, something as powerful as a framework to harness the full potential of what we could build for web UIs, we have to rely on other’s works as a baseline to build better outcomes.&lt;br&gt;
So the formula becomes:&lt;br&gt;
jQuery + js = fine for solo one-offs. React + ui framework = help long term consistency.&lt;/p&gt;

&lt;h3&gt;
  
  
  5 - Are people hiring for React because they want cogs in a machine?
&lt;/h3&gt;

&lt;p&gt;A lot of companies hire with React as a skill keyword, and a lot of those teams at the companies are spending a lot of time on React projects, but is React just a lowest common denominator, a keyword matching mechanism?  A person in the thread made the astute observation that if a role lists all the frameworks, such as saying "This role must know at least one of (React/Angular/Vue)" then the writers may effectively mean "must know javascript" because those frameworks are not the same at all anyway.&lt;br&gt;
In a way that's close, but React/Angular/Vue are not just a technology, they are also a clique or community; a way of thinking about engineering on the web that didn't exist in the 90s.  It also involves engineering for problems that didn't exist in the 90s.  The web interface for the spotify player and other web apps with subtle tweaks and requirements cannot be aggregated from a collection of jQuery plugins.  So React is not for solo work, it’s for &lt;strong&gt;team work&lt;/strong&gt;, and the clique and the community methodologies are more than the technology.&lt;/p&gt;

&lt;p&gt;Pure js = fine for solo development. React = assists with &lt;strong&gt;team&lt;/strong&gt; consistency.&lt;br&gt;
If you like to spend a weekend writing an amazing 100k pure javascript genius solution, but two months from now &lt;em&gt;no-one else on your team&lt;/em&gt; will get to understand what the flip you built, React helps push back against that with the huge amount of community documentation and best practices that we might not be able to find in the work of a virtuoso solo javascript developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  So for now I'm still moving that project to React, but let me know of any great alternatives I should check out
&lt;/h2&gt;

&lt;p&gt;So for now I am planning to move my legacy project from jQuery+js to React.  I yearn for the day when js is robust enough and consistent enough to get done what I want to get done (creating a lexicon of UI verbs to compose, and app widgets that are customized to my app, mainly).  There may be other alternatives out there with good component systems, and I'm happy to hear of them, but the conceptual &lt;code&gt;component&lt;/code&gt; is one crucial piece, and being able to build on the shoulders of (ui) giants who are better than me is the other crucial piece.  I don't want to spend another day building a good button again.  How about you?  Where are you sourcing your grain-fed free-range buttons from these days?&lt;/p&gt;

&lt;h2&gt;
  
  
  Honorable Mentions
&lt;/h2&gt;

&lt;p&gt;Alternatives to React to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://swup.js.org/" rel="noopener noreferrer"&gt;https://swup.js.org/&lt;/a&gt; single-page-app but with minimal framework, still along for the feel of an SPA&lt;/li&gt;
&lt;li&gt;HEC no-framework approach: &lt;a href="https://medium.com/@metapgmr/hex-a-no-framework-approach-to-building-modern-web-apps-e43f74190b9c" rel="noopener noreferrer"&gt;https://medium.com/@metapgmr/hex-a-no-framework-approach-to-building-modern-web-apps-e43f74190b9c&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Astro to use every framework at once instead of just react? &lt;a href="https://astro.build/" rel="noopener noreferrer"&gt;https://astro.build/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;What about a little boilerplate repo that I am working on myself as a result of this article, (WIP) called &lt;code&gt;lazier&lt;/code&gt;: &lt;a href="https://github.com/tchalvak/lazier/tree/main" rel="noopener noreferrer"&gt;https://github.com/tchalvak/lazier/tree/main&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The bane of AWS Lambda Coldstarts</title>
      <dc:creator>Coco</dc:creator>
      <pubDate>Sun, 17 Mar 2024 17:55:21 +0000</pubDate>
      <link>https://forem.com/rrsai/the-bane-of-aws-lambda-coldstarts-2pe7</link>
      <guid>https://forem.com/rrsai/the-bane-of-aws-lambda-coldstarts-2pe7</guid>
      <description>&lt;p&gt;Coldstarts of AWS lambdas are the bane of my existence, are they for you?  I often find that the coldstart delay degrades the user experience, and while it seems like they should be very avoidable &lt;em&gt;because the coldstarts should not be exposed to end users&lt;/em&gt;, they end up being a little difficult to see the way around.&lt;/p&gt;

&lt;h2&gt;
  
  
  When The User Encounters A Coldstart
&lt;/h2&gt;

&lt;p&gt;Here is the scenario of interaction with coldstarts that you may encounter.  You do an api call for some data, it involves a lambda, and it's fast.  Like blazing fast, 12ms, 15ms, great response time.  But every so often, the api call hangs... ...and hangs, and hangs, for seconds, not ms.  And because it only happens infrequently, it's really hard to debug, but when it does happen it's a pretty bad user experience.&lt;br&gt;
That is it.  You've encountered the coldstart problem.  Your lambda interaction that is usually blazing fast is sometimes really slow BUT ONLY INFREQUENTLY.  The problem is that it's so slow that infrequently that it really degrades the user experience.&lt;/p&gt;

&lt;p&gt;When you get a hot lambda instance it's like a good cup of fresh coffee, only blazing fast, taking just a few miliseconds to perk you right up.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjz6p90yuqhyxc6qib12a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjz6p90yuqhyxc6qib12a.png" alt="hot start lambda is like fresh coffee" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When it's cold, it's like yesterday's coffee, you take a sip and grimace and the caffeine is going to take a while to kick in&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcl1a14cfbwyn1lk4pi13.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcl1a14cfbwyn1lk4pi13.png" alt="cold start lambda is like day-old coffee" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So what can we do?&lt;/p&gt;

&lt;h2&gt;
  
  
  A Few Avoidance Techniques
&lt;/h2&gt;

&lt;p&gt;I am going to give a few hacks that have worked for me first, because the real answer overall is going to be annoying; it requires a mindset change in how we deal with data (precomputation, which I will get to later).  So here are a few good hacks to tide us both over.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't put synchronous lambdas at the end of your api gateways (in other words if you expect to wait on a response or to have to manipulate the response data, make it an async lambda)

&lt;ul&gt;
&lt;li&gt;when writing input or "commands" through an api endpoint, try to immediately emit an event to eventBridge and return {'success':'OK'} respond, instead of doing everything all at once (this is generally a &lt;a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/decompose-monoliths-into-microservices-by-using-cqrs-and-event-sourcing.html" rel="noopener noreferrer"&gt;CQRS approach&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;when reading or querying, try to: read directly from database &lt;strong&gt;without&lt;/strong&gt; a lambda, or turn on caching on apigateway, or precompute the resultset seperately&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Warming: If you have an event driven architecture, you can set up an event scheduler that fires an event to warm up a lambda with whatever schedule you want, to wake it up at appropriate times (e.g. 7 am and 8 am in the morning is a good one before people come online for the day to warm it up for others) or use someone else's &lt;a href="https://github.com/juanjoDiaz/serverless-plugin-warmup" rel="noopener noreferrer"&gt;warmer library&lt;/a&gt;
&lt;/li&gt;

&lt;li&gt;Increase the memory of a lambda function (because in the background that causes AWS to increase the CPU class of a function), e.g. double the provisioned memory will probably increase the CPU class that AWS will give it and because you're charged by resources*time, faster invocations with more memory may not actually cost more in the end (your mileage may vary)&lt;/li&gt;

&lt;li&gt;A Temporary Stopgap: Provisioned Concurrency: It's an option to increase the provisioned concurrency to 1 so that there's always a "warm" instance, but I don't recommend it and only include that here for completeness.  It really doesn't solve the problem anyway (when enough load occurs, a new instance will spin up and you'll still have to incurr the cost of a coldstart)&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  AWS's Recommendations for Coldstarts
&lt;/h2&gt;

&lt;p&gt;One of the concepts that you will encounter when reading about coldstarts and how to deal with them is as follows: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS will recommend &lt;a href="https://aws.amazon.com/blogs/compute/operating-lambda-performance-optimization-part-1/" rel="noopener noreferrer"&gt;ways to make coldstarts less slow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AWS will recommend not putting a lambda directly at the end of a user-facting interaction, because the coldstart will kill the user experience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What doesn't happen often enough is a recommendation for what to actually do instead of sticking lambdas at the end, instead of suffering from coldstarts at all.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5fa4o6tgziuy6rhsds34.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5fa4o6tgziuy6rhsds34.png" alt="An onion model for AWS lambda and serverless interaction times" width="700" height="363"&gt;&lt;/a&gt;&lt;br&gt;
...a glimpse of a model to determine where slowness can come from via &lt;a href="https://lumigo.io/blog/debugging-slow-lambda-response-times/" rel="noopener noreferrer"&gt;lumigo&lt;/a&gt; where the problem of coldstarts is generally happening in the orange band&lt;/p&gt;

&lt;p&gt;Any recommendation to decrease the time of the lambda itself or the lambda allocation where coldstarts occur is only going to get you so far.  It's useful when you have already written lambda code and just want it to act faster, but the deeper solution brings us to precomputation...&lt;/p&gt;

&lt;h2&gt;
  
  
  The Deeper, Harder Precomputation Solution
&lt;/h2&gt;

&lt;p&gt;The really deep solution is to develop systems with cold starts in mind by relying on precomputation.  In this model, instead of calculating and manipulating data &lt;em&gt;on the fly&lt;/em&gt; inside a lambda when an api call requests it, put the data into dynamodb in a &lt;em&gt;triggered&lt;/em&gt; manner (whether triggered by writes or by a time-to-live or on a schedule) using a precomputational lambda and then just always pull right from that precomputed data set in api calls.  So let's say there is a &lt;strong&gt;latest_statistics&lt;/strong&gt; dynamodb table, the api calls and apigateway would pull directly from that dynamodb fast and simplistically with no computation at all, and then separately &lt;em&gt;out of band&lt;/em&gt; a lambda would update what data gets in &lt;strong&gt;latest_statistics&lt;/strong&gt;.&lt;br&gt;
Precomputation is a major change from approaching things from a "pull, manipulate, respond" way of developing, so we may need helpful techniques like the avoidance techniques above to help us along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Techniques for Faster Hot Lambda Invocations
&lt;/h2&gt;

&lt;p&gt;This isn't applicable to coldstarts, but here are few techniques for speedier hot lambda invocations to round it out for good measure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cache variables in the global scope of the instance, so that the hot lambda instance can have them in memory, things like api clients and unchanging dependencies&lt;/li&gt;
&lt;li&gt;Cache a response if a request happens close enough in time, in other words putting a json/data response into memory along with a timestamp, and if little enough time has elapsed that you are comfortable, just return the in-memory data without having to reach out again to the database&lt;/li&gt;
&lt;li&gt;Predictive, 2-stage approach: Return a quick and dirty response fast, and then set the slower results to be collected and displayed with once updated timestamp or a specific command id becomes available&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Overall
&lt;/h2&gt;

&lt;p&gt;In the 1,000 foot view from above, there are two parts to mitigating the subtle effects of coldstarts:  The first is an approach change to ensure that users cannot touch lambdas that will wait during coldstarts.  For example, if you have to get a user profile, instead of manipulating the data in custom ways in the lambda compute, have apigateway pull directly from dynamodb.  And secondly, deferring results, so that the lambda that is front-facing and user facing can be fast, and the slow compute work can happen behind the scenes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional resources
&lt;/h2&gt;

&lt;p&gt;A resource for more coldstart avoidance techniques and countermeasures: &lt;a href="https://www.simform.com/blog/lambda-cold-starts/" rel="noopener noreferrer"&gt;https://www.simform.com/blog/lambda-cold-starts/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Serverless warmer library: &lt;a href="https://github.com/juanjoDiaz/serverless-plugin-warmup" rel="noopener noreferrer"&gt;https://github.com/juanjoDiaz/serverless-plugin-warmup&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Coldstart Stats Daily By Language/Environment:&lt;br&gt;
&lt;a href="https://maxday.github.io/lambda-perf/" rel="noopener noreferrer"&gt;https://maxday.github.io/lambda-perf/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An option to watch is LLRT, Low Latency Runtime: &lt;a href="https://github.com/awslabs/llrt" rel="noopener noreferrer"&gt;https://github.com/awslabs/llrt&lt;/a&gt; which is in the early stages, but generally bundles node into a single bundle&lt;/p&gt;

&lt;p&gt;If connecting to an RDS database, you can consider using an RDS proxy for connection pooling, though it is an additional expense: &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-database.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/lambda/latest/dg/configuration-database.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>lambda</category>
      <category>coldstart</category>
    </item>
    <item>
      <title>The 1000 papercuts of AWS Serverless</title>
      <dc:creator>Coco</dc:creator>
      <pubDate>Tue, 12 Mar 2024 07:16:13 +0000</pubDate>
      <link>https://forem.com/rrsai/the-1000-papercuts-of-aws-serverless-21o6</link>
      <guid>https://forem.com/rrsai/the-1000-papercuts-of-aws-serverless-21o6</guid>
      <description>&lt;p&gt;AWS serverless is great for scaling up to heavy usage and down to zero.  It is truly a space to do engineering at a true sense of the word, putting together systems and composing pieces of a puzzle in a way that servers and monoliths can't match.  It's how I make my living.  It's why I get paid the big bucks.  :p&lt;/p&gt;

&lt;p&gt;However, the more I use serverless, the more I come to intimately know some parts of it that I wish were better.  From trying to tamp down runaway costs, to trying to "see" what these very complex interlacing systems are doing internally, to just avoiding having to constantly context switch, there are obstacles that tend to pile up.  Individually, each obstacle - obstable to doing stuff easily and simply - doesn't amount to much on it's own, but like "death by a thousand (paper) cuts", the cumulative effects tend to weigh down attempts at good engineering.&lt;/p&gt;

&lt;p&gt;One of the first things that I'll talk about is surprises lying in wait in terms of cost, then I will move on to structural and complexity issues and end with context switching and finding your place again.  But costs first, because as AWS's Dr Werner says, costs is a proxy for sustainability, so if you can't control it well, things can get unsustainable fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost Boundaries
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Scaling up Spikes
&lt;/h3&gt;

&lt;p&gt;In many server-based services, it was common to just spin up a server and have a relatively stable expectation of cost.  Years ago, if I spun up a virtual server on Heroku or DigitalOcean or Rackspace or EC2, I wouldn't worry much about how much it was going to cost me generally, because the most it would cost was 1 server's worth, and was pretty stable.&lt;/p&gt;

&lt;p&gt;The scaling and performance was also pretty static is the problem of course.  Essentially every time I was creating a server, I was way over-provisioning the server in the hope that I would never run up against it's upper limits.  Or if I did, I would have time to adjust.  It's not great to overprovision, but at least the cost had natural maximums that were usually stable and predictable.&lt;/p&gt;

&lt;p&gt;... A Year Of An EC2 Server ...&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05w2lk98mnh2yvxyntlu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05w2lk98mnh2yvxyntlu.png" alt="A Year Of An EC2 Server" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the serverless cloud, since it is often on-demand by default, the cost can go up and out of control if I don't take the time to set up limits up front. AWS ships with a 1000 concurrent lambda invocation limit on the account, but if &lt;strong&gt;someone&lt;/strong&gt; (&lt;em&gt;coughs&lt;/em&gt; we won't say who) writes an infinite loop in a lambda or a poison pill in an SQS queue, the system could run 10 invocations x 1000 concurrent instances for 10,000 invocations per second.  Speaking from experience, this can rack up thousands of dollars in a day.&lt;/p&gt;

&lt;p&gt;... Roughly the same timeframe of a serverless service ...&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv7btwlxuzxcmihsyy4qi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv7btwlxuzxcmihsyy4qi.png" alt="A Month of Serverless Services" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is by design; you only pay for what you use.  However, the dark side of that is that a spike in usage can rack up a major spike in cost.&lt;/p&gt;

&lt;h3&gt;
  
  
  Missing low-granularity budget controls
&lt;/h3&gt;

&lt;p&gt;The granularity of budgets is either really long, like a month, and thus I will hear about a problem way too late &lt;em&gt;(Finding out on the 15th of the month that there's a major cost spike can be too late and costly)&lt;/em&gt;, or it is really noisy and thus the signal that I want to hear about get lost in the noise ("&lt;em&gt;Oh no, a cost overrun is currently happening!&lt;/em&gt;" gets quickly lost in &lt;em&gt;"Another daily budget adjustment as it swings back and forth"&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7w48vs61bazvm7lbg4wb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7w48vs61bazvm7lbg4wb.png" alt="RDS costs by month" width="800" height="417"&gt;&lt;/a&gt;&lt;br&gt;
Here is a monthly cost bump that I got in RDS (the maroon), that because it is viewed at a monthly granularity, is difficult to track down.&lt;/p&gt;

&lt;p&gt;When viewed with a daily granularity, it becomes more clear that this was a service that was added:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flmlusxru9jc62000epmc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flmlusxru9jc62000epmc.png" alt="RDS costs by day" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So the more granular you can make your cost monitoring, the easier it can be to debug.&lt;br&gt;&lt;br&gt;
Unfortunately, for -budgets- the granularity min-maxes out at a day at the lowest, so for alerting and alarming against cost overruns budgets are not particularly effective.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cost Anomaly detection
&lt;/h3&gt;

&lt;p&gt;Ideally, automatic anomaly detection would fill the gap of weird cost overruns that may happen in unexpected areas not cost anomaly detection to be a helpful assistant in detecting cost spikes.  It just responds to late, and to too regular of anomalies:&lt;/p&gt;

&lt;p&gt;At a granularity of a day, by the time 24 hours has gone by, I can have already racked up thousands of dollars before ever getting an email that something has gone wrong.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4z3ptxepsqwyy2k8gpe6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4z3ptxepsqwyy2k8gpe6.png" alt="Cost Anomalies with Low Granularity" width="800" height="357"&gt;&lt;/a&gt;&lt;br&gt;
Here is an example of some cost anomalies that get caught, but where the anomalies are often so minor that they're like an anomaly of 0.7 cents?&lt;/p&gt;

&lt;h2&gt;
  
  
  Architectural Design Simplicity
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Automating code deployments has been made easy, automating Infrastructure-as-Code deployments is still rough&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As I have gone in depth into using Infrastructure-as-Code (hereafter IaC) for work and personal projects, I commonly want to automate deployment of my infrastructure alongside my code.  Code in the same repository, infrastucture in the same repository, data fixtures in the same repository, and I can build the whole application all at once.  Guides that talk about code deployment often have great direct approaches.  On the other hand, guides that talk about IaaC deployments are often another matter.&lt;br&gt;
There seems to be a substantial lack of visualization tools with IaaC to make it easier to handle the complexity that it brings with it.  I have spent many hours at work designing architectural diagrams at work... ...of &lt;strong&gt;already&lt;/strong&gt; existing infrastructure, in an attempt to understand it and capture it's purpose.  Conversely, if I am diagraming something that I am architecting from scratch, it would make a lot of sense if there were a way to map from a visual diagram to a baseline architecture and modify both in concert.&lt;/p&gt;

&lt;p&gt;There are possibilities around this space:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS CodeStar&lt;/li&gt;
&lt;li&gt;AWS Amplify Studio&lt;/li&gt;
&lt;li&gt;AWS Codecatalyst&lt;/li&gt;
&lt;li&gt;etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But these generally seem to revolve around using a standard blueprint and spinning up a pre-generated set of infrastructure, as opposed to creating infrastructure and then &lt;strong&gt;splitting apart&lt;/strong&gt; the pieces that are provisioned, in order to retroactively refactor as time goes on.&lt;/p&gt;

&lt;p&gt;I find a gap with cloudformation &lt;strong&gt;and&lt;/strong&gt; AWS CDK where it can be very difficult to &lt;em&gt;see&lt;/em&gt; what has already been created holistically.  For example, if there were a legacy architectural stack that was created with little institutional architectural documentation, it is quite difficult to go see what all the resources the app/ecosystem of that legacy stack are.&lt;/p&gt;

&lt;p&gt;So if feels like there is a missing toolset around IaaC that code has more matured enough to have good tools for.  Unfortunately, because the power of Iac is so strong and far reaching, architects and engineers need the tools all the more on to keep complexity under control.  Just like the thoughts that early global explorers probably had while navigating new coastlines and navigating by the stars; "I really wish I had a good map to see where I am NOW."&lt;/p&gt;

&lt;h2&gt;
  
  
  Visibility
&lt;/h2&gt;

&lt;p&gt;While we're near the topic of visibility, let's talk about the somewhat unrealized promise of observability on AWS cloud.  With a complex system, it becomes important to "see" what each of the pieces are doing when each operates independently of each-other.  With micro-microservices, each piece could be the failure point that I am looking for when debugging, so I need to be able to "see" each.  But observability is pretty difficult to set up on AWS when not working directly in the console, and after-the-fact monitoring is just no longer enough when trying to track down which peice of a 30 link service chain is the one that is broken.&lt;/p&gt;

&lt;p&gt;Take an SQS&amp;lt;-to-&amp;gt;Lambda&amp;lt;-to-&amp;gt;Dynamo stack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu89oo3crqaqpwh4q1qmb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu89oo3crqaqpwh4q1qmb.png" alt="SQS to Lambda to DynamoDB" width="501" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If I look in dynamo, I can see the stored data.  If I look at SQS, I &lt;strong&gt;may&lt;/strong&gt; see the messages in flight if something is wrong or slow, but more likely is I will see an &lt;strong&gt;empty&lt;/strong&gt; queue and no evidence of whether it is empty because messages have &lt;strong&gt;already&lt;/strong&gt; flowed through it. Or because messages have &lt;strong&gt;not yet&lt;/strong&gt; flowed through it.&lt;/p&gt;

&lt;p&gt;With the lambda I will see the traces after the fact of events, the invocation metrics, and the logging entries that I have to manually create, but I actually want to see the events that are continually flowing &lt;strong&gt;through&lt;/strong&gt; the lambda.&lt;/p&gt;

&lt;p&gt;So serverless requires connecting together these many-link chains of services, and it stops being effective to just monitor the input end of the chain and expect certain output at the other end of the chain.  The number of chain links where it could be breaking down is too high, real time observability of the behavior of the data through the chain becomes necessary.  &lt;/p&gt;

&lt;p&gt;Unfortunately, observability seems to have a high overhead setup, so much so that it is usually relegated to the domains of large corporations, and adds a lot of overhead for individual engineers.  For example, I was interested in getting real time tracing and observability with AWS X-Ray, but even after setting it up for a reduced test case stack, it ended up not actually showing any live data, and I gave up on it because the overhead, not just the learning curve, seems to be too high to be an efficient use of time in standard use cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloudwatch Log Ease of Access
&lt;/h2&gt;

&lt;p&gt;Ok, so if observability may not be easily accessible, we have to fall back to monitoring (e.g. monitoring lambdas, since most custom code will be in the lambdas), and for that we need Cloudwatch.&lt;/p&gt;

&lt;p&gt;Now Cloudwatch logs have two problems.  out-of-time-order, and difficult findability.  &lt;/p&gt;

&lt;p&gt;The out-of-time-order problem is generally an interface problem. It is common to want to do X behavior in your app, and check for output Y in the cloudwatch logs.  However, because looking at a stream doesn't get you to the &lt;strong&gt;next&lt;/strong&gt; stream when a new lambda instance is created, you may never see your output Y when looking at a single log.  Since every lambda instance creates it's own stream, and you can't predict when a new lambda instance will spin up, whether for concurrency or because of an old instance being killed off, you can't predict where your logged information will appear.&lt;/p&gt;

&lt;p&gt;The way that logwatch is configured in the AWS console is... ...like a jigsaw puzzle that has been split apart.  Each stream is it's own separate peice, and (ironically), they don't flow into each-other.&lt;br&gt;
I can't tell you how many times I have been looking for a log output message to come through in log stream A... ...but it never will because a new stream B has been spun up in the meantime, and the log output is actually in stream B.&lt;/p&gt;

&lt;h3&gt;
  
  
  Log output findability is low
&lt;/h3&gt;

&lt;p&gt;The findability / search problem is just that searching cloudwatch log streams is not a very user friendly experience.  It's case &lt;strong&gt;sensitive&lt;/strong&gt; by default, for some reason, and the documentation on operators, well, there almost isn't any, so you're often limited to mostly knowing a priori the exact string that you need to find.&lt;br&gt;
For an egregious example, to trivially find all "Error", "ERROR" and "error" instances, none of these will get you all you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;error (1/3rd of results)&lt;/li&gt;
&lt;li&gt;ERROR (1/3rd of results)&lt;/li&gt;
&lt;li&gt;error ERROR Error (0 results because of exact matching)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The actual search terms and operators you need, after quite a bit of research, end up being along the lines of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;?error ?ERROR ?Error&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And good luck if your error is actually like ERR or something, because it's case sensitive.&lt;/p&gt;

&lt;p&gt;Frankly, even after all the time that I have been using cloudwatch logs, and getting used to the problems above,&lt;br&gt;
I still have no idea how other engineers are getting &lt;strong&gt;good&lt;/strong&gt; information out of lambda invocation logs.  I am still searching for some realtime log viewer &amp;amp; aggregator tool, so that I could just see some output pop up, in real time, whichever log stream it ends up in.&lt;/p&gt;

&lt;p&gt;These papercuts of cloudwatch are small, but because cloudwatch and monitoring are so core to everything, and how frequently you'll be looking at logs for so many scenarios - invocations, alarms, dynamo errors, even billing - those usability issues are going to be hitting constantly, probably daily.&lt;/p&gt;

&lt;h2&gt;
  
  
  Navigation
&lt;/h2&gt;

&lt;p&gt;Now, in a hypothetical monolith, if you have a problem, you generally know where to go to debug, you go to the &lt;strong&gt;application&lt;/strong&gt; (and it's server, and the infrastructure built by other people that runs that app), but crucially, because it's a monolith, it's generally all in the same place.  When running serverless, though, you have to collect together the &lt;strong&gt;services&lt;/strong&gt; and context switch between them.&lt;/p&gt;

&lt;p&gt;Again, with a monolith, it's all there, all in the same place.  The place is complex and intermingled, but hopefully you at least know where it is, it's on that server or whatever.&lt;br&gt;
With serverless, you have to navigate and metaphorically travel back and forth, between contexts and between services.  It can be disruptive to process to hop between Lambda, SQS, Alarms in cloudwatch, and Dynamo. So navigation becomes a key activity.&lt;br&gt;
Navigation &lt;em&gt;should&lt;/em&gt; be a smooth helper for moving between these things.  Navigation, through a good information architecture, should highlight the things that are likely to be &lt;strong&gt;most important&lt;/strong&gt; to the user, and &lt;strong&gt;deprioritize&lt;/strong&gt; those things that the user rarely uses.&lt;br&gt;
Here is what my current navigation in aws looks like, though:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flueziunwie15h1mf0aer.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flueziunwie15h1mf0aer.png" alt="manually favorited SERVICES in aws" width="800" height="29"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or on the homepage there is one other jumping-off point:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3qbwnfxyeiww6ir88i2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3qbwnfxyeiww6ir88i2.png" alt="Recently visited SERVICES" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, while services are great for engineering and putting together applications, they don't really work for &lt;em&gt;Navigation&lt;/em&gt;, for finding things.&lt;br&gt;
For example, I really don't want to navigate to the base case of AWS &lt;strong&gt;Lambda&lt;/strong&gt;, I want MY lambda functions that I was most recently working on.  I don't want the general category of DynamoBD, I just want to get back to the actual Chat table that I was most recently working on.  Because I had to context switch out to a different service, and now I am trying to get back into flow.&lt;/p&gt;

&lt;p&gt;The current navigation is very "flat". There are 100s of AWS services, and each is presented as if they were equally important to the current user.  Of course they aren't.  They can't be all equally important.  Manually favoriting and bookmarking services is one way to communicate a bit of priority, but the "services" really are never what I'm looking for anyway.  The services are like a whole herd of similar zebra, and I am searching for that one that I previously shot a tranquilizer dart into.&lt;/p&gt;

&lt;h2&gt;
  
  
  UI Hierarchy
&lt;/h2&gt;

&lt;p&gt;Traditional websites go to a ton of trouble to make it easy for me to get to the most useful thing that I want to do.  Especially when they are selling a product. "Oh, you're ordering seeds online again?  Let me make the [Buy This Seed] button 5 times bigger, with an image."  By contrast, with AWS services you are switching betweens concepts that are treated a bit too equally in terms of concept and navigation.  So that flat treatment of services makes serverless context switching that much more of a difficulty.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fixing the UI Hierarchy
&lt;/h3&gt;

&lt;p&gt;You can create an application and a resource group to gather up the pieces within a category that you are working on.  That is a very manual process.  What is really needed and desirable within the AWS UI is a landing page for people working in AWS where the most recently used resources (not just services) are continuously collected.  Last 5 viewed lambdas.  Last 5 viewed queues.  Mix the services together into a "last 10", so that returning to work on a serverless pieces is just 1 click away, and getting back to work is easy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Service Icons
&lt;/h3&gt;

&lt;p&gt;Finally, an anecdote about the AWS service icons:&lt;/p&gt;

&lt;p&gt;There is a joke that floats around the AWS community about a quiz you can take to try to show your knowledge of the 3d AWS service icons.  It's a fun little 5 minutes of satire rooted in a reality of using all the services: &lt;a href="https://news.ycombinator.com/item?id=17697366" rel="noopener noreferrer"&gt;https://news.ycombinator.com/item?id=17697366&lt;/a&gt;  I personally have memorized some of the icons as a way to quickly try to navigate, but is memorizing that really the best navigational aids we can have?&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>Building The ELF, a handcrafted-gift planning app, with AWS Bedrock</title>
      <dc:creator>Coco</dc:creator>
      <pubDate>Thu, 14 Dec 2023 03:52:05 +0000</pubDate>
      <link>https://forem.com/rrsai/building-the-elf-a-homeade-gift-planning-app-with-aws-bedrock-1ej4</link>
      <guid>https://forem.com/rrsai/building-the-elf-a-homeade-gift-planning-app-with-aws-bedrock-1ej4</guid>
      <description>&lt;p&gt;Are you as bad as me at coming up with gifts? Here's my contribution towards the holiday season. I call it The ELF, and briefly explain what led me to create and it how you can use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I really suck at coming up with gifts for my loved ones. I waaaannt to, because they're great, but I just never know what to do or how to do it. Does that sound like you to?  It is me. So I created an app which just for fun I have named "The Elf" where you can describe a loved one's hobbies and likes and dislikes and such, and the AI language model suggests crafts and other homemade things to create for them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Everyone, it has suggested some of the best gifts that I will have given in 30 years, things that are so obvious and yet so perfect for the people I put in; it blows New York Times gift recommendation posts out of the water, and it also blows my own personal gift brainstorming skills out of the water.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Why does it work well?  Because you know the person and the AI knows lots of approaches to creating homeade items written about across the web.  So it combines your personalized knowledge with the AI's broad knowledge into a personal result for your giftee.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it out:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://partyrock.aws/u/rrsai/uKbUrNenL/Homemade-Gift-Planner-Elf" rel="noopener noreferrer"&gt;Homemade Gift Planner Elf&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Converting a custom EC2 websockets chat to use serverless</title>
      <dc:creator>Coco</dc:creator>
      <pubDate>Thu, 20 Apr 2023 00:32:01 +0000</pubDate>
      <link>https://forem.com/rrsai/converting-a-custom-ec2-websockets-chat-to-use-serverless-24dg</link>
      <guid>https://forem.com/rrsai/converting-a-custom-ec2-websockets-chat-to-use-serverless-24dg</guid>
      <description>&lt;p&gt;I have been maintaining a custom, on-server websockets chat for about 5 years as part of the broader ninjawars.net web app.  Today, I got tired of maintaining the uptime of the chat server, and decided to move it over to some form of serverless backend.  So I decided to go through converting my custom EC2 server-based websockets chat over to the new(ish) apigateway serverless websockets, so I wouldn't have to keep the chat server "up" and the chat could still work. Here is what I found.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read time:&lt;/strong&gt; 3 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Development time:&lt;/strong&gt; 3 hours (your mileage may vary, much of mine was spent debugging AWS arn permissions :) )&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzsyr6igv6rzernrwtzqv.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzsyr6igv6rzernrwtzqv.jpeg" alt="Image description" width="800" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Findings first:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Don't handcode your websocket realtime chat, (except as a learning exercise for how to deal with other realtime websocket clients).  There are quite a few subtle obstacles that make a custom coded websocket finicky, and require custom coding. The one I ran into was the “ack” system needed to deal with keep alive. Otherwise the chat may experienced a loss of connection that the serverless websocket api gateway does after a time of inactivity, disconnecting the client.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/NinjaWars/ws-chat" rel="noopener noreferrer"&gt;The Repo with the chat tools&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have not yet extracted the aws lambda code down into that repository, nor converted the quick prototype over to something like aws cdk.  That may be a future exercise.&lt;/p&gt;

&lt;h2&gt;
  
  
  The path
&lt;/h2&gt;

&lt;p&gt;Ok, so what overall pieces are there to create a serverless realtime chat with websockets?&lt;/p&gt;

&lt;p&gt;AWS API Gateway's websockets api is relatively new, and due to the potential need to do "ack" (keepalive of the connection), it may be necessary to convert over to aws appsync in the future (see this article: &lt;a href="https://docs.aws.amazon.com/appsync/latest/devguide/real-time-websocket-client.html" rel="noopener noreferrer"&gt;full realtime websockets client via appsync&lt;/a&gt; ).  However, in the meantime I just spun up some custom resources: A dynamodb table, three lambdas, and an apigatway.  Oh, and I connected it up to my pre-existing domainname &lt;a href="http://chatapi.ninjawars.net" rel="noopener noreferrer"&gt;*.ninjawars.net&lt;/a&gt;.  &lt;strong&gt;Websockets is weird&lt;/strong&gt;.  It's like an echo chamber, you send a message and it broadcasts it out to the various connected client connections.&lt;/p&gt;

&lt;p&gt;Let's walk through a few of the necessary parts to get a quote unquote "simple" web chat up in a realtime way (without having to maintain a full EC2 server for the websocket)&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Create an API Gateway WebSocket API
&lt;/h2&gt;

&lt;p&gt;The first step is to create an API Gateway WebSocket API. To do this, navigate to the API Gateway console and select "Create API." Then, select "WebSocket API" and follow the prompts to create your API.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Create a Lambda Function or Three
&lt;/h2&gt;

&lt;p&gt;The next step is to create a Lambda function that will handle the WebSocket connections and messages. In my case, I used Node.js and the AWS SDK to handle the WebSocket connections and messages. I am using the guide here: &lt;a href="https://hackernoon.com/websockets-api-gateway-9d4aca493d39" rel="noopener noreferrer"&gt;websockets-api&lt;/a&gt; for the general websockets mechanism.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Configure the WebSocket Routes
&lt;/h2&gt;

&lt;p&gt;Once you have created your Lambda function, you need to configure the WebSocket route to use the Lambda function. To do this, navigate to the API Gateway console and select your WebSocket API. Then, select "Routes" and assign each route (&lt;code&gt;$connect&lt;/code&gt;, &lt;code&gt;$disconnect&lt;/code&gt;, and the custom "&lt;code&gt;onMessage&lt;/code&gt;", or perhaps just the fallback route of $default) to point at their respective lambdas. For the "Integration target," select your Lambda function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Deploy Your API
&lt;/h2&gt;

&lt;p&gt;After configuring your WebSocket route, you need to deploy your API to make it available for use. To do this, navigate to the API Gateway console and select your WebSocket API. Then, select "Actions" and "Deploy API." Follow the prompts to deploy your API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Test Your API from the lambdas and externally
&lt;/h2&gt;

&lt;p&gt;Once your API is deployed, you can test it using a WebSocket client.  I used the wscat command-line tool to test my API. You connect to the wss: url, then just paste in any arbitrary text, though probably it should in the end be a json object.&lt;/p&gt;

&lt;p&gt;I hear there are also browser-based clients such as the "Simple WebSocket Client" Chrome extension.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test Event For AWS Lambda
&lt;/h3&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;"requestContext"&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;"accountId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123456789012"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"resourceId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123456"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"domainName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"000000xxxx.execute-api.us-east-2.amazonaws.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;"stage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"production"&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;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;test from test event in aws console&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;uname&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;xxxxxxusername&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;date&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;1681948677627&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;sender_id&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;128274&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&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;h3&gt;
  
  
  Test message from client
&lt;/h3&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="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test from test event in aws console"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"uname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxxxxxusername"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1681948677627"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sender_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;"128274"&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;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Beware!&lt;/strong&gt;&lt;br&gt;
Because there is the assumption that websockets is the mechanism &lt;em&gt;for the realtime&lt;/em&gt;, there's a pitfall that you don't get any long-term storage out of it!  So if you want to show a "history" for the chat (and you do, trust me you do), then you have to have a separate backend source that will handle the posting, saving, and retrieving of the chats anyway, and that will need to be pulled from for the initial chat history.  So the websockets part of the chat is actually only half of the equation, a different api and database is needed for long-term storage of the chats that were sent in a non-realtime way.&lt;/p&gt;

&lt;p&gt;Overall, the reason I recommend going with a framework like amplify is because the complexity of getting it right in a bespoke way is pretty high.  The initial "prototype" is simple with a websockets serverless backend, plus some UI, but there are hidden gotchas that come up invisibly later, like the need to ack the connection, and handle reconnections to the websocket server.&lt;/p&gt;

&lt;p&gt;Even this minor task ("just create a realtime chat!") is actually much harder than it looks on the face of it.&lt;/p&gt;

</description>
      <category>websockets</category>
      <category>apigateway</category>
      <category>lambda</category>
    </item>
    <item>
      <title>Practical and pragmatic generic aria roles to use</title>
      <dc:creator>Coco</dc:creator>
      <pubDate>Tue, 17 Jan 2023 04:58:56 +0000</pubDate>
      <link>https://forem.com/rrsai/practical-and-pragmatic-generic-aria-roles-to-use-4ek6</link>
      <guid>https://forem.com/rrsai/practical-and-pragmatic-generic-aria-roles-to-use-4ek6</guid>
      <description>&lt;p&gt;It's sometimes difficult to pick an aria role, because they are defined vaguely.  Because an aria role is often used to define the purpose of a piece of an application, it often doesn't pin down what specifically the role is, the description hems and haws around the purpose, it provides the vague shape of a thing but not the specifics.  Roles are by nature vague.  For example, if a &lt;code&gt;role=button&lt;/code&gt; were exactly the same as &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; it would &lt;em&gt;actually be redundant&lt;/em&gt;, there would be no point in the role, we would just use &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;!  So the role descriptions are often more vague.&lt;/p&gt;

&lt;p&gt;This results in some difficulty:  How do we know what roles to use?  For example, try to avoid using &lt;code&gt;role=button&lt;/code&gt;.  Why?  Because you should use actual &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;s, and the actual buttons &lt;strong&gt;get for free&lt;/strong&gt; the role=button.&lt;/p&gt;

&lt;p&gt;So then what roles are actually, pragmatically useful when otherwise using html5?&lt;/p&gt;

&lt;p&gt;Well, as app authors, what we are often doing is setting priority.  We aren't just creating one &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; among thousands, it's a &lt;code&gt;&amp;lt;div role=region&amp;gt;&lt;/code&gt;.  It's not just a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;, it's a &lt;code&gt;&amp;lt;span role=comment&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So what roles are NOT given to us for free by a html5 element like  and &lt;a&gt; ( a role=link element), and work well for when we need to make generic elements more specific?&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;role=region&lt;/code&gt;&lt;/strong&gt; is a useful generic role to highlight an area&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;role=alert&lt;/code&gt;&lt;/strong&gt; applies to really high priority, transient things that come up and may go away after, things that elicit a response&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;role=status&lt;/code&gt;&lt;/strong&gt; for status updates, generally where the contents are going to update live&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;role=comment&lt;/code&gt;&lt;/strong&gt; for where it is people writing comment responses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;role=note&lt;/code&gt;&lt;/strong&gt; for separated text&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A huge majority of the remaining roles fall into two "try not to use" categories: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't use these because the role comes for free from the semantic html5 element: role=button, role=figure, role=code, etc&lt;/li&gt;
&lt;li&gt;Abstract roles (they exist, but are not intended for use with authorship)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  In Summary
&lt;/h2&gt;

&lt;p&gt;I sorted through the aria roles trying to find 2023's most useful generic roles.  For now, these are the most useful roles that I could find for authorship that aren't rendered redundant with other html5 builtins.&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>privacy</category>
      <category>selfhost</category>
      <category>welcome</category>
    </item>
    <item>
      <title>Using the software testing pyramid to capture high value with less effort</title>
      <dc:creator>Coco</dc:creator>
      <pubDate>Wed, 23 Nov 2022 22:57:48 +0000</pubDate>
      <link>https://forem.com/rrsai/using-the-software-testing-pyramid-to-capture-high-value-with-less-effort-56lg</link>
      <guid>https://forem.com/rrsai/using-the-software-testing-pyramid-to-capture-high-value-with-less-effort-56lg</guid>
      <description>&lt;h2&gt;
  
  
  Let's talk about how to stabilize a complex application, back to front.
&lt;/h2&gt;

&lt;p&gt;Recently I was working on a strategy to text a complex application, get some checks in place so that bugs in core processes would be caught before they could go live, even as I worked on the underlying systems (core creation and updating of information, generally).&lt;/p&gt;

&lt;p&gt;To put it another way, I kept on breaking my own core application functionality in weird ways while trying to make improvements.&lt;/p&gt;

&lt;p&gt;I can't tell you the number of times that I have had some core functionality (login, forgot password, the homepage, the first page a user sees) break and it took some time for me to catch it.  I have broken &lt;a href="http://ninjawars.net" rel="noopener noreferrer"&gt;http://ninjawars.net&lt;/a&gt; more times than I can count, over it's 19 years of being in existence.  Usually in totally new ways.&lt;/p&gt;

&lt;p&gt;So I wanted to get a check in place to try to prevent breakage, and get that check automated in the Continous Integration.&lt;/p&gt;

&lt;p&gt;Well, it is time to get some stability on this beast.  I built some unit tests via TDD while I was coding things, I created some basic integration tests run through python to check urls that are deployed in a local instance and check that they load.  What I needed now was some End-2-End tests, with a real, true browser involved.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Testing Pyramid
&lt;/h2&gt;

&lt;p&gt;Before I get into what I did, I just want to mention that my approach was informed by the testing pyramid:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj8kv90gfa4zr6vmr15z1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj8kv90gfa4zr6vmr15z1.jpg" alt="Testing Pyramid" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You have a lot of unit tests at the bottom, some integration tests in the middle, and fewer E2E tests at the top of the testing pyramid.&lt;/p&gt;

&lt;p&gt;Some people I have spoken to get a little too caught up in the pyramid metaphor and say "Ok, so you have to write lots of unit tests first, right?" but nah, don't get too hung up on it being a pyramid like the pyramid of giza.  Ironically the tiny tip of the pyramid (a few E2E tests) is more valuable than the wide base of the pyramid (lots of E2E tests).&lt;/p&gt;

&lt;h2&gt;
  
  
  DON'T GIVE IN, TEST FROM THE OUTSIDE IN!
&lt;/h2&gt;

&lt;p&gt;Don't give in, test from the outside in! By this I mean don't do what's easy and write a few unit tests and stop at the layer of unit tests (there are always more unit tests you &lt;strong&gt;could&lt;/strong&gt; write, so it's easy to get lost at the unit test stage).  Instead consider ignoring integration tests until you know you need them, delay unit tests later, just skip right to writing E2E tests first!  You can get a lot of stability value from working down from the top and up from the bottom, until you meet in the middle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cypress for E2E tests
&lt;/h3&gt;

&lt;p&gt;So I started to set up &lt;code&gt;cypress&lt;/code&gt; for E2E browser tests.  Modern, powerful, and integrates well with continuous integration.&lt;/p&gt;

&lt;p&gt;I ran through the core paths of the system, login, forgot password, player account profile, homepage and main page.&lt;/p&gt;

&lt;p&gt;E2E tests are actually nice for this because knowing how to use the app allows us to create tests.  We don't need as much to know how the infrastructure, the react components, the code itself is working, as long as we have a good sense of the &lt;strong&gt;behavior&lt;/strong&gt; of the app itself, and how we expect it to behave.  Also almost everyone is familiar with login, so testing a login page with E2E tests is highly familiar ground, a good place to start.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test Flow
&lt;/h3&gt;

&lt;p&gt;Homepage --&amp;gt; Login --&amp;gt; Main Page&lt;/p&gt;

&lt;p&gt;Login --&amp;gt; Main Page --&amp;gt; Profile Page&lt;/p&gt;

&lt;p&gt;Login --&amp;gt; Forgot Password&lt;/p&gt;

&lt;p&gt;Login --&amp;gt; Main Page --&amp;gt; Core Page&lt;/p&gt;

&lt;p&gt;This set of test flows for E2E tests cover a LOT of ground, if these pieces of your app are operational, at least people can get in and see your core functionality, and try to use it.  So these tests flows are high value.  Potentially much more valuable than testing 5-10 units of unit test functionality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Forment Revolution
&lt;/h3&gt;

&lt;p&gt;You don't have to do what they tell you.  Write your E2E tests first, do unit tests later, if you can.&lt;/p&gt;

&lt;p&gt;Just a brief final anecdote, I once worked at a company with &lt;strong&gt;thousands&lt;/strong&gt; of unit tests (it had a full QA team dedicated to creating unit tests)... ...and the app still kept breaking &lt;em&gt;because the app was much much more complex than the sum of it's units.&lt;/em&gt;  If your current tests aren't working for you, don't do more of the same, get some E2E tests in place.&lt;/p&gt;

&lt;p&gt;Thoughts on these ideas?&lt;/p&gt;

</description>
      <category>testingpyramid</category>
      <category>cypress</category>
      <category>e2etesting</category>
    </item>
    <item>
      <title>Moving an EC2 server Exim4 email to AWS Email systems</title>
      <dc:creator>Coco</dc:creator>
      <pubDate>Tue, 01 Nov 2022 03:44:17 +0000</pubDate>
      <link>https://forem.com/rrsai/moving-an-ec2-server-exim4-email-to-aws-email-systems-34me</link>
      <guid>https://forem.com/rrsai/moving-an-ec2-server-exim4-email-to-aws-email-systems-34me</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I have an EC2 server running in production that connects to &lt;br&gt;
Exim4 to send out emails, transactional and otherwise.&lt;/p&gt;

&lt;p&gt;AWS's recommendation for simplest email seems to essentially be "&lt;a href="https://docs.aws.amazon.com/pinpoint/latest/developerguide/send-messages-email.html#send-messages-email-choose-method" rel="noopener noreferrer"&gt;Use AWS SES instead of pinpoint&lt;/a&gt;".&lt;/p&gt;

&lt;h3&gt;
  
  
  Pieces
&lt;/h3&gt;

&lt;p&gt;Generally there are some email templates that have to be programmatically fed into the email system.&lt;/p&gt;

&lt;p&gt;An internal API has to be created to accept requests for sending out new transactional emails.  Implementation of this will be with an AWS lambda called first by local CLI, and later via an invocation event.&lt;/p&gt;

&lt;p&gt;Initially, manual whitelisting of addresses in SES will be done via the console while the SES is still in sandbox mode.&lt;/p&gt;

&lt;p&gt;Security checks need to be done to ensure email injection can not be done (there may be something that AWS SES will do to make email injection attackers less effective than Exim4, but that is always worth checking)&lt;/p&gt;

&lt;p&gt;Create unsubscribe link system, requiring a url on the main domain that accepts url-based unsubscribes in one action, and  adds the user to a blacklist&lt;/p&gt;

&lt;p&gt;Eventually, getting the AWS SES out of sandbox mode (here are some example rationales, though your milage may vary, these are just drafts).&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting out of SES sandbox mode
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;How do you plan to build or acquire your mailing list?&lt;/li&gt;
&lt;li&gt;- Users must opt in to receiving transactional emails after they create an account and provide an email address.  We do not cold-call/cold email users, they sign up and willingly provide their information.&lt;/li&gt;
&lt;li&gt;How do you plan to handle bounces and complaints?&lt;/li&gt;
&lt;li&gt;- Complaints: Complaints can just be forwarded through to the main contact email, and dealt with accordingly on a case-by-case basis.
&lt;/li&gt;
&lt;li&gt;- Bounces: Bounces are more complicated, and need an automated system to take out email addresses that bounce in real time.  To handle bounces, an SNS notification topic will be created, which triggers an AWS lambda to add the email to a do-not-send list and refrain from sending further emails to the bouncing address.&lt;/li&gt;
&lt;li&gt;How can recipients opt out of receiving email from you?&lt;/li&gt;
&lt;li&gt;- We provide a simple on-step unsubscribe link in clear, blue text in the footer of every email.  We also follow the structure that allows standard free email providers to use the one-click [Unsubscribe] button method.&lt;/li&gt;
&lt;li&gt;How did you choose the sending rate or sending quota that you specified in this request?&lt;/li&gt;
&lt;li&gt;- Currently there are XXX number of users in the system.  Only X% of them opt in to receiving emails.  We send a transactional email at the end of the day to those people who have opted in.  As a result, we expect to send XXX * 0.0X emails a day, * 31 for monthly numbers.  We also send out a monthly update email to those users who have opted in, thus adding another XXX * 0.0X emails per month.  Give a buffer of 120%, results in YYY emails per month as an upper bound.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...More on this process later...&lt;/p&gt;

&lt;p&gt;Useful references:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/@serbanmihai/how-to-handle-aws-ses-bounces-and-complaints-53d6e7455443" rel="noopener noreferrer"&gt;https://medium.com/@serbanmihai/how-to-handle-aws-ses-bounces-and-complaints-53d6e7455443&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/ses/latest/dg/send-email-exim.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/ses/latest/dg/send-email-exim.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/free-code-camp/sending-emails-with-amazon-ses-7617e83327b6" rel="noopener noreferrer"&gt;https://medium.com/free-code-camp/sending-emails-with-amazon-ses-7617e83327b6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/pinpoint/latest/developerguide/send-messages-email.html#send-messages-email-choose-method" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/pinpoint/latest/developerguide/send-messages-email.html#send-messages-email-choose-method&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>ses</category>
      <category>email</category>
    </item>
    <item>
      <title>Hacking a quick closed-source react static site in aws s3 and cloudfront, with a lambda helper</title>
      <dc:creator>Coco</dc:creator>
      <pubDate>Tue, 01 Nov 2022 03:05:48 +0000</pubDate>
      <link>https://forem.com/rrsai/hacking-a-quick-closed-source-react-static-site-in-aws-s3-and-cloudfront-with-a-lambda-helper-3n3o</link>
      <guid>https://forem.com/rrsai/hacking-a-quick-closed-source-react-static-site-in-aws-s3-and-cloudfront-with-a-lambda-helper-3n3o</guid>
      <description>&lt;p&gt;We all know about deploying a static react build to an aws s3 bucket.  We can build a react site, e.g. &lt;code&gt;npm run build&lt;/code&gt; and get an output directory, which we can then serve as a static site, &lt;code&gt;npx serve ./build&lt;/code&gt; for example.&lt;/p&gt;

&lt;p&gt;What is the fasted robust site we can hack together easily ourselves, before we go to third-party services like vercel, netlify, and surge.sh (for instance if you are working for a company that does not want to use out-of-aws third-parties for infrastructure) ? A bucket+cloudfront site is a good option.  I have been running nigh unbreakdable cloudfront sites that have been up for years without complaint and almost zero maintenance. One caveat is that keeping the caching settings and invalidations correct initially is tricky, cloudfront caches at the edge really really well, so we might want to automate invalidation of the / root for ourselves.  &lt;/p&gt;

&lt;p&gt;This is where we can have a little fun by using a lambda to automatically trigger on changes to the bucket assets, leaving us with a dead-simple, copy-and-paste - from local folder to bucket - deploy process.&lt;/p&gt;

&lt;p&gt;So the first step step is to create a bucket &amp;amp; upload the files to it e.g. &lt;code&gt;aws s3 sync ./build s3://your-bucket-name&lt;/code&gt;, and then we want a robust and wont-cost-much site DNS, which we can do relatively fast using cloudfront:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creating a cloudfront distribution&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Set the error pages of the cloudfront distribution to point error 404 at /index.html, error 403 at /index.html, so that the react app can route all urls that don't have static assets at them to the main index page.  Set the path at / to have a caching policy of no-cache, must-revalidate, so that people hitting the site will always get a fresh / root result, but we can more aggressively cache other assets because they will get invalidated when we push up.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Creating a lambda watcher to invalidate on bucket changes: &lt;a href="https://gist.github.com/supinf/e66fd36f9228a8701706" rel="noopener noreferrer"&gt;https://gist.github.com/supinf/e66fd36f9228a8701706&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Trigger the lambda on bucket changes.&lt;br&gt;
S3 is one of the standard triggers for a lambda function, so you can set S3 changes to trigger the lambda invocation.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjkbb88ft5mjqeryj8a7x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjkbb88ft5mjqeryj8a7x.png" alt="Add AWS lambda trigger" width="510" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64dbelrlzm7sbkdp323q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64dbelrlzm7sbkdp323q.png" alt="Set up your bucket changes to trigger the lambda" width="800" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;s3 -&amp;gt; lambda -&amp;gt; cloudfront&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the first stage of development, you may want to wrap the cloudfront distribution behind a WAF (or WAF2, whatever) so you can control who has access to it while you are doing rapid development.  If you don't care who sees or hits the site, skip the WAF, with cloudfront I find you'll rarely need it, your site will be so stable.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Deploy via CI
&lt;/h2&gt;

&lt;p&gt;Because the infrastructure itself will handle the cache invalidation, your CI can simply be responsible for building the assets.  In the beginning this could be as simple as having an index.html with hello world in it or you could skip right to react and &lt;code&gt;npm run build&lt;/code&gt; and a github action that runs &lt;code&gt;cp ./src/* ./build&lt;/code&gt; and then &lt;code&gt;aws s3 sync ./build  s3://your-bucket-name-here/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;(You will have to add an aws token secret to your github secrets to allow github action to upload to the bucket)&lt;/p&gt;

</description>
      <category>react</category>
      <category>cloudfront</category>
      <category>staticdeploy</category>
    </item>
    <item>
      <title>A diagram of the constellation of useful UI libraries</title>
      <dc:creator>Coco</dc:creator>
      <pubDate>Thu, 11 Aug 2022 04:33:00 +0000</pubDate>
      <link>https://forem.com/rrsai/a-diagram-of-the-constellation-of-useful-ui-libraries-29og</link>
      <guid>https://forem.com/rrsai/a-diagram-of-the-constellation-of-useful-ui-libraries-29og</guid>
      <description>&lt;p&gt;When refactoring a frontend, it can be useful to have a "toolbelt" of different libraries to move from a complex set of html/css to - for example - react or cleaner css principles.  CSS is especially problematic to refactor because of how it cascades to other parts of an app. &lt;/p&gt;

&lt;p&gt;Here are a few tools worth considering:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyjcrzbt5b6moy7unqar6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyjcrzbt5b6moy7unqar6.png" alt="constellation of UI libraries" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>favoriteuilibraries</category>
    </item>
  </channel>
</rss>
