<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jorge Contreras</title>
    <description>The latest articles on DEV Community by Jorge Contreras (@jorgecontreras).</description>
    <link>https://dev.to/jorgecontreras</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%2F1273188%2F1a58b5a6-4bcf-4aac-b9d9-09910349696c.jpeg</url>
      <title>DEV Community: Jorge Contreras</title>
      <link>https://dev.to/jorgecontreras</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jorgecontreras"/>
    <language>en</language>
    <item>
      <title>Understanding MCP Servers: The Model Context Protocol Explained</title>
      <dc:creator>Jorge Contreras</dc:creator>
      <pubDate>Fri, 09 May 2025 14:01:39 +0000</pubDate>
      <link>https://dev.to/jorgecontreras/understanding-mcp-servers-the-model-context-protocol-explained-150j</link>
      <guid>https://dev.to/jorgecontreras/understanding-mcp-servers-the-model-context-protocol-explained-150j</guid>
      <description>&lt;p&gt;As AI technologies continue to evolve, developers are constantly seeking ways to enhance and streamline interactions with large language models (LLMs). One significant advancement in this space is the Model Context Protocol (MCP), &lt;a href="https://www.anthropic.com/news/model-context-protocol" rel="noopener noreferrer"&gt;recently&lt;/a&gt; introduced by Anthropic, and its implementation through MCP servers. In this article, I'll share my findings and experiences with MCP servers, exploring what they are, why they matter, and how you can get started with them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Model Context Protocol?
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://modelcontextprotocol.io/introduction" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt; (MCP) is a standardized communication protocol that defines how applications interact with language models while efficiently managing context. It was designed to address the limitations of traditional API interactions with LLMs, particularly around context management.&lt;/p&gt;

&lt;p&gt;The protocol enables developers to create applications that can have more natural, ongoing conversations with AI models without constantly hitting context limitations.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an MCP Server?
&lt;/h2&gt;

&lt;p&gt;An MCP server is a specialized server that implements the Model Context Protocol, designed to enhance interactions with LLMs by managing contextual information more efficiently. In essence, it serves as a middleware between your application and language models, providing optimized context handling, memory management, and state persistence across interactions.&lt;/p&gt;

&lt;p&gt;Unlike traditional API calls to language models where context is handled within each request, an MCP server maintains context as a first-class citizen, allowing for more sophisticated and efficient AI interactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Would I Need an MCP Server?
&lt;/h2&gt;

&lt;p&gt;The need for MCP servers arises from several limitations in standard LLM interactions. Here is a comparison between traditional LLM calls and MCP Server Approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  Traditional LLM Calls 🆚 MCP Server Approach
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Traditional LLM API Calls&lt;/th&gt;
&lt;th&gt;MCP Server Approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Context Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manually append full history; prone to overflows&lt;/td&gt;
&lt;td&gt;Context is intelligently summarized and pruned by the server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory Efficiency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sends entire conversation each time&lt;/td&gt;
&lt;td&gt;Only sends what's relevant, with long-term memory persistence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost Optimization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High token usage due to repeated context&lt;/td&gt;
&lt;td&gt;Reduced tokens via smart context windows and state reuse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Enhanced Functionality&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited to basic Q&amp;amp;A or single-turn logic&lt;/td&gt;
&lt;td&gt;Supports retrieval-augmented generation, tool use, and multi-turn sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Consistent Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Degrades with long interactions or context resets&lt;/td&gt;
&lt;td&gt;Maintains consistent response quality via controlled context&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you're building applications that require ongoing conversations with AI models, persistent memory, or sophisticated context management, an MCP server could be invaluable to your architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes a Server an MCP Server?
&lt;/h2&gt;

&lt;p&gt;A server becomes an MCP server when it implements the Model Context Protocol &lt;a href="https://modelcontextprotocol.io/specification/2025-03-26" rel="noopener noreferrer"&gt;specifications&lt;/a&gt;. Key characteristics include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Context Management&lt;/strong&gt;: Implements strategies for context maintenance, summarization, and relevance determination.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protocol Implementation&lt;/strong&gt;: Adheres to the MCP API specifications for communication with clients.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State Persistence&lt;/strong&gt;: Maintains conversation state across multiple interactions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory Management&lt;/strong&gt;: Implements strategies for what to remember, summarize, or forget.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Message Routing&lt;/strong&gt;: Efficiently routes messages between clients and language models.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional Features&lt;/strong&gt;: May include retrieval-augmented generation, tool use, or other enhanced capabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The core differentiator is the server's implementation of the protocol's standards for handling context as a managed resource rather than merely passing messages.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Company or Organization is Behind It?
&lt;/h2&gt;

&lt;p&gt;The Model Context Protocol was created by Anthropic, the AI research company behind the Claude language model. They introduced MCP to provide developers with a standardized way to build applications that could more effectively maintain conversations with their AI models.&lt;/p&gt;

&lt;p&gt;Anthropic has made the MCP specification open for implementation, encouraging the development of various server implementations and client libraries across the ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the Known Limitations of MCP Servers?
&lt;/h2&gt;

&lt;p&gt;Despite their advantages, MCP servers do have several limitations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Implementation Complexity&lt;/strong&gt;: Setting up and maintaining an MCP server requires more infrastructure than simple API calls.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Latency Concerns&lt;/strong&gt;: The additional processing layer can introduce latency in some implementations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resource Requirements&lt;/strong&gt;: Running an MCP server requires additional computational resources compared to direct API calls.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Standardization Challenges&lt;/strong&gt;: As the protocol evolves, different implementations may support different feature sets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Model Compatibility&lt;/strong&gt;: Not all language models are fully optimized for MCP-style interactions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security Considerations&lt;/strong&gt;: Persistent state management introduces additional security concerns regarding data storage and access.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost Structure&lt;/strong&gt;: While potentially reducing token usage, running the server itself adds operational costs.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These limitations don't diminish the value of MCP servers but are important considerations when deciding whether to implement one in your AI architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Are There Similar Alternatives That Solve the Same Kind of Problem?
&lt;/h2&gt;

&lt;p&gt;Several alternatives address similar context management challenges:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.llamaindex.ai/" rel="noopener noreferrer"&gt;LlamaIndex&lt;/a&gt;&lt;/strong&gt;: Offers advanced retrieval and indexing capabilities for managing context with LLMs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Custom RAG Solutions&lt;/strong&gt;: Many teams build custom retrieval-augmented generation systems that manage context through vector databases.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Context Compression Techniques&lt;/strong&gt;: Some solutions focus on compressing context rather than managing it through a protocol.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Function Calling Frameworks&lt;/strong&gt;: Frameworks that orchestrate complex interactions between models and tools.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  🛠️ Function Calling Frameworks for LLMs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Framework / Tool&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Ecosystem&lt;/th&gt;
&lt;th&gt;Good For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OpenAI Function Calling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Native support for structured function execution via JSON schema&lt;/td&gt;
&lt;td&gt;OpenAI API&lt;/td&gt;
&lt;td&gt;Simple apps, single-agent LLM + tools setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LangChain&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Python/JS framework to build chains, tools, and autonomous agents with function calling&lt;/td&gt;
&lt;td&gt;Open-source&lt;/td&gt;
&lt;td&gt;Agent workflows, tool orchestration, RAG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Semantic Kernel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Microsoft’s SDK for building AI copilots using plugins, skills, and memory&lt;/td&gt;
&lt;td&gt;Microsoft / Azure&lt;/td&gt;
&lt;td&gt;Enterprise apps, plugin-based agent design&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AutoGen&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi-agent system framework from Microsoft for LLM collaboration&lt;/td&gt;
&lt;td&gt;Open-source (MS Research)&lt;/td&gt;
&lt;td&gt;Agent collaboration, task decomposition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CrewAI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Orchestrates LLM agents as a “crew,” each with a role and tools&lt;/td&gt;
&lt;td&gt;Open-source&lt;/td&gt;
&lt;td&gt;Role-based multi-agent workflows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Google Vertex AI Extensions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Allows function/tool integration in Vertex AI models (tools like web search, APIs)&lt;/td&gt;
&lt;td&gt;Google Cloud Platform&lt;/td&gt;
&lt;td&gt;GCP-native AI tool chaining&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hugging Face Transformers Agents&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tool-using agents powered by Hugging Face pipelines&lt;/td&gt;
&lt;td&gt;Hugging Face&lt;/td&gt;
&lt;td&gt;Open-source experimentation, local models&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The main difference is that MCP represents a standardized protocol specifically designed for context management, while many alternatives are frameworks or techniques that can be used to implement similar functionality but lack the standardization benefits.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Can I See an MCP Server in Action?
&lt;/h2&gt;

&lt;p&gt;To experience an MCP server firsthand, you can take a look at these amazing resources:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/modelcontextprotocol/servers" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;br&gt;
&lt;a href="https://mcp.so/" rel="noopener noreferrer"&gt;MCP.so&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To get a quick feel for it, I recommend starting with a simple local implementation that connects to a model you already have access to, such as Claude via Anthropic's API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can I Build My Own MCP Server and What Would I Need?
&lt;/h2&gt;

&lt;p&gt;Yes, you can build your own MCP server with the following requirements:&lt;/p&gt;

&lt;h3&gt;
  
  
  Technical Requirements:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Programming Knowledge&lt;/strong&gt;: Familiarity with a language suitable for server implementation (Python is common).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;API Access&lt;/strong&gt;: Access to an LLM API (Anthropic's Claude, OpenAI's GPT, etc.). Or if you prefer to run the LLM locally you should definitely checkout &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;ollama&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Server Environment&lt;/strong&gt;: A system to host your server (can be local for development).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Database&lt;/strong&gt;: For persistent storage of conversation history and context (PostgreSQL, MongoDB, etc.).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Understanding of Protocol&lt;/strong&gt;: Familiarity with the MCP specification.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Implementation Steps:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Start with one of the reference implementations or starter repositories.&lt;/li&gt;
&lt;li&gt;Set up your development environment and dependencies.&lt;/li&gt;
&lt;li&gt;Configure your model API credentials.&lt;/li&gt;
&lt;li&gt;Implement the core protocol endpoints.&lt;/li&gt;
&lt;li&gt;Add context management strategies based on your use case.&lt;/li&gt;
&lt;li&gt;Test with simple client applications.&lt;/li&gt;
&lt;li&gt;Optimize for your specific requirements.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Building a basic MCP server can be accomplished in a weekend for experienced developers, but creating a production-ready implementation with advanced features will require more significant investment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Links
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.anthropic.com/news/model-context-protocol" rel="noopener noreferrer"&gt;https://www.anthropic.com/news/model-context-protocol&lt;/a&gt;&lt;br&gt;
&lt;a href="https://modelcontextprotocol.io/introduction" rel="noopener noreferrer"&gt;https://modelcontextprotocol.io/introduction&lt;/a&gt;&lt;br&gt;
&lt;a href="https://mcp.so/" rel="noopener noreferrer"&gt;https://mcp.so/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.serverless.com/framework/docs/guides/mcp" rel="noopener noreferrer"&gt;https://www.serverless.com/framework/docs/guides/mcp&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/modelcontextprotocol/servers" rel="noopener noreferrer"&gt;https://github.com/modelcontextprotocol/servers&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>systemdesign</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Building AWS Lambda Functions</title>
      <dc:creator>Jorge Contreras</dc:creator>
      <pubDate>Sun, 23 Mar 2025 15:58:57 +0000</pubDate>
      <link>https://dev.to/aws-builders/building-aws-lambda-functions-ogb</link>
      <guid>https://dev.to/aws-builders/building-aws-lambda-functions-ogb</guid>
      <description>&lt;h1&gt;
  
  
  From your Local to the Cloud
&lt;/h1&gt;

&lt;p&gt;Building software is one of the most rewarding creative activities you can do. One the reasons I love building tech solutions is that you can create awesome stuff with little resources. But building is not always straightforward. The process of creating a great piece of software involves testing, a lot. &lt;/p&gt;

&lt;p&gt;In order to build something that solves a real problem and becomes robust, it needs to go through a lot of changes, adjustments, improvements and tuning. For this reason, it is crucial to have a quick and easy way to make changes and see the result as fast as possible. Developing locally reduces this feedback loop and you can iterate faster. &lt;/p&gt;

&lt;p&gt;Now enter AWS Lambda. Suddenly, testing locally isn't so simple anymore. Your code is running in the cloud, inside an AWS-managed environment that you don't control. And if your Lambda interacts with other AWS services like S3, DynamoDB, or API Gateway, things get even trickier.&lt;/p&gt;

&lt;p&gt;I ran into this problem recently while working on a project, and I had to dig deep to find a good local testing approach. If you're struggling with this too, let me save you some time and share what I've learned.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, How Do You Test AWS Lambda Locally?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option 1: AWS SAM – The Official Way
&lt;/h3&gt;

&lt;p&gt;My first stop was &lt;a href="https://aws.amazon.com/serverless/sam/" rel="noopener noreferrer"&gt;AWS SAM&lt;/a&gt; (Serverless Application Model), which is AWS's official tool for local development. With SAM, you can invoke a Lambda function on your machine using sam local invoke, or even spin up a local API Gateway using sam local start-api. This means you can test API calls before deploying to AWS, which is super useful.&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%2F9gtt67tt5a7j089u3g2s.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%2F9gtt67tt5a7j089u3g2s.png" alt="Image description" width="460" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But there's a catch. Since SAM relies on Docker to simulate the AWS environment, it can feel a bit heavy at times. Plus, setting it up can take a while if you're new to it. Still, if you want an AWS-supported way to test locally, SAM is a solid option.&lt;/p&gt;

&lt;p&gt;If you are interested in learning more about this approach, I would recommend to watch this &lt;a href="https://www.youtube.com/watch?v=mhdX4znMd2Q" rel="noopener noreferrer"&gt;awesome tutorial&lt;/a&gt;, where Jonathan goes through the whole development and deployment cycle.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/mhdX4znMd2Q"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 2: LocalStack – Running AWS on Your Machine
&lt;/h3&gt;

&lt;p&gt;Then I came across &lt;a href="https://www.localstack.cloud/" rel="noopener noreferrer"&gt;LocalStack&lt;/a&gt;, which is basically a fully emulated AWS environment that runs entirely on your local machine. This approach is quite interesting. If your Lambda function interacts with S3, DynamoDB, or SQS, you can test everything without even touching AWS.&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%2Fxqlqjji3705pcki0e3gc.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%2Fxqlqjji3705pcki0e3gc.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I spun up LocalStack, deployed my Lambda, and boom! my function was running locally as if it were in the cloud. But again, there's a tradeoff. The free version has some limitations, and running a full AWS-like environment locally can be resource-intensive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 3: AWS Lambda Runtime Interface Emulator
&lt;/h3&gt;

&lt;p&gt;Another option I explored was the &lt;a href="https://github.com/aws/aws-lambda-runtime-interface-emulator" rel="noopener noreferrer"&gt;AWS Lambda Runtime Interface Emulator&lt;/a&gt;. This is an official AWS tool that lets you run Lambda inside a Docker container, mimicking the AWS runtime. It's particularly useful if you're deploying container-based Lambdas.&lt;/p&gt;

&lt;p&gt;While this was helpful, I found that for most of my use cases, I didn't need to go that deep. If you're working with Lambda containers, though, this is worth checking out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 4: The Good Old Mocking Approach
&lt;/h3&gt;

&lt;p&gt;Sometimes, the simplest solution is the best one. Instead of running a full AWS stack locally, I started writing unit tests with mocked AWS SDK responses. Using tools like moto (for Python) or aws-sdk-mock (for Node.js), I could simulate DynamoDB, S3, and other AWS services without spinning up anything locally.&lt;/p&gt;

&lt;p&gt;This approach made my tests run way faster, and it worked great for logic validation. Of course, it didn't fully replace integration testing, but for quick feedback, it was a lifesaver.&lt;/p&gt;

&lt;h3&gt;
  
  
  So, What’s the Best Approach?
&lt;/h3&gt;

&lt;p&gt;Honestly, there's no one-size-fits-all solution. For me, a combination of AWS SAM for local execution and unit tests with mocks gave me the best of both worlds. I could run real-world tests when needed but still keep my feedback loop fast.&lt;/p&gt;

&lt;p&gt;I'm curious: how do you test your Lambda functions locally? Are you using one of these methods, or do you have a different approach? Let's chat in the comments! 🚀&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>cloud</category>
      <category>aws</category>
    </item>
    <item>
      <title>AWS Lambda Performance Tuning: How to Reduce Cold Starts</title>
      <dc:creator>Jorge Contreras</dc:creator>
      <pubDate>Wed, 12 Mar 2025 21:52:59 +0000</pubDate>
      <link>https://dev.to/aws-builders/aws-lambda-performance-tuning-how-to-reduce-cold-starts-44p9</link>
      <guid>https://dev.to/aws-builders/aws-lambda-performance-tuning-how-to-reduce-cold-starts-44p9</guid>
      <description>&lt;p&gt;Hey fellow builders! If you've worked with AWS Lambda, you've probably run into cold starts. Yes! those annoying delays when your function spins up after being idle. While AWS is great at handling infrastructure for us, cold starts can slow things down, especially for latency-sensitive apps.&lt;/p&gt;

&lt;p&gt;So, how do we reduce them? Let's dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a cold start? 🥶
&lt;/h2&gt;

&lt;p&gt;When a Lambda function is invoked after being idle, AWS needs to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spin up a new execution environment&lt;/li&gt;
&lt;li&gt;Load your function’s code&lt;/li&gt;
&lt;li&gt;Initialize dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This whole process takes milliseconds to seconds, which might not seem like much, but it's an eternity from the user's perspective. As customer-obsessed builders, we cannot let that be!&lt;/p&gt;

&lt;h2&gt;
  
  
  Ok so, cold starts are bad. What can we do about it?
&lt;/h2&gt;

&lt;p&gt;As with any cloud computing challenge, there are multiple approaches, each with its own trade-offs. Let's explore a few ideas, one of them might be the perfect fit for your use case.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Provisioned concurrency.
&lt;/h3&gt;

&lt;p&gt;This is the most straightforward solution. AWS introduced &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/provisioned-concurrency.html" rel="noopener noreferrer"&gt;Provisioned Concurrency&lt;/a&gt; to keep function instances warm. It preloads execution environments so your function is ready to go instantly. It is perfect for low-latency, high traffic workloads. However, it will incur an extra cost, so keep that in mind.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Optimize Function Memory &amp;amp; CPU.
&lt;/h3&gt;

&lt;p&gt;Finding the right balance between the allocated resources should be an art form. You can experiment and make adjustments based on observations. Luckily, there are awesome folks out there who have paved the way for us. Checkout this &lt;a href="https://github.com/alexcasalboni/aws-lambda-power-tuning" rel="noopener noreferrer"&gt;AWS Lambda Power Tuning tool&lt;/a&gt;. In &lt;a href="https://www.youtube.com/watch?v=QUJ_Govd0CQ" rel="noopener noreferrer"&gt;this video&lt;/a&gt;, Daniel clearly explains how to use it.&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%2F9yjk64b94ze2ih1ah2hs.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%2F9yjk64b94ze2ih1ah2hs.png" alt="Image description" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Keep your deployment package small.
&lt;/h3&gt;

&lt;p&gt;AWS &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/chapter-layers.html" rel="noopener noreferrer"&gt;Lambda layers&lt;/a&gt; let you package dependencies separately from your function code. Instead of bundling large libraries (like bcrypt or Puppeteer) inside your deployment package, you can put them in a layer and reference them in multiple functions.&lt;/p&gt;

&lt;p&gt;✅ Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smaller function size (faster cold starts 🚀)&lt;/li&gt;
&lt;li&gt;Easier updates (update the layer instead of redeploying everything)&lt;/li&gt;
&lt;li&gt;Code reuse (share layers across multiple Lambdas)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example: A Node.js layer with dependencies&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a nodejs folder and install packages inside it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p nodejs &amp;amp;&amp;amp; cd nodejs
npm install sharp
cd ..
zip -r layer.zip nodejs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upload layer.zip to AWS Lambda as a new layer and add the layer to your Lambda function in the AWS Console or using AWS CLI.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Avoid Heavy Initialization.
&lt;/h3&gt;

&lt;p&gt;A common mistake in Lambda development is initializing database connections or loading heavy dependencies inside the handler. This slows down every invocation! Instead, move initialization outside the handler so that it runs only once per execution environment.&lt;/p&gt;

&lt;p&gt;❌ Don't do this! (DB connection inside the handler)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MongoClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mongodb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MongoClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MONGO_URI&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Establishes a new connection on every invocation ❌&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mydb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Do this! (Persistent DB connection &amp;amp; Lazy Loading)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MongoClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mongodb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Store DB connection outside the handler&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getDBClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MongoClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MONGO_URI&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dbClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getDBClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dbClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mydb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;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%2F9lmi62k9ipfhi3gh639i.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%2F9lmi62k9ipfhi3gh639i.jpg" alt="Image description" width="800" height="718"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is this better?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The connection is reused across multiple invocations.&lt;/li&gt;
&lt;li&gt;Lazy loading (&lt;code&gt;getDBClient()&lt;/code&gt;) ensures the connection initializes only when needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Warmers
&lt;/h3&gt;

&lt;p&gt;A warmer is a simple mechanism that sends a request to your Lambda function at regular intervals, preventing it from being idle. It's like giving your lambda a nudge just to keep it awake. You can use CloudWatch Events to run the warmer call every 5 minutes, for example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Cold starts are annoying but manageable with the right strategies. If you need instant response times, Provisioned Concurrency is your best bet. Otherwise, keeping things lightweight, optimizing resources, and using warmers can make a big difference. Your users will thank you.&lt;/p&gt;

&lt;p&gt;What tricks have worked for you? Drop your thoughts in the comments! 💬👇&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>aws</category>
      <category>cloud</category>
    </item>
    <item>
      <title>AWS Machine Learning Certified? Let’s Do This!</title>
      <dc:creator>Jorge Contreras</dc:creator>
      <pubDate>Fri, 07 Feb 2025 13:00:00 +0000</pubDate>
      <link>https://dev.to/jorgecontreras/aws-machine-learning-certified-lets-do-this-4g1c</link>
      <guid>https://dev.to/jorgecontreras/aws-machine-learning-certified-lets-do-this-4g1c</guid>
      <description>&lt;p&gt;Whether you're a seasoned machine learning pro or someone just starting to dip your toes into the field, the &lt;strong&gt;AWS Certified Machine Learning - Specialty&lt;/strong&gt; exam is a whole different beast. AWS offers an incredible array of ML tools and services—but figuring out how they all fit together can feel overwhelming.&lt;/p&gt;

&lt;p&gt;With the vast amount of available material, figuring out what's truly important versus what's just "nice to know" feels like a puzzle in itself.&lt;/p&gt;

&lt;p&gt;In this series, I'll break things down step-by-step, cutting through the noise and focusing on what really matters for the exam. Let's create a roadmap together that makes tackling this certification feel manageable, not overwhelming.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Certification?
&lt;/h2&gt;

&lt;p&gt;AWS certifications are more than just badges of honor; they're proof that you know your stuff. But why did I pick the Machine Learning - Specialty exam out of all the AWS certifications? A few reasons:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Machine Learning is everywhere:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ML is shaping everything—from personalized recommendations to autonomous cars. This certification is a chance to dive into AWS's take on it and how they power real-world ML solutions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-World Impact:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AWS isn't just for passing exams. It's a powerful ecosystem used in production systems across industries. Mastering these tools gives you an edge in delivering scalable, secure, and effective ML solutions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Career Edge:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Whether you're a data scientist, engineer, or just curious about ML, this certification proves you're ready to take on complex ML challenges. It's a way to stand out in a competitive field.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hands-On Fun:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Certifications aren't just about theory—they push you to use tools, services, and techniques that you might not have explored otherwise. And trust me, there's nothing more satisfying than spinning up a SageMaker model that actually works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Joining the Community:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the most underrated perks of getting certified is the community. AWS certifications are a conversation starter—they're a way to connect with like-minded people who share your passion for machine learning and cloud technologies. Whether it's at meetups, on forums, or through LinkedIn, being certified signals to others that you speak the same language and are serious about your craft.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Need to Know Before Starting
&lt;/h2&gt;

&lt;p&gt;The certification is a journey, you should take your time and be patient. Here's what helps to have under your belt:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fundamental ML Concepts:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Familiarize yourself with the following concepts and algorithms: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linear Regression&lt;/li&gt;
&lt;li&gt;Logistic Regression&lt;/li&gt;
&lt;li&gt;Decision trees&lt;/li&gt;
&lt;li&gt;Clustering (K-means)&lt;/li&gt;
&lt;li&gt;Gradient Boosting&lt;/li&gt;
&lt;li&gt;Random Forest&lt;/li&gt;
&lt;li&gt;K-nearest neighbors (KNN)&lt;/li&gt;
&lt;li&gt;Support Vector Machines&lt;/li&gt;
&lt;li&gt;Neural Networks&lt;/li&gt;
&lt;li&gt;Convolutional Neural Networks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Python Skills:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Many AWS ML tools lean on Python, so familiarity with the language is essential. Bonus points if you've dabbled in libraries like Pandas, NumPy, or Scikit-learn.&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%2F7vzcd4julqxcq2xphqkm.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%2F7vzcd4julqxcq2xphqkm.png" alt="Image description" width="691" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS Basics:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you've set up an S3 bucket or launched an EC2 instance before, you're already ahead. Understanding IAM roles, permissions, and basic cloud concepts will help.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Series Will Cover
&lt;/h2&gt;

&lt;p&gt;I've planned this series to be your friendly guide through the topics you'll need to master. Expect posts on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Core AWS ML services like SageMaker, Rekognition, Polly, and more.&lt;/li&gt;
&lt;li&gt;How to process and prepare data for ML models on AWS.&lt;/li&gt;
&lt;li&gt;Tips for training, tuning, and deploying models.&lt;/li&gt;
&lt;li&gt;Insights from my own study process and hands-on labs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of this as part blog, part study group, and part diary of my experience. If you're on the same journey or thinking about it, feel free to share your thoughts, questions, or tips in the comments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's Next?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the next post, we'll dive into the heart of AWS ML: SageMaker. We'll break down what it is, why it's so powerful, and how you can start using it right away.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Thoughts:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you've been waiting for the right time to get started, this is your sign. AWS Machine Learning certification isn't just a test—it's a chance to level up your skills and explore a fascinating field. &lt;/p&gt;

&lt;p&gt;Ready? Let’s do this together!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>certification</category>
      <category>machinelearning</category>
      <category>cloudnative</category>
    </item>
    <item>
      <title>Kubernetes CRDs: The Backbone of Kubernetes Extensibility</title>
      <dc:creator>Jorge Contreras</dc:creator>
      <pubDate>Tue, 03 Dec 2024 13:01:00 +0000</pubDate>
      <link>https://dev.to/jorgecontreras/kubernetes-crds-the-backbone-of-kubernetes-extensibility-pha</link>
      <guid>https://dev.to/jorgecontreras/kubernetes-crds-the-backbone-of-kubernetes-extensibility-pha</guid>
      <description>&lt;p&gt;Kubernetes is a highly extensible platform, and at the core of its extensibility lies the concept of &lt;strong&gt;Custom Resource Definitions (CRDs)&lt;/strong&gt;. CRDs empower developers to extend Kubernetes' capabilities by creating custom resource types that operate just like native Kubernetes objects. In this article, we’ll explore what CRDs are, why they’re important, and highlight some real-world examples of how they’re used.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are CRDs (Custom Resource Definitions)?
&lt;/h2&gt;

&lt;p&gt;Kubernetes is already packed with built-in resources like &lt;code&gt;Pod&lt;/code&gt;, &lt;code&gt;Deployment&lt;/code&gt;, and &lt;code&gt;Service&lt;/code&gt;. But what if you need to manage something Kubernetes doesn’t natively understand—like a database, an application workflow, or a set of cloud resources?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enter CRDs!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A CRD lets you create and manage custom resource types, allowing Kubernetes to recognize and handle them just like its native objects. By registering a CRD in your cluster, you’re essentially saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Hey Kubernetes, here’s a new resource type. Treat it like one of your own.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, if you define a Database CRD, you can create resources like Postgres or MySQL directly in Kubernetes, complete with their own schemas and validation rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Should You Care About CRDs?
&lt;/h2&gt;

&lt;p&gt;Alright, here’s the deal: CRDs make Kubernetes amazingly flexible. &lt;/p&gt;

&lt;p&gt;With CRDs, you can:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add New Features:&lt;/strong&gt; Need Kubernetes to manage your app-specific workflows? No problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay Declarative:&lt;/strong&gt; Manage everything using YAML—just like the built-in stuff.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automate All the Things:&lt;/strong&gt; Pair your CRD with a custom controller (or operator) to handle the heavy lifting for you.&lt;/p&gt;

&lt;p&gt;Basically, CRDs let you turn Kubernetes into your personal Swiss Army knife for app and infrastructure management.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's see an example!
&lt;/h2&gt;

&lt;p&gt;Here’s a quick example of a CRD that defines a custom resource type called &lt;code&gt;Database&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apiextensions.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CustomResourceDefinition&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;databases.awesomeproject.com&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;awesomeproject.com&lt;/span&gt;
  &lt;span class="na"&gt;names&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Database&lt;/span&gt;
    &lt;span class="na"&gt;plural&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;databases&lt;/span&gt;
    &lt;span class="na"&gt;singular&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;database&lt;/span&gt;
  &lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespaced&lt;/span&gt;
  &lt;span class="na"&gt;versions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
      &lt;span class="na"&gt;served&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;openAPIV3Schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
          &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
              &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
                &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
                &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;After applying this CRD, Kubernetes knows how to handle a Database resource. You can now create custom databases using YAML—how cool is that?&lt;/p&gt;

&lt;h2&gt;
  
  
  Are they common?
&lt;/h2&gt;

&lt;p&gt;You bet they are! CRDs are everywhere in the Kubernetes ecosystem. Here are some popular ones that you might bump into:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Cert-Manager
&lt;/h3&gt;

&lt;p&gt;Automates the boring stuff around TLS certificates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CRDs&lt;/strong&gt;: &lt;code&gt;Certificate&lt;/code&gt;, &lt;code&gt;Issuer&lt;/code&gt;, &lt;code&gt;ClusterIssuer&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Example&lt;/strong&gt;: Automatically get certificates from Let’s Encrypt.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. ArgoCD
&lt;/h3&gt;

&lt;p&gt;Powers your GitOps workflows (syncing Git to your cluster).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CRDs&lt;/strong&gt;: &lt;code&gt;Application&lt;/code&gt;, &lt;code&gt;AppProject&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Example&lt;/strong&gt;: Define an application that ArgoCD will deploy from Git.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Prometheus Operator
&lt;/h3&gt;

&lt;p&gt;Makes monitoring a breeze by automating Prometheus setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CRDs&lt;/strong&gt;: &lt;code&gt;ServiceMonitor&lt;/code&gt;, &lt;code&gt;PodMonitor&lt;/code&gt;, &lt;code&gt;Alertmanager&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Example&lt;/strong&gt;: Define which services Prometheus should monitor.&lt;/p&gt;

&lt;h2&gt;
  
  
  CRDs in Action: How They Work
&lt;/h2&gt;

&lt;p&gt;When you combine CRDs with a custom controller or operator, things get really exciting. Imagine this:&lt;/p&gt;

&lt;p&gt;You define a Database custom resource to manage your Postgres instance. &lt;br&gt;
A controller watches for changes to Database resources.&lt;br&gt;
The controller handles all the nitty-gritty details—provisioning storage, creating users, setting up backups, you name it!&lt;br&gt;
This is how tools like ArgoCD and Cert-Manager work behind the scenes. CRDs let Kubernetes handle the &lt;em&gt;what&lt;/em&gt;, while the controller handles the &lt;em&gt;how&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;CRDs are what make Kubernetes extensibility easy and fun. They let you manage almost anything: databases, certificates, cloud resources, with Kubernetes’ familiar declarative style. Whether you’re using popular tools like Istio and Prometheus Operator, or building your own custom workflows, CRDs are a must-know feature.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>cloudnative</category>
      <category>devops</category>
    </item>
    <item>
      <title>AWS Step Functions: Your Workflow's Best Friend</title>
      <dc:creator>Jorge Contreras</dc:creator>
      <pubDate>Fri, 29 Nov 2024 13:00:00 +0000</pubDate>
      <link>https://dev.to/jorgecontreras/aws-step-functions-your-workflows-best-friend-3j2b</link>
      <guid>https://dev.to/jorgecontreras/aws-step-functions-your-workflows-best-friend-3j2b</guid>
      <description>&lt;p&gt;Let’s talk about automation because, let’s face it, nobody has time to babysit workflows. That’s where AWS Step Functions comes in. Think of it as the air traffic controller for your applications, making sure every task gets done in the right order, at the right time, and without you breaking a sweat.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore what Step Functions is, why it’s so handy, and how you can use it to orchestrate all kinds of workflows—whether you’re processing data, training machine learning models, or just keeping your microservices from stepping on each other’s toes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Exactly Are AWS Step Functions?
&lt;/h2&gt;

&lt;p&gt;AWS Step Functions is like a super-organized assistant for your cloud applications. It helps you manage workflows by breaking them down into individual tasks and stringing them together in a way that makes sense. You can think of it as flowcharts that actually do work.&lt;/p&gt;

&lt;p&gt;Rather than writing custom code to handle retries, errors, and task coordination, Step Functions takes care of all of that for you. You just tell it what to do (using a JSON file in Amazon States Language) and let it run the show.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why are they so useful?
&lt;/h2&gt;

&lt;p&gt;Step Functions can save you a ton of time and hassle. Here’s how:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Tames Complexity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Got a bunch of services that need to work together? Step Functions makes them play nice by managing the sequence, timing, and decisions between tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Grows with You&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Whether you’re running 10 workflows or 10,000, Step Functions scales automatically. And because it’s serverless, you don’t have to worry about managing infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Keeps Costs in Check&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You only pay for what you use. Every time a task moves from one state to the next, that’s a state transition—and that’s all you’re billed for. No hidden costs here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Helps You Sleep at Night&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With built-in monitoring and logging through AWS CloudWatch, you can keep tabs on your workflows and troubleshoot without the guesswork.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understood but, where can Step Function be applied in the real world?
&lt;/h2&gt;

&lt;p&gt;Step Functions shines in pretty much any scenario where tasks need to happen in a certain order (or at the same time). Here are a few examples:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Data Processing Pipelines&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Orchestrate an ETL workflow: pull raw data from S3, transform it with AWS Glue, and load it into a database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Machine Learning Workflows&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Automate model training with SageMaker: preprocess the data, train the model, and deploy it—without lifting a finger.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Microservices Coordination&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tie together multiple microservices, making sure each service completes its task before the next one starts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Real-Time Event Handling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Process streaming data with Amazon Kinesis and trigger alerts or actions based on what’s happening in real time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can I see an example please?
&lt;/h2&gt;

&lt;p&gt;Let’s say you’re building a photo app, and every time someone uploads a picture, you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resize the image.&lt;/li&gt;
&lt;li&gt;Analyze it (e.g., detect objects using Rekognition).&lt;/li&gt;
&lt;li&gt;Save the metadata to a database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s how you’d build that in Step Functions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step-by-Step Workflow&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user uploads an image to an S3 bucket.&lt;/li&gt;
&lt;li&gt;Step Functions triggers a Lambda function to resize the image.&lt;/li&gt;
&lt;li&gt;A second Lambda function analyzes the image.&lt;/li&gt;
&lt;li&gt;The final Lambda function saves the analysis results to DynamoDB.
&lt;/li&gt;
&lt;/ol&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;"Comment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Photo processing workflow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"StartAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ResizeImage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"States"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ResizeImage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:region:account-id:function:resizeImageFunction"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AnalyzeImage"&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;"AnalyzeImage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:region:account-id:function:analyzeImageFunction"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Next"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SaveMetadata"&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;"SaveMetadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:lambda:region:account-id:function:saveMetadataFunction"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"End"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;AWS Step Functions is one of those services that makes life easier the more you use it. Whether you’re building simple task sequences or managing complex pipelines, it’s got the tools to keep everything running smoothly. And the best part? No more custom code for retries, errors, or orchestration.&lt;/p&gt;

&lt;p&gt;So, what workflow will you automate with Step Functions? Let’s get building!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloudnative</category>
      <category>serverless</category>
    </item>
    <item>
      <title>How I Built a Serverless URL Shortener on AWS Using Terraform</title>
      <dc:creator>Jorge Contreras</dc:creator>
      <pubDate>Mon, 25 Nov 2024 16:05:32 +0000</pubDate>
      <link>https://dev.to/jorgecontreras/how-i-built-a-serverless-url-shortener-on-aws-using-terraform-83e</link>
      <guid>https://dev.to/jorgecontreras/how-i-built-a-serverless-url-shortener-on-aws-using-terraform-83e</guid>
      <description>&lt;p&gt;Hey there, fellow devs! 👋&lt;/p&gt;

&lt;p&gt;I’ve been practicing on AWS as preparation for my certification exams. I wanted to share a project I worked on: a &lt;strong&gt;serverless URL shortener&lt;/strong&gt;. It’s a simple, real-world application that demonstrates the power of AWS services like &lt;strong&gt;Lambda&lt;/strong&gt;, &lt;strong&gt;API Gateway&lt;/strong&gt;, and &lt;strong&gt;DynamoDB&lt;/strong&gt;, while also introducing &lt;strong&gt;Terraform&lt;/strong&gt; for managing infrastructure as code.&lt;/p&gt;

&lt;p&gt;By the end of this guide, you’ll have a fully functional URL shortener that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shortens long URLs with a POST request.&lt;/li&gt;
&lt;li&gt;Redirects users to the original URL with a GET request.&lt;/li&gt;
&lt;li&gt;Uses AWS's serverless stack for scalability and low cost.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, grab a coffee ☕ and let’s get started!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;AWS Services Used&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AWS Lambda&lt;/strong&gt;: To execute the backend logic for shortening and redirecting URLs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon DynamoDB&lt;/strong&gt;: To store mappings between short and long URLs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amazon API Gateway&lt;/strong&gt;: To expose RESTful API endpoints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terraform&lt;/strong&gt;: To define and deploy the infrastructure as code.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we start building, make sure you have the following tools installed and configured:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS Account&lt;/strong&gt;:&lt;br&gt;
You’ll need an &lt;a href="https://aws.amazon.com/free/" rel="noopener noreferrer"&gt;AWS account&lt;/a&gt; to deploy resources. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS CLI&lt;/strong&gt;:&lt;br&gt;
Install the &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" rel="noopener noreferrer"&gt;AWS Command Line Interface (CLI)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After installing, configure the CLI with your AWS credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   aws configure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll be prompted to enter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Access Key ID&lt;/li&gt;
&lt;li&gt;Secret Access Key&lt;/li&gt;
&lt;li&gt;Default AWS Region (e.g., us-east-1)&lt;/li&gt;
&lt;li&gt;Output Format (leave as json)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run this command to verify the configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   aws s3 &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it lists your S3 buckets (or none if you don’t have any), the &lt;br&gt;
   setup is complete.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terraform&lt;/strong&gt;:&lt;br&gt;
Install Terraform (v1.5+ recommended).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Python&lt;/strong&gt;:&lt;br&gt;
Install Python 3.9 or higher to write the Lambda functions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;cURL or Postman&lt;/strong&gt;:&lt;br&gt;
These tools will help you test the API endpoints after deployment.&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 1. Create the project structure:
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;project-root/
├── application/
│   ├── backend/
│   │   ├── lambda_create/          
│   │   │   └── create_short_url.py
│   │   ├── lambda_get/             
│   │       └── get_original_url.py
├── terraform/                      # Terraform configuration files
    └── main.tf                     # Defines AWS resources
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 2: Writing the Lambda Functions
&lt;/h2&gt;

&lt;p&gt;AWS Lambda is a serverless compute service that lets you run code without managing servers. You simply write your code, upload it to Lambda, and AWS handles the rest—like provisioning, scaling, and running the infrastructure. In this section, we'll write the logic in python and package it as zip to be uploaded. &lt;/p&gt;

&lt;p&gt;We will create two lambdas: one for creating the short url, and the other to get the original url back from a short url.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;1. Create the &lt;code&gt;CreateShortURL&lt;/code&gt; Function&lt;/strong&gt;
&lt;/h3&gt;
&lt;h4&gt;
  
  
  File: &lt;code&gt;application/backend/lambda_create/create_short_url.py&lt;/code&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;

&lt;span class="c1"&gt;# Initialize DynamoDB client
&lt;/span&gt;&lt;span class="n"&gt;dynamodb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dynamodb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;table_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;URLMapping&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;  &lt;span class="c1"&gt;# Replace with your DynamoDB table name
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Parse the request body
&lt;/span&gt;        &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;original_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;OriginalURL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;original_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;OriginalURL is required&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;# Generate a unique short URL identifier (6-character UUID)
&lt;/span&gt;        &lt;span class="n"&gt;short_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;())[:&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="c1"&gt;# Store the mapping in DynamoDB
&lt;/span&gt;        &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;TableName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ShortURL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;S&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;short_url&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;OriginalURL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;S&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;original_url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Return the short URL
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ShortURL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;short_url&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Internal server error&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Create the GetOriginalURL Function&lt;/strong&gt;
&lt;/h3&gt;
&lt;h4&gt;
  
  
  File: application/backend/lambda_get/get_original_url.py
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;

&lt;span class="c1"&gt;# Initialize DynamoDB client
&lt;/span&gt;&lt;span class="n"&gt;dynamodb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dynamodb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;table_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;URLMapping&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;  &lt;span class="c1"&gt;# Replace with your DynamoDB table name
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Get the short URL from the path parameter
&lt;/span&gt;        &lt;span class="n"&gt;short_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pathParameters&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;short_url&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="c1"&gt;# Query DynamoDB for the original URL
&lt;/span&gt;        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;TableName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ShortURL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;S&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;short_url&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Check if the item exists
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Item&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Short URL not found&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;original_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Item&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;OriginalURL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;S&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="c1"&gt;# Return a 302 redirect to the original URL
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;headers&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Location&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;original_url&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Internal server error&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Package the lambda functions&lt;/strong&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;application/backend/lambda_create
zip create_short_url.zip create_short_url.py

&lt;span class="nb"&gt;cd&lt;/span&gt; ../lambda_get
zip get_original_url.zip get_original_url.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After packaging, ensure your project looks 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;project-folder/
├── application/
│   ├── backend/                  # Backend logic for API
│       ├── lambda_create/        # CreateShortURL Lambda
│       │   ├── create_short_url.py
│       │   ├── create_short_url.zip
│       ├── lambda_get/           # GetOriginalURL Lambda
│           ├── get_original_url.py
│           ├── get_original_url.zip
│
├── terraform/                    # Terraform configurations
    ├── main.tf

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Define your Infrastructure as Code
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;main.tf&lt;/code&gt;, define the AWS resources. In this section, we define what resources will be created in the AWS cloud, from IAM roles and policies to Lambdas, DynamoDB and the API Gateway. It allows for managing your infrastructure as code, isn't that awesome?&lt;/p&gt;

&lt;p&gt;The file is somewhat long so I just included a snippet here. You can find the whole contents of the file in my &lt;a href="https://github.com/jorgecontreras/tinyurl/blob/main/terraform/main.tf" rel="noopener noreferrer"&gt;github repo&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# DynamoDB Table&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_dynamodb_table"&lt;/span&gt; &lt;span class="s2"&gt;"url_mapping"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"URLMapping"&lt;/span&gt;
  &lt;span class="nx"&gt;hash_key&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"short_url"&lt;/span&gt;

  &lt;span class="nx"&gt;attribute&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"short_url"&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"S"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;billing_mode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"PAY_PER_REQUEST"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# IAM Role for Lambda&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role"&lt;/span&gt; &lt;span class="s2"&gt;"lambda_exec_role"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"url_shortener_lambda_role"&lt;/span&gt;

  &lt;span class="nx"&gt;assume_role_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsonencode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;Version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;
    &lt;span class="nx"&gt;Statement&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="nx"&gt;Action&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sts:AssumeRole"&lt;/span&gt;
      &lt;span class="nx"&gt;Effect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
      &lt;span class="nx"&gt;Principal&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;Service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"lambda.amazonaws.com"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}]&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Lambda Functions&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lambda_function"&lt;/span&gt; &lt;span class="s2"&gt;"create_short_url"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;filename&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${path.module}/../application/backend/lambda_create/create_short_url.zip"&lt;/span&gt;
  &lt;span class="nx"&gt;function_name&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"CreateShortURL"&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lambda_exec_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
  &lt;span class="nx"&gt;handler&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"create_short_url.lambda_handler"&lt;/span&gt;
  &lt;span class="nx"&gt;runtime&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"python3.9"&lt;/span&gt;

  &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;variables&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;TABLE_NAME&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_dynamodb_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url_mapping&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Deploy your infrastructure!
&lt;/h2&gt;

&lt;p&gt;Run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;terraform
terraform init
terraform plan
terraform apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5. Test
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Shorten a URL&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Send a POST request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"OriginalURL": "https://www.example.com"}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
https://&amp;lt;api-gateway-id&amp;gt;.execute-api.&amp;lt;region&amp;gt;.amazonaws.com/shorten
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;2. Redirect using the short URL&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; https://&amp;lt;api-gateway-id&amp;gt;.execute-api.&amp;lt;region&amp;gt;.amazonaws.com/&amp;lt;short_url&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;And that’s it! 🎉 You’ve built a fully functional URL shortener using AWS and Terraform. Checkout the full project &lt;a href="https://github.com/jorgecontreras/tinyurl" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s what we achieved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learned how to set up AWS resources with Terraform.&lt;/li&gt;
&lt;li&gt;Created Lambda functions for shortening and redirecting URLs.&lt;/li&gt;
&lt;li&gt;Integrated everything with API Gateway and DynamoDB.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stay tuned for more AWS articles! next, we’ll explore securing APIs and adding custom domain names. Happy coding!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloudcomputing</category>
      <category>serverless</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Concurrency in Go</title>
      <dc:creator>Jorge Contreras</dc:creator>
      <pubDate>Fri, 01 Mar 2024 02:19:25 +0000</pubDate>
      <link>https://dev.to/jorgecontreras/concurrency-in-go-1ok1</link>
      <guid>https://dev.to/jorgecontreras/concurrency-in-go-1ok1</guid>
      <description>&lt;h3&gt;
  
  
  What is concurrency and why does it matter?
&lt;/h3&gt;

&lt;p&gt;Concurrency is handling several tasks within a given timeframe. Most modern applications, such as web servers, databases, and user interfaces, require real-time processing and responsiveness. Concurrency allows to handle multiple tasks, like API requests or database calls, simultaneously. This helps us developers improve the performance of the applications our users love. Concurrency allows for maximum optimization of computing resources, making our systems highly efficient while lowering infrastructure costs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Concurrency optimizes computing resources, maximizes performance and minimize infrastructure costs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Why is concurrency hard to implement?
&lt;/h3&gt;

&lt;p&gt;Concurrency is challenging to implement for several reasons, largely due to the complexities and unpredictable nature of managing multiple tasks that run at overlapping times. Very often, these concurrent tasks need to share resources and it is very easy to make mistakes and interfere with other tasks. For example, if one task attempts to read from the memory while another task is writing. All these tasks being executed at the same time need an efficient way to synchronize and ensure there are no conflicts between them. Deadlocks, livelocks, starvation and race conditions are just a few examples of these complexities[1].&lt;/p&gt;

&lt;h3&gt;
  
  
  How is concurrency implemented in different programming languages?
&lt;/h3&gt;

&lt;p&gt;Concurrency is not a new concept. The idea of concurrency in computing began with the development of multiprogramming systems. The Atlas Computer, developed at the University of Manchester and operational in 1962, is often credited as one of the first machines to provide a form of multiprogramming. The semaphore, invented by Dijkstra and colleagues[2], is one of the first primitives for all things related to synchronization.&lt;/p&gt;

&lt;p&gt;While it is possible to implement these primitives in languages like C or C++, it can be challenging, as these languages provide low-level control over hardware and memory, but it is up to the developer to control the threads and shared resources, keep track of memory usage, free up space and so on.&lt;/p&gt;

&lt;p&gt;Over time, there has been a development of techniques to facilitate the implementation of concurrent systems. In the world of Javascript, &lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;NodeJS&lt;/a&gt; implements concurrency using a non-blocking, event-driven architecture, primarily centered around the event loop and callbacks. In PHP, the &lt;a href="https://openswoole.com/" rel="noopener noreferrer"&gt;OpenSwoole&lt;/a&gt; framework enables PHP developers to write asynchronous, concurrent, and highly scalable applications without needing extensive knowledge of non-blocking I/O programming.&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%2F5dhv2ttf9u9jsxk1mjt5.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%2F5dhv2ttf9u9jsxk1mjt5.jpeg" alt="Image description" width="781" height="624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A few programming languages and their concurrency approach&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What makes Go an excellent choice for concurrent applications?
&lt;/h3&gt;

&lt;p&gt;Go's concurrency model, based on the Communicating Sequential Processes (CSP) theory, makes concurrent programming intuitive [3]. Go abstracts many of the complexities that arise from concurrent system architectures like distributed systems and cloud computing. The go runtime, via its scheduler, takes care of managing goroutines, which are Go's lightweight threads of execution [4].&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gobyexample.com/goroutines" rel="noopener noreferrer"&gt;Goroutines&lt;/a&gt; are much more lightweight than OS threads. They have a smaller memory footprint, and the overhead of creating and destroying a goroutine is significantly lower than that of an OS thread. This allows Go programs to easily handle thousands or even millions of goroutines.&lt;/p&gt;

&lt;p&gt;Go by itself does not eliminate the complexities associated to concurrent programming, but it definitely makes them easier to manage. It provides composable primitives like goroutines, channels and waitgroups to facilitate synchronization. Its efficient garbage collector takes care of freeing up resources for you. Additionally, Go’s standard library includes a wealth of packages that are well-suited for building cloud-native applications. Additionally, Go provides the performance benefits of a compiled language, which is critical for cloud and network services that need to handle high loads efficiently.&lt;/p&gt;

&lt;h3&gt;
  
  
  How is concurrency achieved in Go?
&lt;/h3&gt;

&lt;p&gt;Let's take a look at how goroutines are created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Pink&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hi, Pink Goroutine!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Purple&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, Purple Goroutine!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Green&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, Green Goroutine!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Orange&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, Orange Goroutine!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// start the goroutines&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;Pink&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;Purple&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;Green&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;Orange&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main process triggers the goroutines using the go keyword before the function call. These goroutines or threads start execution immediately and they run concurrently.&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%2Fbfklzb9d3oxdcxcusl25.gif" 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%2Fbfklzb9d3oxdcxcusl25.gif" alt="Image description" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;goroutines executing concurrently.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Just imagine all the time-consuming tasks that you could execute at the same time! Pulling from different external resources, reading from a database, calling an API. As long as they don't depend on each other, there is no need to wait for one task to complete to start working on the next.&lt;/p&gt;

&lt;p&gt;In some cases though, you may need to actually wait for some goroutines to complete before starting the next one. For that, Go provides waitgroups:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"sync"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Pink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// Decrement counter when done&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hi, Pink Goroutine!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Purple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// Decrement counter when done&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, Purple Goroutine!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Green&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// Decrement counter when done&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, Green Goroutine!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Orange&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, Orange Goroutine!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;

    &lt;span class="c"&gt;// Increment the WaitGroup counter for each goroutine&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Start the first three goroutines&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;Pink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;Purple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;Green&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Wait for the first three goroutines to complete&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Now start the Orange goroutine&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;Orange&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;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%2Fywwf3rgy5qfkkw7qy5y0.gif" 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%2Fywwf3rgy5qfkkw7qy5y0.gif" alt="Image description" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;waitgroups: The process waits for the first 3 goroutines to complete.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://gobyexample.com/waitgroups" rel="noopener noreferrer"&gt;Waitgroups&lt;/a&gt; gives you the ability to wait for goroutines to be completed before moving on.&lt;/p&gt;

&lt;p&gt;Why is synchronization important, you ask? Let's take a closer look the animation above. Did you notice the orange goroutine was not completed? That's because the process continues its execution and the goroutine may not get enough time to complete whatever it was doing. Adding that goroutine to the waitgroup would solve the issue. There could be many places in your system that requires this type of synchronization: use it wisely!&lt;/p&gt;

&lt;p&gt;Finally, let's see what &lt;a href="https://gobyexample.com/channels" rel="noopener noreferrer"&gt;channels&lt;/a&gt; can do for us. Go's philosophy to prevent common issues like data races goes something like this:&lt;/p&gt;

&lt;p&gt;Do not communicate by sharing memory; instead, share memory by communicating.&lt;/p&gt;

&lt;p&gt;What does this mean? Instead of explicitly using locks to mediate access to shared data, Go encourages the use of channels to pass references to data between goroutines. Let's see a code example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="s"&gt;"Hello"&lt;/span&gt; &lt;span class="p"&gt;}()&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="s"&gt;"World"&lt;/span&gt; &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="n"&gt;msg1&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;
    &lt;span class="n"&gt;msg2&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, two goroutines communicate strings through a channel. Instead of accessing a shared variable, they use the channel to send and receive messages.&lt;/p&gt;

&lt;p&gt;This principle is one of the key reasons why Go's concurrency model is considered more straightforward and robust compared to traditional thread-based models.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping up
&lt;/h3&gt;

&lt;p&gt;Concurrency enables applications to handle multiple tasks efficiently, essential in applications driven by real-time data, high-performance demands, and the need for scalable systems that make the most optimal use of computing resources. Go's design principles, its simplicity and efficient communication over shared memory, makes it a great choice for distributed systems and cloud-native technologies. Go was designed with concurrency in mind since its inception, making it stand out from other programming languages.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;[1] &lt;a href="https://www.cs.yale.edu/homes/aspnes/pinewiki/Deadlock.html" rel="noopener noreferrer"&gt;https://www.cs.yale.edu/homes/aspnes/pinewiki/Deadlock.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[2] &lt;a href="https://pages.cs.wisc.edu/%7Eremzi/OSTEP/threads-sema.pdf" rel="noopener noreferrer"&gt;https://pages.cs.wisc.edu/~remzi/OSTEP/threads-sema.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[3] &lt;a href="https://www.cs.cmu.edu/%7Ecrary/819-f09/Hoare78.pdf" rel="noopener noreferrer"&gt;https://www.cs.cmu.edu/~crary/819-f09/Hoare78.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[4] Cox-Buday, K. (2017). Concurrency in go: Tools and techniques for developers. O'Reilly Media.&lt;/p&gt;

</description>
      <category>concurrency</category>
      <category>go</category>
      <category>softwaredevelopment</category>
    </item>
  </channel>
</rss>
