<?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: Jasper Gabriel</title>
    <description>The latest articles on DEV Community by Jasper Gabriel (@jdg2896).</description>
    <link>https://dev.to/jdg2896</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%2F1067852%2F9c972a7a-5c3e-4663-ad30-21fe9b9b0c62.jpeg</url>
      <title>DEV Community: Jasper Gabriel</title>
      <link>https://dev.to/jdg2896</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jdg2896"/>
    <language>en</language>
    <item>
      <title>How I Contributed to Open-Source While Learning Svelte</title>
      <dc:creator>Jasper Gabriel</dc:creator>
      <pubDate>Sun, 21 Jan 2024 09:10:02 +0000</pubDate>
      <link>https://dev.to/jdg2896/how-i-contributed-to-open-source-while-learning-svelte-1b1j</link>
      <guid>https://dev.to/jdg2896/how-i-contributed-to-open-source-while-learning-svelte-1b1j</guid>
      <description>&lt;p&gt;If you're looking to start contributing to open-source projects, or you want to make more open-source contributions, you might already be looking at different open-source projects, seeing where you can help out.&lt;/p&gt;

&lt;p&gt;Sometimes, contributing to open-source projects comes naturally. You might even find opportunities to improve a project's documentation while reading, or in my case while learning Svelte.&lt;/p&gt;

&lt;p&gt;In this article, I'll share how I ended up contributing to &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; while learning through their &lt;a href="https://learn.svelte.dev/tutorial/welcome-to-svelte" rel="noopener noreferrer"&gt;interactive tutorials&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  My background: deciding to learn Svelte
&lt;/h2&gt;

&lt;p&gt;Before we continue, let me share my background.&lt;/p&gt;

&lt;p&gt;Throughout my career, I've mostly done backend development. I wanted to learn frontend development to build my personal website. &lt;/p&gt;

&lt;p&gt;I was deciding between &lt;strong&gt;React&lt;/strong&gt; and &lt;strong&gt;Svelte&lt;/strong&gt;. After browsing through multiple blogs (including this &lt;a href="https://prismic.io/blog/svelte-vs-react" rel="noopener noreferrer"&gt;one&lt;/a&gt;) and Reddit threads comparing both, I was ready to choose.&lt;/p&gt;

&lt;p&gt;Based on my quick research, &lt;strong&gt;React&lt;/strong&gt; is ideal for complex and large-scale applications while &lt;strong&gt;Svelte&lt;/strong&gt; is more beginner-friendly since I don't have to learn &lt;a href="https://react.dev/learn/writing-markup-with-jsx" rel="noopener noreferrer"&gt;JSX&lt;/a&gt; and &lt;a href="https://legacy.reactjs.org/docs/faq-internals.html" rel="noopener noreferrer"&gt;virtual DOM&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As someone who is new to frontends and just wants to build a personal website, I ended up choosing Svelte for its simplicity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning Svelte through the interactive tutorials
&lt;/h2&gt;

&lt;p&gt;Now that I've chosen to learn Svelte for building my website, the first I did was visit &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte's website&lt;/a&gt;. Then I went to &lt;a href="https://learn.svelte.dev/tutorial/welcome-to-svelte" rel="noopener noreferrer"&gt;Svelte's interactive tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The tutorial is composed of four parts, covering both &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; and &lt;a href="https://kit.svelte.dev/" rel="noopener noreferrer"&gt;SvelteKit&lt;/a&gt;, which is a UI framework for Svelte.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Note:&lt;/strong&gt; Here's my &lt;a href="https://github.com/jdg2896/learning-notes/blob/main/notes/learning-svelte-and%20-sveltekit.md" rel="noopener noreferrer"&gt;notes on GitHub&lt;/a&gt; while learning Svelte and SvelteKit.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Finding possible improvements in the tutorial
&lt;/h2&gt;

&lt;p&gt;I went through the tutorials during my free time. The first part was pretty straightforward.&lt;/p&gt;

&lt;p&gt;Once I got to the second part, in the &lt;a href="https://learn.svelte.dev/tutorial/slots" rel="noopener noreferrer"&gt;slots section&lt;/a&gt;, I noticed a difference between the docs on the left, and the code on the right. &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%2Fy8fsjca9i9rz86entubd.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%2Fy8fsjca9i9rz86entubd.png" alt="Learning Svelte interactive tutorial website, slots section difference between docs and code" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the left part, the docs show &lt;code&gt;&amp;lt;div class="card "&amp;gt;&lt;/code&gt;, while the code snippet on the right shows &lt;code&gt;&amp;lt;div class="card"&amp;gt;&lt;/code&gt;. The difference is that there's an &lt;strong&gt;extra whitespace on the class value&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here's a side-by-side comparison to see the difference more clearly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;div class="card "&amp;gt;&lt;/code&gt; (Left part: docs)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;div class="card"&amp;gt;&lt;/code&gt; (Right part: code snippet)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I usually notice small details like this, so I paused and looked to improve the tutorial page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improving the tutorial documentation
&lt;/h2&gt;

&lt;p&gt;Websites and documentation that are open-source usually have an &lt;strong&gt;edit page button&lt;/strong&gt; so readers can edit the page when they find issues or possible improvements. &lt;/p&gt;

&lt;p&gt;Fortunately, the maintainers at Svelte also make it easy to edit the interactive tutorial pages.&lt;/p&gt;

&lt;p&gt;While still on the slots tutorial page, I clicked the &lt;strong&gt;Edit this page&lt;/strong&gt; link at the bottom.&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%2Fgc0wtdmpo14wmwn4th45.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%2Fgc0wtdmpo14wmwn4th45.png" alt="Learning Svelte interactive tutorial website, click the " width="800" height="1327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking the &lt;strong&gt;Edit this page&lt;/strong&gt; button brought me to the &lt;a href="https://github.com/sveltejs/learn.svelte.dev/tree/main/content/tutorial/02-advanced-svelte/07-composition/01-slots" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; of Svelte's interactive tutorial.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reviewing the contributing guidelines
&lt;/h3&gt;

&lt;p&gt;While reviewing Svelte's repository, I didn't see any &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; or any other open-source contributing guidelines, which can also be found in the repository's &lt;code&gt;README.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What I did instead was review the previous commit messages to see if there was a specific commit format that I should follow. &lt;/p&gt;

&lt;p&gt;There was no standard commit format, so I went with the &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/" rel="noopener noreferrer"&gt;conventional commits&lt;/a&gt; format.&lt;/p&gt;

&lt;h3&gt;
  
  
  Forks, commits, and pull requests through the GitHub website
&lt;/h3&gt;

&lt;p&gt;Now, I'll show you the steps on how I contributed my changes through the GitHub website.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Note:&lt;/strong&gt; The screenshots I will show for forking, comitting, and creating a pull request on GitHub were made only to show the process. &lt;/p&gt;

&lt;p&gt;I won't create an actual pull request adding a random white space. 😉&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;While still on the slots page &lt;code&gt;README.md&lt;/code&gt; file, I clicked the &lt;strong&gt;edit button&lt;/strong&gt; to edit the file directly on GitHub.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbbkqy5vm4mz4q89yxzp9.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%2Fbbkqy5vm4mz4q89yxzp9.png" alt="learn.svelte.dev on GitHub website, slots section README.md, click " width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Since it was my first time contributing to &lt;a href="https://github.com/sveltejs/learn.svelte.dev" rel="noopener noreferrer"&gt;Svelte's tutorial&lt;/a&gt;, I was prompted to &lt;strong&gt;fork the repository&lt;/strong&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnw8d4zhkagryvgtaepvt.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%2Fnw8d4zhkagryvgtaepvt.png" alt="learn.svelte.dev on the GitHub website, prompt to fork the repository." width="800" height="160"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once I forked the repository, I edited the file with the improvements. Then I clicked &lt;strong&gt;Commit changes&lt;/strong&gt;. &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F09xuzjkmuadsnxuro07n.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%2F09xuzjkmuadsnxuro07n.png" alt="learn.svelte.dev on the GitHub website, click " width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I was prompted to enter my &lt;strong&gt;commit message&lt;/strong&gt;, along with the optional description and commit email. Then I clicked &lt;strong&gt;Propose changes&lt;/strong&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9u2tegf84kp1ip6x57wb.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%2F9u2tegf84kp1ip6x57wb.png" alt="learn.svelte.dev on the GitHub website, prompt to enter commit message, optional description, and commit email. Then click " width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After making a commit, GitHub will automatically create a &lt;strong&gt;new branch&lt;/strong&gt; with &lt;code&gt;patch-&amp;lt;number&amp;gt;&lt;/code&gt; for the branch name. My branch name is &lt;code&gt;patch-3&lt;/code&gt;. Then I reviewed the changes before clicking &lt;strong&gt;Create pull request&lt;/strong&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3o54qfwyagkobrj7wh5.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%2Fa3o54qfwyagkobrj7wh5.png" alt="learn.svelte.dev on the GitHub website, create a new branch " width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, I was prompted to enter a pull request title and description. Then I clicked &lt;strong&gt;Create pull request&lt;/strong&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3o54qfwyagkobrj7wh5.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%2Fa3o54qfwyagkobrj7wh5.png" alt="learn.svelte.dev on the GitHub website, prompt to enter pull request title and description. Then click " width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Making changes on the GitHub website works for small commits, but I'd still recommend &lt;strong&gt;cloning the project to your local machine to test your changes&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;It's ideal to make a habit of &lt;strong&gt;testing your changes before making a pull request to open-source projects&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So that's exactly what I did. I cloned the project and followed the &lt;code&gt;README.md&lt;/code&gt; docs for setting up the project locally.&lt;/p&gt;

&lt;p&gt;Once I've &lt;strong&gt;tested out that my changes didn't break anything&lt;/strong&gt;, I made the pull request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pull request merged!
&lt;/h3&gt;

&lt;p&gt;After creating my pull request, it's up to the maintainers if and when they'll approve and merge it.&lt;/p&gt;

&lt;p&gt;After a few days, one of my &lt;a href="https://github.com/sveltejs/learn.svelte.dev/pull/550" rel="noopener noreferrer"&gt;pull requests&lt;/a&gt; was merged.&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%2Ftvk7f7kv6qn00yl90cj3.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%2Ftvk7f7kv6qn00yl90cj3.png" alt="My GitHub pull request on learn.svelte.dev repository merged." width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Making pull requests that &lt;strong&gt;introduce small changes and have good descriptions&lt;/strong&gt; increases your chances of having your pull request approved.&lt;/p&gt;

&lt;p&gt;It also makes it easier for the open-source project maintainers to review your pull request, since they are usually busy with a lot of things.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other possible improvements I've found and some tips
&lt;/h2&gt;

&lt;p&gt;I'd like to share that I made three pull requests, but only one has been approved and merged as of writing this.&lt;/p&gt;

&lt;p&gt;Here are the other pull requests if you're curious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/sveltejs/learn.svelte.dev/pull/551" rel="noopener noreferrer"&gt;docs: add code snippet for removing if blocks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sveltejs/learn.svelte.dev/pull/552" rel="noopener noreferrer"&gt;docs: update code snippet for consistency with source file&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Based on my observations, the less visited pages of a website usually have more areas for improvement. In the case of &lt;a href="https://learn.svelte.dev/tutorial/welcome-to-svelte" rel="noopener noreferrer"&gt;Svelte's interactive tutorials&lt;/a&gt;, not everyone will finish the tutorials. &lt;/p&gt;

&lt;p&gt;As a result, the less visited tutorial content might have more areas for improvement, since fewer people can spot potential issues.&lt;/p&gt;

&lt;p&gt;So if you're looking to improve websites and documentation, &lt;strong&gt;you can start looking at the least visited pages first.&lt;/strong&gt; 😉&lt;/p&gt;

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

&lt;p&gt;To recap, I've shared my story on how I made an open-source contribution while learning frontend development with Svelte.&lt;/p&gt;

&lt;p&gt;Hopefully, my story shows that sometimes, you can contribute to open-source even if it's not your first intention. You just have to follow one of the scouts' principles which is to &lt;em&gt;"leave the campground cleaner than you found it"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When you see issues in documentation, you can improve it as long as it's open-source. Even if it's not open-source, you can still contact the project's support team or message the author directly.&lt;/p&gt;

&lt;p&gt;Thank you for reading and I would love to hear your open-source experiences. Feel free to comment or message me &lt;a href="https://linktr.ee/jdg28" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Good luck on your open-source journey!&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kit.svelte.dev/" rel="noopener noreferrer"&gt;SvelteKit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.svelte.dev/tutorial/welcome-to-svelte" rel="noopener noreferrer"&gt;Learn Svelte and SvelteKit: Interactive Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://prismic.io/blog/svelte-vs-react" rel="noopener noreferrer"&gt;Svelte vs React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sveltejs/learn.svelte.dev" rel="noopener noreferrer"&gt;learn.svelte.dev GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.conventionalcommits.org/en/v1.0.0/" rel="noopener noreferrer"&gt;Conventional Commits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sveltejs/learn.svelte.dev/pull/550" rel="noopener noreferrer"&gt;Merged pull request to learn.svelte.dev GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sveltejs/learn.svelte.dev/pull/551" rel="noopener noreferrer"&gt;Pull request: "docs: add code snippet for removing if blocks"&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sveltejs/learn.svelte.dev/pull/552" rel="noopener noreferrer"&gt;Pull request: "docs: update code snippet for consistency with source file"&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>opensource</category>
      <category>github</category>
      <category>svelte</category>
      <category>learning</category>
    </item>
    <item>
      <title>How to Make Your Awesome GitHub Profile</title>
      <dc:creator>Jasper Gabriel</dc:creator>
      <pubDate>Sun, 07 Jan 2024 13:17:35 +0000</pubDate>
      <link>https://dev.to/jdg2896/how-to-make-your-awesome-github-profile-hog</link>
      <guid>https://dev.to/jdg2896/how-to-make-your-awesome-github-profile-hog</guid>
      <description>&lt;p&gt;If you're new to GitHub or have mostly worked with private GitHub repositories, chances are you don't have a GitHub profile yet.&lt;/p&gt;

&lt;p&gt;A GitHub profile helps provide basic information for those visiting your profile. Having a well-made profile can even help you stand out, especially when you start contributing to open-source projects and people start noticing you.&lt;/p&gt;

&lt;p&gt;In this article, I'll show how to create your own GitHub profile. I'll also share where to get inspiration for your profile. Finally, I'll share resources and tips to help you create an awesome GitHub profile!&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Your GitHub Profile
&lt;/h2&gt;

&lt;p&gt;Before you can start customizing your GitHub profile, you'll first need to create one.&lt;/p&gt;

&lt;p&gt;Here's a &lt;a href="https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/customizing-your-profile/managing-your-profile-readme" rel="noopener noreferrer"&gt;short guide&lt;/a&gt; from GitHub on how to set up your profile. &lt;/p&gt;

&lt;p&gt;But all you need to do is to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new repository that is &lt;strong&gt;the same as your GitHub username&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;README.md&lt;/code&gt; file to your new repository.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, my GitHub username is &lt;a href="https://github.com/jdg2896" rel="noopener noreferrer"&gt;jdg2896&lt;/a&gt;. To create my profile, I need to create a repository also named &lt;a href="https://github.com/jdg2896/jdg2896" rel="noopener noreferrer"&gt;jdg2896&lt;/a&gt;, then add a &lt;code&gt;README.md&lt;/code&gt; file.&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%2F7swmbnbnoqympvptgf0r.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%2F7swmbnbnoqympvptgf0r.png" alt="Example GitHub profile repository" width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After setting up your &lt;code&gt;repository&lt;/code&gt; and &lt;code&gt;README.md&lt;/code&gt; file, verify that your profile is visible by going to your GitHub profile at &lt;a href="https://github.com/YOUR-USERNAME" rel="noopener noreferrer"&gt;https://github.com/YOUR-USERNAME&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In my case, it would be &lt;a href="https://github.com/jdg2896" rel="noopener noreferrer"&gt;https://github.com/jdg2896&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Customizing Your GitHub Profile
&lt;/h2&gt;

&lt;p&gt;Now that you have a GitHub profile, it's time to get creative!&lt;/p&gt;

&lt;p&gt;The key here is to &lt;strong&gt;let your personality show&lt;/strong&gt; on your profile. Your GitHub profile doesn't have to be too formal like LinkedIn.&lt;/p&gt;

&lt;p&gt;I'd also suggest &lt;strong&gt;starting simple&lt;/strong&gt;. This helps get your GitHub profile up and running. You can always improve your profile later when you have new ideas.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Flavored Markdown, Formatting, and HTML
&lt;/h3&gt;

&lt;p&gt;For customizing your GitHub profile's &lt;code&gt;README.md&lt;/code&gt;, you'll be using &lt;strong&gt;GitHub Flavored Markdown&lt;/strong&gt;. If you've written markdown content before, formatting should be easy for you.&lt;/p&gt;

&lt;p&gt;If it's your first time writing in markdown, you can go to &lt;a href="https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax" rel="noopener noreferrer"&gt;GitHub's documentation&lt;/a&gt; to familiarize yourself with the available formatting options. &lt;/p&gt;

&lt;p&gt;You can also use &lt;strong&gt;HTML&lt;/strong&gt; for additional formatting options for your profile. &lt;/p&gt;

&lt;p&gt;I've found the following HTML tags to be useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;non-breaking space: &lt;code&gt;nbsp;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;div center align: &lt;code&gt;&amp;lt;div align="center"&amp;gt; &amp;lt;/div&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can use most HTML tags, but GitHub Flavored Markdown filters out the following HTML tags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;xmp&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;noembed&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;noframes&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;plaintext&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡: To learn more, here's the &lt;a href="https://github.github.com/gfm/#html-blocks" rel="noopener noreferrer"&gt;GitHub Flavored Markdown Spec&lt;/a&gt; related to HTML blocks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Finding Inspiration
&lt;/h3&gt;

&lt;p&gt;To help you get started, I suggest looking at other awesome GitHub profiles for ideas. You can go to &lt;a href="https://github.com/abhisheknaiidu/awesome-github-profile-readme" rel="noopener noreferrer"&gt;awesome-github-profile-readme&lt;/a&gt;, where I've found inspiration when making my profile. &lt;/p&gt;

&lt;p&gt;Since the profiles are open-source, you can use some of the good ideas for your awesome profile!&lt;/p&gt;

&lt;p&gt;You can also check out &lt;a href="https://github.com/jdg2896" rel="noopener noreferrer"&gt;my profile&lt;/a&gt; for some ideas. 😉&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Badges
&lt;/h3&gt;

&lt;p&gt;For adding badges to your profile, you can check out &lt;a href="https://github.com/Ileriayo/markdown-badges" rel="noopener noreferrer"&gt;markdown-badges&lt;/a&gt;. The repository has a wide selection of badges to choose from, ranging from programming languages to streaming platforms like Netflix.&lt;/p&gt;

&lt;p&gt;If you can't find what you're looking for or want to create custom badges, you can go to &lt;a href="https://shields.io/" rel="noopener noreferrer"&gt;shields.io&lt;/a&gt;, which is what &lt;a href="https://github.com/Ileriayo/markdown-badges" rel="noopener noreferrer"&gt;markdown-badges&lt;/a&gt; use. &lt;/p&gt;

&lt;p&gt;Here's an example where I used &lt;a href="https://github.com/Ileriayo/markdown-badges" rel="noopener noreferrer"&gt;markdown-badges&lt;/a&gt; on my profile.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbapwwgnky72rcgyucfz0.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%2Fbapwwgnky72rcgyucfz0.png" alt="Markdown badges example" width="800" height="126"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Adding Icons
&lt;/h3&gt;

&lt;p&gt;For adding a &lt;code&gt;skills&lt;/code&gt; or &lt;code&gt;tech stack&lt;/code&gt; section to your profile, I recommend using &lt;a href="https://github.com/tandpfun/skill-icons" rel="noopener noreferrer"&gt;skill-icons&lt;/a&gt; which provide beautiful icons.&lt;/p&gt;

&lt;p&gt;If your icon is not supported, you can go to &lt;a href="https://simpleicons.org/" rel="noopener noreferrer"&gt;simpleicons&lt;/a&gt;, which has over 2900 SVG icons for popular brands.&lt;/p&gt;

&lt;p&gt;Here's an example where I used &lt;a href="https://github.com/tandpfun/skill-icons" rel="noopener noreferrer"&gt;skill-icons&lt;/a&gt; for my profile's tech stack section. &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff6mmy6fbx0s7wloih2ya.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%2Ff6mmy6fbx0s7wloih2ya.png" alt="Icons example" width="800" height="182"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Using Emojis
&lt;/h3&gt;

&lt;p&gt;In GitHub Flavored Markdown, you can use emojis. To see the full list of supported emojis, you can go to this &lt;a href="https://github.com/ikatyang/emoji-cheat-sheet" rel="noopener noreferrer"&gt;emoji-cheat-sheet&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to get the list of supported emojis yourself, you can use &lt;a href="https://docs.github.com/en/rest/emojis/emojis#get-emojis" rel="noopener noreferrer"&gt;GitHub's Emoji API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Going to &lt;a href="https://api.github.com/emojis" rel="noopener noreferrer"&gt;https://api.github.com/emojis&lt;/a&gt; on your browser should show a JSON response of all supported emojis.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"+1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.githubassets.com/images/icons/emoji/unicode/1f44d.png?v8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"-1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.githubassets.com/images/icons/emoji/unicode/1f44e.png?v8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"100"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.githubassets.com/images/icons/emoji/unicode/1f4af.png?v8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"1234"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.githubassets.com/images/icons/emoji/unicode/1f522.png?v8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"1st_place_medal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.githubassets.com/images/icons/emoji/unicode/1f947.png?v8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"2nd_place_medal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.githubassets.com/images/icons/emoji/unicode/1f948.png?v8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"3rd_place_medal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.githubassets.com/images/icons/emoji/unicode/1f949.png?v8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"8ball"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.githubassets.com/images/icons/emoji/unicode/1f3b1.png?v8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's an example where I used emojis for my profile.&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%2Fwcmquxyznodiefm72m93.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%2Fwcmquxyznodiefm72m93.png" alt="Emojis example" width="800" height="152"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding GitHub Stats
&lt;/h3&gt;

&lt;p&gt;For adding cards and stats for your GitHub activity, I recommend using &lt;a href="https://github.com/anuraghazra/github-readme-stats" rel="noopener noreferrer"&gt;github-readme-stats&lt;/a&gt;. You can customize your stat cards with different layouts and themes.&lt;/p&gt;

&lt;p&gt;Here's an example where I added GitHub stats to my profile.&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%2Fb8a27lbcpn6v5097qt7v.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%2Fb8a27lbcpn6v5097qt7v.png" alt="GitHub stats example" width="800" height="249"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Quotes
&lt;/h3&gt;

&lt;p&gt;Adding random quotes to your profile can add a nice touch for visitors. I found &lt;a href="https://github.com/PiyushSuthar/github-readme-quotes" rel="noopener noreferrer"&gt;github-readme-quotes&lt;/a&gt; to be useful for doing just that.&lt;/p&gt;

&lt;p&gt;Here's what it looks like on my profile. I personally like to add quotes to provide some value to my profile visitors.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe7p3mvaedem3cqakxn4o.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%2Fe7p3mvaedem3cqakxn4o.png" alt="Quotes example" width="800" height="181"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Improving Accessibility
&lt;/h3&gt;

&lt;p&gt;When customizing your profile, make sure that it is &lt;strong&gt;viewable by as many people as possible&lt;/strong&gt;. Not everyone can view or load images. Some people have disabilities, while others have slow internet connections.&lt;/p&gt;

&lt;p&gt;One way you can improve the &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility" rel="noopener noreferrer"&gt;accessibility&lt;/a&gt; of your profile is by adding descriptive &lt;code&gt;alt text&lt;/code&gt; to your images.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Markdown Image --&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;Image Alt Text&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;image-source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- HTML Image Tag --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Image Alt Text"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"image-source"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then to test your profile's accessibility, you can try to disable image loading on your web browser. Here's a &lt;a href="https://www.wikihow.com/Disable-Images-in-Google-Chrome" rel="noopener noreferrer"&gt;guide&lt;/a&gt; on how to disable image loading for Google Chrome.&lt;/p&gt;

&lt;p&gt;Here's what my profile looks like with image loading disabled on Google Chrome.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhuoitbxhpjx3g49rj052.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%2Fhuoitbxhpjx3g49rj052.png" alt="GitHub profile accessibility example" width="800" height="546"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  More Ideas
&lt;/h3&gt;

&lt;p&gt;For adding more infographics to your profile, I recommend checking out &lt;a href="https://github.com/lowlighter/metrics" rel="noopener noreferrer"&gt;metrics&lt;/a&gt;. This is one of the most starred repositories on GitHub with the &lt;code&gt;github-profile&lt;/code&gt; topic, so I couldn't leave this out.&lt;/p&gt;

&lt;p&gt;Then I found this beautiful resource &lt;a href="https://github.com/rzashakeri/beautify-github-profile" rel="noopener noreferrer"&gt;beautify-github-profile&lt;/a&gt;, where you can find more ways to customize your profile.&lt;/p&gt;

&lt;p&gt;If you're also feeling adventurous, you can explore the &lt;code&gt;github-profile&lt;/code&gt; topic &lt;a href="https://github.com/topics/github-profile" rel="noopener noreferrer"&gt;here&lt;/a&gt;. The repositories are sorted by the number of stars by default. &lt;/p&gt;

&lt;p&gt;Feel free to explore repositories with the &lt;code&gt;github-profile&lt;/code&gt; topic. You might even find ones that aren't used as much but are just what you need.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Profile Achievements
&lt;/h3&gt;

&lt;p&gt;While this is not related to customizing your GitHub profile's &lt;code&gt;README.md&lt;/code&gt;, I feel the need to include it.&lt;/p&gt;

&lt;p&gt;If you go to your GitHub profile, you'll notice an &lt;code&gt;Achievements&lt;/code&gt; section on the left sidebar.&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%2F4r7ooadf32uq1ibzg6cs.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%2F4r7ooadf32uq1ibzg6cs.png" alt="GitHub profile achievements" width="800" height="546"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These achievements are fun to collect and can improve your overall GitHub profile.&lt;/p&gt;

&lt;p&gt;To learn more about what achievements are available and how to get them, check out the &lt;a href="https://github.com/Schweinepriester/github-profile-achievements" rel="noopener noreferrer"&gt;list of GitHub profile achievements&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;To recap, we walked through how to create your GitHub profile. Then I showed how to format your profile with GitHub Flavored Markdown and HTML. After that, I shared where you can get inspiration for your own profile. Finally, I gave tips and resources on ways to customize your profile.&lt;/p&gt;

&lt;p&gt;I hope this can help you in making your awesome GitHub profile. I'd love to see what you can come up with!&lt;/p&gt;

&lt;p&gt;Thank you for reading and feel free to comment or connect with me &lt;a href="https://linktr.ee/jdg28" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/customizing-your-profile/managing-your-profile-readme" rel="noopener noreferrer"&gt;Managing your GitHub profile README&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax" rel="noopener noreferrer"&gt;GitHub Basic Writing and Formatting Syntax&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/abhisheknaiidu/awesome-github-profile-readme" rel="noopener noreferrer"&gt;awesome-github-profile-readme repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Ileriayo/markdown-badges" rel="noopener noreferrer"&gt;markdown-badges repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://shields.io/" rel="noopener noreferrer"&gt;shields.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tandpfun/skill-icons" rel="noopener noreferrer"&gt;skill-icons repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://simpleicons.org/" rel="noopener noreferrer"&gt;simpleicons.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ikatyang/emoji-cheat-sheet" rel="noopener noreferrer"&gt;emoji-cheat-sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/rest/emojis/emojis#get-emojis" rel="noopener noreferrer"&gt;GitHub's Emoji API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/anuraghazra/github-readme-stats" rel="noopener noreferrer"&gt;github-readme-stats repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/PiyushSuthar/github-readme-quotes" rel="noopener noreferrer"&gt;github-readme-quotes repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility" rel="noopener noreferrer"&gt;MDN: What is accessibility?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wikihow.com/Disable-Images-in-Google-Chrome" rel="noopener noreferrer"&gt;Disable Images in Google Chrome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/lowlighter/metrics" rel="noopener noreferrer"&gt;metrics repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rzashakeri/beautify-github-profile" rel="noopener noreferrer"&gt;beautify-github-profile repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/topics/github-profile" rel="noopener noreferrer"&gt;repositories with "github-profile" topic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Schweinepriester/github-profile-achievements" rel="noopener noreferrer"&gt;github-profile-achievements list&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>github</category>
      <category>profile</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Reflections and Goal Setting as a Software Engineer</title>
      <dc:creator>Jasper Gabriel</dc:creator>
      <pubDate>Sun, 31 Dec 2023 02:05:49 +0000</pubDate>
      <link>https://dev.to/jdg2896/reflections-and-goal-setting-as-a-software-engineer-4ddg</link>
      <guid>https://dev.to/jdg2896/reflections-and-goal-setting-as-a-software-engineer-4ddg</guid>
      <description>&lt;p&gt;As software engineers, we're often busy year-round developing new features, fixing production bugs, learning new tech stacks, interacting with different teams, and many more. As a result, we tend to feel tired towards the end of the year. We would use our holiday breaks and vacation leaves to shut off completely, spending time with family and friends, traveling to new places, and doing hobbies like gaming, reading, and whatever makes us feel good.&lt;/p&gt;

&lt;p&gt;Unwinding during our break is completely normal, and is even needed to recharge for the next year. But the break also allows us to take a pause, reflecting on what happened in the past months. Then it gives us the time and space to plan and set big goals, making sure we have something meaningful to work towards and not just run endlessly in the hamster wheel of software engineering.&lt;/p&gt;

&lt;p&gt;In this article, I'll guide you on your journey towards reflecting on past experiences, along with planning for the future with big, ambitious goals. &lt;/p&gt;

&lt;h2&gt;
  
  
  Reflecting on what happened this year
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“We do not learn from experience...we learn from reflecting on experience.” ― John Dewey&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Often, we let the year pass by without really taking a pause. After a tiring year, we just want to binge our favorite shows, play our favorite video games, and so on.&lt;/p&gt;

&lt;p&gt;By reflecting on our past experiences, we can appreciate our achievements, while also remembering the lessons brought by failures and mistakes.&lt;/p&gt;

&lt;p&gt;This holiday break provides an opportunity to do exactly this, reflecting on what happened this year.&lt;/p&gt;

&lt;h3&gt;
  
  
  A framework for reflecting
&lt;/h3&gt;

&lt;p&gt;For your reflections, I suggest starting simple, especially if you haven't done this before.&lt;/p&gt;

&lt;p&gt;Allot a few minutes of your time to answer these questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What have I done this year?&lt;/li&gt;
&lt;li&gt;What have I learned this year?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For question one, think of &lt;strong&gt;all the things you've done, no matter how small&lt;/strong&gt;. Then remember what you felt after finishing the things you've done. &lt;/p&gt;

&lt;p&gt;By remembering all the good that you've done, you appreciate yourself more. &lt;strong&gt;You did a good job this year!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once you've listed all the things you've done and experienced, it's time for question two. &lt;/p&gt;

&lt;p&gt;From those experiences, what are the &lt;strong&gt;lessons or improvements&lt;/strong&gt; that you can make? &lt;/p&gt;

&lt;p&gt;Think about what you could've done better or wish you'd done if you were able to do those things again.&lt;/p&gt;

&lt;p&gt;Take your time in answering these two questions.&lt;/p&gt;

&lt;h3&gt;
  
  
  My reflections
&lt;/h3&gt;

&lt;p&gt;To give you a reference that might spark ideas of your own, here are my reflections.&lt;/p&gt;

&lt;p&gt;During 2023, I've managed to achieve the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Written &lt;strong&gt;12 articles&lt;/strong&gt; (including this one).&lt;/li&gt;
&lt;li&gt;Contributed to &lt;strong&gt;two open-source projects&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Met up with &lt;strong&gt;two professionals&lt;/strong&gt; (a representative at AWS and a founder) over coffee.&lt;/li&gt;
&lt;li&gt;Experienced being at an &lt;strong&gt;early-stage startup&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Watched 13 startups (including ours) pitch live at a &lt;strong&gt;startup incubator's demo day&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Finished the &lt;strong&gt;AWS Startups Build Accelerator&lt;/strong&gt; program.&lt;/li&gt;
&lt;li&gt;Passed the &lt;strong&gt;AWS Certified Cloud Practitioner&lt;/strong&gt; exam.&lt;/li&gt;
&lt;li&gt;Learned &lt;strong&gt;Svelte and SvelteKit&lt;/strong&gt; by going through the interactive tutorials.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then here's what I learned from these experiences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing is not just about writing itself, but all the pre-writing that comes with it. (I'm practicing &lt;a href="https://www.swyx.io/writing-mise-en-place" rel="noopener noreferrer"&gt;Mise en Place Writing&lt;/a&gt;.)&lt;/li&gt;
&lt;li&gt;You can contribute to open-source projects, even if it's just &lt;a href="https://dev.to/jdg2896/how-i-contributed-one-line-of-code-to-ethereum-3poh"&gt;one line of code&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I should prepare more when meeting up with professionals to lessen the awkward moments.&lt;/li&gt;
&lt;li&gt;If I can buy something instead of building it, then I should buy it. (Using existing solutions for your app's login and authentication.)&lt;/li&gt;
&lt;li&gt;When learning new technologies, make it a habit to take notes as you learn. (Writing helps you learn faster, while also having valuable notes that you can share with others.)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Planning for the new year
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“You do not rise to the level of your goals. You fall to the level of your systems.” - James Clear, Atomic Habits&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  A framework for planning and setting goals
&lt;/h3&gt;

&lt;p&gt;For 2024, I've adapted Sahil Bloom's &lt;a href="https://www.sahilbloom.com/annual-planning" rel="noopener noreferrer"&gt;annual planning template&lt;/a&gt;, which I recommend checking out for yourself.&lt;/p&gt;

&lt;p&gt;For setting your goals, there are two main categories, namely &lt;strong&gt;professional&lt;/strong&gt; and &lt;strong&gt;personal&lt;/strong&gt;. We'll be focusing on setting your professional goals, but the framework is also applicable to personal goals.&lt;/p&gt;

&lt;p&gt;There are three steps in setting your professional goals:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose &lt;strong&gt;1-3 big goals&lt;/strong&gt;, they should be &lt;a href="https://en.wikipedia.org/wiki/SMART_criteria" rel="noopener noreferrer"&gt;SMART&lt;/a&gt; (specific, measurable, attainable, relevant, time-bound).&lt;/li&gt;
&lt;li&gt;Set up &lt;strong&gt;1-3 checkpoint goals&lt;/strong&gt; for each &lt;strong&gt;big goal&lt;/strong&gt; you have.&lt;/li&gt;
&lt;li&gt;Plan &lt;strong&gt;2-3 daily actions&lt;/strong&gt; that will give you progress towards your &lt;strong&gt;big goals&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The idea here is that you choose your &lt;strong&gt;big, ambitious goals&lt;/strong&gt; that feel impossible to achieve. Then work backwards from your big goals.&lt;/p&gt;

&lt;p&gt;After choosing your &lt;strong&gt;big goals&lt;/strong&gt;, it's time to set &lt;strong&gt;checkpoint goals&lt;/strong&gt; for each of your big goals. These checkpoint goals are meant to be shorter-term goals, making your big goals easier to work towards. &lt;/p&gt;

&lt;p&gt;For example, I'd like to &lt;strong&gt;read 12 software engineering books&lt;/strong&gt; for next year. In order to achieve this goal, I'll set up &lt;strong&gt;2-3 checkpoint goals&lt;/strong&gt;. So by April 1, I should have already read &lt;strong&gt;three books&lt;/strong&gt;, then by July 1, &lt;strong&gt;six books&lt;/strong&gt;, and by October 1, &lt;strong&gt;nine books&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Checkpoint goals help keep track of your progress, making sure you don't stray away from your big goals.&lt;/p&gt;

&lt;p&gt;Lastly, the most important part of this framework is having &lt;strong&gt;daily actions and systems&lt;/strong&gt; that will slowly get you towards your big goals.&lt;/p&gt;

&lt;p&gt;To continue with the example, if I want to &lt;strong&gt;read three books every three months&lt;/strong&gt;, I'd have to start with my reading habits. I'll start by &lt;strong&gt;reading for 30 minutes daily&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;This is not a strict rule, and some days I'd find myself feeling lazy. On those days, I'd try to read one page at most. &lt;/p&gt;

&lt;p&gt;The important thing is to do your daily habits, even if you don't feel like doing it. Remember, &lt;strong&gt;anything above zero compounds!&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  My goals
&lt;/h3&gt;

&lt;p&gt;To give you an example, here's one of my big goals for 2024:&lt;/p&gt;

&lt;h4&gt;
  
  
  Big goal
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Continue writing &lt;strong&gt;at least 1 article per week&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Checkpoint goals
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Written &lt;strong&gt;at least 13 articles&lt;/strong&gt; by April 1.&lt;/li&gt;
&lt;li&gt;Written &lt;strong&gt;at least 26 articles&lt;/strong&gt; by July 1.&lt;/li&gt;
&lt;li&gt;Written &lt;strong&gt;at least 39 articles&lt;/strong&gt; by October 1.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Daily systems
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Write around 1000 words per day.&lt;/li&gt;
&lt;li&gt;Take notes when learning new stuff.&lt;/li&gt;
&lt;li&gt;Capture notes when consuming articles.&lt;/li&gt;
&lt;li&gt;Document experiences when trying out new stuff.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;To recap, we've walked through the process of reflecting on your past experiences and achievements, along with what you've learned from them. We also covered frameworks for setting your big, ambitious goals, and how to make sure that you're making daily progress towards them.&lt;/p&gt;

&lt;p&gt;I hope this inspires you to take a pause and go on your journey of reflection and planning.&lt;/p&gt;

&lt;p&gt;Thank you for reading and if you have any questions or feedback, I'd love to hear from you. Feel free to comment or connect with me &lt;a href="https://linktr.ee/jdg28" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Create Real-Time Alerts for Blockchain Events with AWS and QuickNode</title>
      <dc:creator>Jasper Gabriel</dc:creator>
      <pubDate>Sat, 23 Dec 2023 12:55:27 +0000</pubDate>
      <link>https://dev.to/jdg2896/how-to-create-real-time-alerts-for-blockchain-events-with-aws-and-quicknode-23oe</link>
      <guid>https://dev.to/jdg2896/how-to-create-real-time-alerts-for-blockchain-events-with-aws-and-quicknode-23oe</guid>
      <description>&lt;p&gt;Blockchains have revolutionized how we store data by introducing the concept of immutable records. This feature allowed &lt;a href="https://ethereum.org/en/" rel="noopener noreferrer"&gt;Ethereum&lt;/a&gt; and other blockchains to create &lt;a href="https://ethereum.org/en/developers/docs/smart-contracts/" rel="noopener noreferrer"&gt;smart contracts&lt;/a&gt;, which are code that can't be changed. Smart contracts ensured that conditions always execute in the same way, which enabled &lt;a href="https://en.wikipedia.org/wiki/Decentralized_application" rel="noopener noreferrer"&gt;decentralized applications&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;One downside of blockchains is that transactions &lt;strong&gt;take time to process&lt;/strong&gt;. This is the price of guaranteeing the &lt;strong&gt;security&lt;/strong&gt; and &lt;strong&gt;immutability&lt;/strong&gt; of records. Knowing that blockchains will take time to process transactions, it is important to have real-time updates, especially for &lt;strong&gt;customer-facing applications&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this article, I'll show you how to create real-time alerts for blockchain events with &lt;a href="https://aws.amazon.com/" rel="noopener noreferrer"&gt;AWS&lt;/a&gt; and &lt;a href="https://www.quicknode.com/" rel="noopener noreferrer"&gt;QuickNode&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  What to expect
&lt;/h2&gt;

&lt;p&gt;To give a brief overview, you'll deploy &lt;strong&gt;AWS infrastructure&lt;/strong&gt; with &lt;a href="https://aws.amazon.com/serverless/sam/" rel="noopener noreferrer"&gt;AWS SAM&lt;/a&gt;, which consists of a webhook that sends email alerts.&lt;/p&gt;

&lt;p&gt;Then you'll create a &lt;strong&gt;QuickAlert notification&lt;/strong&gt; on &lt;a href="https://ethereum.org/en/" rel="noopener noreferrer"&gt;Ethereum&lt;/a&gt; mainnet.&lt;/p&gt;

&lt;p&gt;Once both are deployed, you will receive an email whenever there are transfers of at least 1 million &lt;a href="https://tether.to/en/" rel="noopener noreferrer"&gt;USDT&lt;/a&gt; or &lt;a href="https://www.circle.com/en/usdc" rel="noopener noreferrer"&gt;USDC&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's a high-level diagram on how QuickAlert notifications work.&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%2Fvzvp0iwcdujtt84sfjra.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%2Fvzvp0iwcdujtt84sfjra.png" alt="QuickAlerts high-level diagram" width="772" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; QuickNode only support webhooks as of writing. In the future, they will support email alerts which will make this solution unnecessary.&lt;/p&gt;

&lt;p&gt;Though the solution that I'll give you is flexible since we'll be using a Lambda function, which you can customize to fit your own use cases.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Before we start
&lt;/h2&gt;

&lt;p&gt;To follow along with this guide, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;a href="https://repost.aws/knowledge-center/create-and-activate-aws-account" rel="noopener noreferrer"&gt;AWS Account&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://www.quicknode.com?tap_a=67226-09396e&amp;amp;tap_s=4357026-faa3ca&amp;amp;utm_source=affiliate&amp;amp;utm_campaign=generic&amp;amp;utm_content=affiliate_landing_page&amp;amp;utm_medium=generic" rel="noopener noreferrer"&gt;QuickNode Account&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then knowledge of the following is helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/serverless/sam/" rel="noopener noreferrer"&gt;AWS SAM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Blockchain" rel="noopener noreferrer"&gt;Blockchains&lt;/a&gt; and &lt;a href="https://ethereum.org/en/" rel="noopener noreferrer"&gt;Ethereum&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ethereum.org/en/developers/docs/smart-contracts/" rel="noopener noreferrer"&gt;Smart Contracts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With that out of the way, let's continue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a webhook with AWS Lambda and SNS
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setting up and configuring AWS SAM CLI
&lt;/h3&gt;

&lt;p&gt;Before proceeding, make sure to &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-getting-started.html" rel="noopener noreferrer"&gt;setup&lt;/a&gt; and &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/using-sam-cli-configure.html" rel="noopener noreferrer"&gt;configure&lt;/a&gt; AWS SAM CLI.&lt;/p&gt;

&lt;p&gt;Then verify that you have installed AWS SAM CLI by running &lt;code&gt;sam --version&lt;/code&gt; on your terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SAM CLI, version 1.105.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After you've verified AWS SAM CLI, it's time to create your webhook with AWS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying the sample application
&lt;/h3&gt;

&lt;p&gt;I have provided a sample application in &lt;a href="https://github.com/jdg2896/aws-lambda-sns-poc" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; to help you get started.&lt;/p&gt;

&lt;p&gt;The application uses &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-getting-started.html" rel="noopener noreferrer"&gt;AWS SAM&lt;/a&gt; to deploy the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/api-gateway/" rel="noopener noreferrer"&gt;Amazon API Gateway&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/sns/" rel="noopener noreferrer"&gt;Amazon SNS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhmib306mw3jsknq3jino.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%2Fhmib306mw3jsknq3jino.png" alt="AWS high-level diagram" width="594" height="131"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then to setup the project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the &lt;a href="https://github.com/jdg2896/aws-lambda-sns-poc" rel="noopener noreferrer"&gt;sample application&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Install Node.js dependencies by running &lt;code&gt;npm install&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add your email to the SNS Topic subscription in the &lt;code&gt;template.yaml&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;SnsTopic&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;AWS::SNS::Topic&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;TopicName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SnsTopicEmailAlert&lt;/span&gt;
      &lt;span class="na"&gt;DisplayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SnsTopicEmailAlert&lt;/span&gt;
      &lt;span class="na"&gt;Subscription&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;YOUR EMAIL HERE&amp;gt;&lt;/span&gt;
          &lt;span class="na"&gt;Protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;email&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build the application by running &lt;code&gt;sam build&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deploy the application by running &lt;code&gt;sam deploy&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You should be prompted to deploy the changeset, enter &lt;code&gt;y&lt;/code&gt; to proceed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the deployment is successful, you should see something 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;CloudFormation outputs from deployed stack
-------------------------------------------------------------------------------------------------
Outputs
-------------------------------------------------------------------------------------------------
Key                 WebEndpoint
Description         API Gateway endpoint URL for Prod stage
Value               https://&amp;lt;redacted&amp;gt;.execute-api.ap-southeast-1.amazonaws.com/Prod/
-------------------------------------------------------------------------------------------------

Successfully created/updated stack - aws-lambda-sns-poc in ap-southeast-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Copy the endpoint&lt;/strong&gt; shown in the output. This will be the webhook URL for your QuickAlert notification later.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You can test your webhook with &lt;a href="https://www.postman.com/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt; or other API testing tools to make sure it is working.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Creating a QuickAlert notification
&lt;/h2&gt;

&lt;p&gt;Now that you've successfully created a webhook, it's time to create a QuickAlert notification.&lt;/p&gt;

&lt;p&gt;Register for a &lt;a href="https://www.quicknode.com?tap_a=67226-09396e&amp;amp;tap_s=4357026-faa3ca&amp;amp;utm_source=affiliate&amp;amp;utm_campaign=generic&amp;amp;utm_content=affiliate_landing_page&amp;amp;utm_medium=generic" rel="noopener noreferrer"&gt;free QuickNode account&lt;/a&gt; if you haven't done so already.&lt;/p&gt;

&lt;p&gt;Once you have an account, here are the steps for creating your QuickAlert notification.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Select &lt;strong&gt;QuickAlerts&lt;/strong&gt; on the left sidebar, then click &lt;strong&gt;Create QuickAlert&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgsunzva8v26h3yvo2jhx.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%2Fgsunzva8v26h3yvo2jhx.png" alt="QuickNode QuickAlerts Dashboard" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name your notification to &lt;strong&gt;My QuickAlert&lt;/strong&gt; or any name you like.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Ethereum&lt;/strong&gt; and &lt;strong&gt;Mainnet&lt;/strong&gt; for chain and network.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Blank Template&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then click &lt;strong&gt;Next&lt;/strong&gt; to proceed.&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%2Fzu90er1fnxi8405289lq.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%2Fzu90er1fnxi8405289lq.png" alt="Configuring the QuickAlert notification name, chain, network, and template" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Before continuing, you need to get a &lt;strong&gt;block number&lt;/strong&gt; to test your QuickAlert expression.&lt;/p&gt;

&lt;p&gt;Go to &lt;a href="https://etherscan.io/advanced-filter?tkn=0xdac17f958d2ee523a2206206994597c13d831ec7&amp;amp;txntype=2&amp;amp;amt=1000000%7e100000000" rel="noopener noreferrer"&gt;Etherscan&lt;/a&gt; and choose any transaction you'd like to test.&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%2F3b975zrdya4nv9yjr099.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%2F3b975zrdya4nv9yjr099.png" alt="Finding 1 million USDT and above transfer transactions on Etherscan" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Once you've chosen a transaction, copy the &lt;strong&gt;block number&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fth8sg1286suy5mxuafrb.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%2Fth8sg1286suy5mxuafrb.png" alt="USDT transfer transaction details on Etherscan" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After you've copied the block number:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Paste it on the &lt;strong&gt;Target Block&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Then click &lt;strong&gt;Get Data&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnb38ntg1tmf3e7kfrmxa.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%2Fnb38ntg1tmf3e7kfrmxa.png" alt="Create QuickAlert expression" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I've created a &lt;a href="https://github.com/quiknode-labs/quickalerts-examples/pull/5" rel="noopener noreferrer"&gt;sample expression&lt;/a&gt; to filter out transfers of at least 1 million USDT or USDC.&lt;/p&gt;

&lt;p&gt;Copy this expression and paste it into the &lt;strong&gt;Create Expression&lt;/strong&gt; field.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;tx_logs_address&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0xdac17f958d2ee523a2206206994597c13d831ec7&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
  &lt;span class="nx"&gt;tx_logs_address&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="nx"&gt;tx_logs_topic0&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="nx"&gt;tx_logs_topic1&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;^0x[0]{24}[a-fa-f0-9]{40}$&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="nx"&gt;tx_logs_topic2&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;^0x[0]{24}[a-fa-f0-9]{40}$&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="nx"&gt;tx_logs_topic3&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span class="nx"&gt;tx_logs_data_int&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000000000000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Then click &lt;strong&gt;Test Expression&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You should see your block number in the &lt;strong&gt;Blocks tested against&lt;/strong&gt; section. &lt;/p&gt;

&lt;p&gt;If there's a &lt;strong&gt;check mark&lt;/strong&gt;, it means that your QuickAlert expression is working.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After testing the expression, click &lt;strong&gt;Next&lt;/strong&gt; to proceed.&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%2Fsodimc61sv44c0imcjlv.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%2Fsodimc61sv44c0imcjlv.png" alt="Test QuickAlert expression" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now to create a Destination, click &lt;strong&gt;Create Destination&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyqhcs8aiqa5s6vebc90k.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%2Fyqhcs8aiqa5s6vebc90k.png" alt="Create QuickAlert Destination" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select &lt;strong&gt;Webhook&lt;/strong&gt;, then click &lt;strong&gt;Continue&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcb60dcj665gyjdlhyh1o.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%2Fcb60dcj665gyjdlhyh1o.png" alt="Select Webhook as destination type" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the following for your webhook:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Webhook name to &lt;strong&gt;My Webhook&lt;/strong&gt; or any name you prefer.&lt;/li&gt;
&lt;li&gt;Paste your &lt;strong&gt;webhook&lt;/strong&gt; from earlier to the URL field.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;POST&lt;/strong&gt; for the request type.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;5 - Matched Receipts&lt;/strong&gt; for the payload type.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then Click &lt;strong&gt;Create Webhook&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdkqprvav3yw5xk7j89j.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%2Fmdkqprvav3yw5xk7j89j.png" alt="Configure webhook name, URL, request type, and payload type" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the &lt;strong&gt;slider&lt;/strong&gt; on the right to enable your webhook.&lt;/p&gt;

&lt;p&gt;Then click &lt;strong&gt;Deploy Notification&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fssc4j6t6hehvq2kij59c.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%2Fssc4j6t6hehvq2kij59c.png" alt="Deploy QuickAlert notification" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Testing the QuickAlert Notification
&lt;/h2&gt;

&lt;p&gt;Now that you've created a QuickAlert notification, wait for it to deliver an alert. It usually takes a &lt;strong&gt;few seconds up to a few minutes&lt;/strong&gt; depending on your filter expressions.&lt;/p&gt;

&lt;p&gt;After waiting, refresh the page. &lt;/p&gt;

&lt;p&gt;You should see changes to the &lt;strong&gt;Last delivery&lt;/strong&gt;, which shows the time since the last notification was triggered.&lt;/p&gt;

&lt;p&gt;Then &lt;strong&gt;click anywhere&lt;/strong&gt; on your QuickAlert notification to view the settings.&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%2F2x5ygwoptv66u03sb4ki.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%2F2x5ygwoptv66u03sb4ki.png" alt="Select created QuickAlert" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, you can edit the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Notification Name&lt;/li&gt;
&lt;li&gt;Expression&lt;/li&gt;
&lt;li&gt;Destinations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Scroll down&lt;/strong&gt; to the bottom of the page to see the events.&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%2F8j8nctijo5m8j05hk9o6.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%2F8j8nctijo5m8j05hk9o6.png" alt="QuickAlert notification settings" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you're at the bottom of the page, you should see the &lt;strong&gt;Events&lt;/strong&gt; section.&lt;/p&gt;

&lt;p&gt;This shows all the blockchain events sent by your QuickAlert notification to your webhook.&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%2Fgxhm9p8bwm7l1pf6xveo.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%2Fgxhm9p8bwm7l1pf6xveo.png" alt="QuickAlert notification sent events" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Checking your email for alerts
&lt;/h3&gt;

&lt;p&gt;Now, check the email you've configured earlier to see if you've received any emails.&lt;/p&gt;

&lt;p&gt;You should see something similar.&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%2F9nn3mj4jih762gfudu2m.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%2F9nn3mj4jih762gfudu2m.png" alt="Email alert from SNS" width="800" height="195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then click the &lt;strong&gt;Etherscan link&lt;/strong&gt; to view the transaction.&lt;/p&gt;

&lt;p&gt;You should see &lt;strong&gt;at least 1 million USDT or USDC&lt;/strong&gt; was transferred.&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%2Fezojciweszdd0m5i0ur6.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%2Fezojciweszdd0m5i0ur6.png" alt="Transaction details from email alert" width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you're done testing, don't forget to &lt;strong&gt;disable&lt;/strong&gt; or &lt;strong&gt;delete&lt;/strong&gt; your QuickAlert notification to avoid wasting your credits.&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%2Ftry4y5sq1z0sxdafdaix.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%2Ftry4y5sq1z0sxdafdaix.png" alt="Disable or delete QuickAlert notification" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;To recap, you've successfully created a QuickAlert notification that sends an email whenever there are transfers of at least 1 million USDT or USDC.&lt;/p&gt;

&lt;p&gt;I hope this can help you with integrating real-time blockchain event notifications into your applications.&lt;/p&gt;

&lt;p&gt;Thank you for reading and if you have any questions or feedback, feel free to comment or connect with me &lt;a href="https://linktr.ee/jdg28" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/jdg2896/aws-lambda-sns-poc" rel="noopener noreferrer"&gt;Sample Application: aws-lambda-sns-poc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/" rel="noopener noreferrer"&gt;AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/api-gateway/" rel="noopener noreferrer"&gt;Amazon API Gateway&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/sns/" rel="noopener noreferrer"&gt;Amazon SNS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/serverless/sam/" rel="noopener noreferrer"&gt;AWS SAM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.quicknode.com/" rel="noopener noreferrer"&gt;QuickNode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.quicknode.com/guides/quicknode-products/quickalerts/an-overview-of-quicknodes-quickalerts" rel="noopener noreferrer"&gt;QuickAlerts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ethereum.org/en/" rel="noopener noreferrer"&gt;Ethereum&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ethereum.org/en/developers/docs/smart-contracts/" rel="noopener noreferrer"&gt;Smart Contracts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>quicknode</category>
      <category>quickalerts</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>5 Things I’ve Learned from the AWS Startups Build Accelerator 2023</title>
      <dc:creator>Jasper Gabriel</dc:creator>
      <pubDate>Sun, 17 Dec 2023 12:50:23 +0000</pubDate>
      <link>https://dev.to/jdg2896/5-things-ive-learned-from-the-aws-startups-build-accelerator-2023-5dml</link>
      <guid>https://dev.to/jdg2896/5-things-ive-learned-from-the-aws-startups-build-accelerator-2023-5dml</guid>
      <description>&lt;p&gt;Before &lt;a href="https://www.ycombinator.com/" rel="noopener noreferrer"&gt;Y Combinator&lt;/a&gt; was &lt;a href="https://foundersatwork.posthaven.com/grow-the-puzzle-around-you/" rel="noopener noreferrer"&gt;founded in 2005&lt;/a&gt; and ran its &lt;a href="https://www.businessofbusiness.com/articles/y-combinator-where-are-they-now-first-batch-reddit-twitch/" rel="noopener noreferrer"&gt;first successful summer batch&lt;/a&gt;, startup accelerators weren't a thing. Now, there are &lt;a href="https://about.crunchbase.com/blog/100-startup-accelerators-around-the-world/" rel="noopener noreferrer"&gt;hundreds (if not thousands) of startup accelerators around the world&lt;/a&gt;. One of the accelerator programs startups can join is the &lt;a href="https://aws.amazon.com/startups/accelerators/build" rel="noopener noreferrer"&gt;AWS Startups Build Accelerator&lt;/a&gt;, which is a 10-week virtual program that provides training and support for launching MVPs to market.&lt;/p&gt;

&lt;p&gt;For the 2023 cohort, out of 2000+ startups that applied, 500+ startups were selected for the program &lt;a href="https://www.linkedin.com/posts/p33r-finance_p33r-awsbuildaccelerator-activity-7121072561857208320-U9f-/" rel="noopener noreferrer"&gt;including ours&lt;/a&gt;. The program provided $2,000 in AWS credits, self-paced courses on &lt;a href="https://skillbuilder.aws/" rel="noopener noreferrer"&gt;AWS Skill Builder&lt;/a&gt;, a &lt;a href="https://slack.com/" rel="noopener noreferrer"&gt;Slack&lt;/a&gt; community with other startup founders, and live AMA sessions with AWS Solution Architects. &lt;/p&gt;

&lt;p&gt;In the 10 weeks the program ran, the following topics were covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding Customers&lt;/li&gt;
&lt;li&gt;Frontend Development&lt;/li&gt;
&lt;li&gt;Backend Development&lt;/li&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;li&gt;Scalable Architectures&lt;/li&gt;
&lt;li&gt;Databases &lt;/li&gt;
&lt;li&gt;Best Practices&lt;/li&gt;
&lt;li&gt;Generative AI&lt;/li&gt;
&lt;li&gt;Leveraging Vendors&lt;/li&gt;
&lt;li&gt;Innovating Iteratively Post-Launch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the AWS Startups Build Accelerator for 2023 finally wrapped up, it's time to reflect on the lessons learned. &lt;/p&gt;

&lt;p&gt;In this article, I'll be sharing five things I've learned throughout the program. The lessons cover what I feel is essential for building successful MVPs, which can lead to further funding rounds and startup growth. &lt;/p&gt;

&lt;p&gt;Even though the accelerator program was intended for technical founders, non-technical founders and fellow software engineers can also find some valuable lessons applicable to their own startup journeys.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Focus on the customer
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.intercom.com/blog/making-things-people-want/" rel="noopener noreferrer"&gt;It's easier to make things people want than to make people want things.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One of the recurring themes in the weekly sessions was the emphasis on bringing value to customers. It makes sense since startups try to provide solutions to problems that customers are willing to pay.&lt;/p&gt;

&lt;p&gt;In order to provide value to customers, we first need to define who our potential customers are. One way to do this is by building a &lt;a href="https://blog.hubspot.com/marketing/buyer-persona-research" rel="noopener noreferrer"&gt;Customer Persona&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Here are some questions to answer when building your &lt;strong&gt;customer persona&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who are our customers?&lt;/li&gt;
&lt;li&gt;What are their pain points?&lt;/li&gt;
&lt;li&gt;Why are they trying to solve the pain?&lt;/li&gt;
&lt;li&gt;How can we help them?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you've defined who your customer is, it's time to build something functional that adds value to customers. &lt;/p&gt;

&lt;p&gt;You should also focus on your &lt;a href="https://www.omniconvert.com/what-is/uvp-unique-value-proposition/" rel="noopener noreferrer"&gt;Unique Value Proposition (UVP)&lt;/a&gt;, which defines how your potential customers will benefit from your solution. &lt;/p&gt;

&lt;p&gt;A framework for defining your UVP is, &lt;strong&gt;"We help X do Y by doing Z"&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;When presenting your UVP to your potential customers, focus on the &lt;strong&gt;benefits&lt;/strong&gt;, and reinforce it with &lt;strong&gt;features&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Another thing to keep in mind is the customer's data. Make sure to securely handle customer data, especially &lt;a href="https://www.dol.gov/general/ppii#:~:text=Personal%20Identifiable%20Information%20(PII)%20is,either%20direct%20or%20indirect%20means." rel="noopener noreferrer"&gt;Personally Identifiable Information (PII)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Remember, &lt;a href="https://www.codemotion.com/magazine/frontend/design-ux/ux-design-enhance-data-security/" rel="noopener noreferrer"&gt;data security is part of the user experience&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Scope your MVP
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.linkedin.com/pulse/when-less-more-danger-over-engineering-trienpont-international/" rel="noopener noreferrer"&gt;Don't over-engineer or over-innovate.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you've defined the customer pain points you're trying to solve, it's time to scope your MVP. &lt;/p&gt;

&lt;p&gt;Oftentimes, we make the mistake of thinking too far ahead in the future, losing focus on what's important. &lt;/p&gt;

&lt;p&gt;Remember, the point of building an MVP is to &lt;strong&gt;validate&lt;/strong&gt; if your idea will solve the customer's &lt;strong&gt;pain points&lt;/strong&gt;, and if customers are willing to &lt;strong&gt;pay&lt;/strong&gt; to use your product. &lt;/p&gt;

&lt;p&gt;For scoping out your MVP, here are some guidelines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who are your target customers?&lt;/li&gt;
&lt;li&gt;What is the problem that you're trying to solve?&lt;/li&gt;
&lt;li&gt;How will you solve that problem?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Make sure to focus on features that will provide value to your potential customers.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Leverage existing solutions for non-core functionality
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://softwareengineering.stackexchange.com/questions/29513/is-reinventing-the-wheel-really-all-that-bad" rel="noopener noreferrer"&gt;Don't reinvent the wheel.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After defining both your customers and the scope of your MVP, it's time to start building. &lt;/p&gt;

&lt;p&gt;One mistake that I've encountered a lot is trying to build &lt;strong&gt;every part&lt;/strong&gt; of the system. This can be a costly mistake, especially for early-stage startups where your main goal is to &lt;strong&gt;validate your idea&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;By trying to build parts of your system that don't provide value to customers, you risk losing your ability to move quickly and pivot if your assumptions are wrong. &lt;/p&gt;

&lt;p&gt;There's also an opportunity cost since instead of building actual features that customers want, you're wasting time building something that could easily be built with an existing solution.&lt;/p&gt;

&lt;p&gt;An example of where you can use existing solutions is &lt;strong&gt;authentication and user management&lt;/strong&gt;. Building one from scratch will take a lot of time and won't be as secure as the existing solutions.  &lt;/p&gt;

&lt;p&gt;The exception here is if your startup is focused on providing authentication services, then it's a core part of your business and you should build it. &lt;/p&gt;

&lt;p&gt;Here are some examples of services where you can use existing solutions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Authentication and User Management&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/cognito/" rel="noopener noreferrer"&gt;Cognito&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://auth0.com/" rel="noopener noreferrer"&gt;Auth0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.okta.com/" rel="noopener noreferrer"&gt;Okta&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;AI Solutions&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://openai.com/" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/generative-ai/" rel="noopener noreferrer"&gt;AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cloud.google.com/ai/generative-ai" rel="noopener noreferrer"&gt;Google Cloud&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://azure.microsoft.com/en-us/solutions/ai" rel="noopener noreferrer"&gt;Azure&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;By using existing solutions, you allow your startup to go to market faster, and actually validate your ideas and get customer feedback.&lt;/p&gt;

&lt;p&gt;Just remember, &lt;a href="https://www.tokyodev.com/articles/all-code-is-technical-debt" rel="noopener noreferrer"&gt;every code you write becomes technical debt&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Become a Great Buyer
&lt;/h3&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%2F0t1bhecvglnv0fmn2uaj.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%2F0t1bhecvglnv0fmn2uaj.png" alt="AWS Well-Architected for Vendors" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For guidelines on selecting 3rd-party vendors, the &lt;a href="https://docs.aws.amazon.com/wellarchitected/latest/framework/welcome.html" rel="noopener noreferrer"&gt;AWS Well-Architected Framework&lt;/a&gt; can be applied here.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Operational Excellence&lt;/strong&gt; - Consider differentiation, switching cost, and criticality.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; - Consider compliance attestations in the short to long term.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability&lt;/strong&gt; - Consider reputation, funding, and existing traction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt; - Consider product use patterns, frequency of need, and scalability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost Efficiency&lt;/strong&gt; - Consider vendor costs in the pricing model.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use these guidelines when evaluating which vendor to use. &lt;/p&gt;

&lt;h3&gt;
  
  
  Outgrowing an existing solution
&lt;/h3&gt;

&lt;p&gt;Eventually, if your idea is correct and you've found loyal customers, your startup will go through a rapid growth phase. &lt;/p&gt;

&lt;p&gt;In this case, you might outgrow solutions from existing vendors. You can also use the Well-Architected Framework to re-evaluate if the 3rd-party solutions are still worth it, or if it's time to &lt;strong&gt;move&lt;/strong&gt; to another vendor or &lt;strong&gt;build&lt;/strong&gt; a custom solution. &lt;/p&gt;

&lt;p&gt;It might be time to move away from a vendor if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pricing&lt;/strong&gt; is prohibitively expensive at scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; is not compliant with your business requirements (HIPAA, ISO, SOC2).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt; is not being supported, vendor solution is unstable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt; is not predictable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Leveraging existing solutions with the startup I'm working with
&lt;/h3&gt;

&lt;p&gt;Here is an example of leveraging existing solutions in the startup I'm currently working with. &lt;/p&gt;

&lt;p&gt;We have a service that allows customers to &lt;strong&gt;sell their crypto&lt;/strong&gt; and &lt;strong&gt;receive fiat&lt;/strong&gt; in their &lt;strong&gt;bank accounts or e-wallets&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3gyjxe8t3tkfgfmaok6o.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%2F3gyjxe8t3tkfgfmaok6o.png" alt="Rails by P33R Finance High-Level Architecture" width="774" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are two things in this flow where we opted to use a 3rd-party vendor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transaction gas fee computation&lt;/li&gt;
&lt;li&gt;Blockchain smart contract events alerting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to deposit crypto into the smart contract, we used &lt;a href="https://web3js.org/" rel="noopener noreferrer"&gt;Web3.js&lt;/a&gt; to interact with the smart contract. &lt;/p&gt;

&lt;p&gt;For sending transactions, we needed to properly compute gas fees. In testing our MVP, we've found that sometimes the default gas values provided by Web3.js weren't enough, which caused some transactions to fail.&lt;/p&gt;

&lt;p&gt;Luckily, &lt;a href="https://metamask.io/news/developers/metamasks-gas-api-is-now-available-to-any-developer-via-infura/" rel="noopener noreferrer"&gt;MetaMask's Gas API was recently released to the public&lt;/a&gt;. Since &lt;a href="https://metamask.io/" rel="noopener noreferrer"&gt;MetaMask&lt;/a&gt; is a leading crypto wallet and its Gas API is battle-tested in production, we decided to use their Gas API instead of building our own solution.&lt;/p&gt;

&lt;p&gt;Then after the crypto is deposited to the smart contract, we are using smart contract events to start the process of sending fiat to the customer.&lt;/p&gt;

&lt;p&gt;We originally implemented our own solution to listen and send smart contract events, which I documented &lt;a href="https://dev.to/jdg2896/how-to-implement-and-deploy-a-smart-contract-event-listener-with-aws-cdk-b1"&gt;here&lt;/a&gt;. Later, we found out that it was causing problems and was harder to maintain at this early stage, so we switched to a 3rd-party solution with &lt;a href="https://www.quicknode.com/" rel="noopener noreferrer"&gt;QuickNode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In hindsight, we should've done this from the start, but that's what happens when you reflect on your experiences. You discover better ways to approach a problem or improve an existing solution.  &lt;/p&gt;

&lt;h2&gt;
  
  
  4. Aim for iteration, not perfection
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.aha.io/roadmapping/guide/plans/what-is-a-minimum-lovable-product" rel="noopener noreferrer"&gt;Iterate towards an MLP (Minimum Lovable Product).&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&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%2Fdnwypylsiplqrv041rfg.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%2Fdnwypylsiplqrv041rfg.png" alt="Build, Test, Iterate" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After launching your MVP, you might think the journey is over and you can just wait to gain new customers. Well, not quite.&lt;/p&gt;

&lt;p&gt;The work is just getting started after you launch your MVP. You'll need to continuously test, gather customer feedback, and improve your existing product. That's the only way you'll get and retain loyal customers, and in turn, grow your startup. &lt;/p&gt;

&lt;h3&gt;
  
  
  Testing your MVP
&lt;/h3&gt;

&lt;p&gt;Before conducting tests with real customers, you first need to make sure that you have sufficient monitoring in place for your systems.&lt;/p&gt;

&lt;p&gt;Ideally, you should be monitoring the &lt;strong&gt;health of your systems&lt;/strong&gt; and &lt;strong&gt;key metrics&lt;/strong&gt; that define success for your MVP. By having monitoring in place, you don't rely on customers (you shouldn't) to tell you that your product is not working. &lt;/p&gt;

&lt;p&gt;After ensuring you have proper monitoring, you can conduct testing for your MVP.&lt;/p&gt;

&lt;p&gt;Here are some approaches you can try for testing your MVP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.browserstack.com/guide/what-is-ux-testing" rel="noopener noreferrer"&gt;UX Testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.productplan.com/glossary/beta-test/" rel="noopener noreferrer"&gt;Beta Testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.optimizely.com/optimization-glossary/ab-testing/" rel="noopener noreferrer"&gt;A/B Tests&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here are additional ways to capture customer feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Survey tools:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.surveymonkey.com/" rel="noopener noreferrer"&gt;Survey Monkey&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.typeform.com/try/typeformbrand/" rel="noopener noreferrer"&gt;Typeform&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://www.userinterviews.com/blog/the-ultimate-guide-to-doing-kickass-customer-interviews" rel="noopener noreferrer"&gt;Customer interviews&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://www.questionpro.com/blog/focus-group/" rel="noopener noreferrer"&gt;Focus groups&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;One tip for gathering customer feedback is to make it convenient. &lt;strong&gt;Make it easy for customers to provide feedback&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Then make sure you also have a presence in other channels such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chatbots&lt;/li&gt;
&lt;li&gt;Cloud-based call center&lt;/li&gt;
&lt;li&gt;Notifications (push, SMS, email)&lt;/li&gt;
&lt;li&gt;Social channels&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Iterating your MVP
&lt;/h3&gt;

&lt;p&gt;Once you've gathered enough customer feedback, it's now time to iterate your product. &lt;/p&gt;

&lt;p&gt;Before you can quickly iterate your product, you need to have the proper infrastructure set in place to support fast iterations. Consider setting up &lt;a href="https://about.gitlab.com/topics/ci-cd/" rel="noopener noreferrer"&gt;Continuous Integration / Continuous Deployment (CI/CD)&lt;/a&gt; pipelines and versioning. &lt;/p&gt;

&lt;p&gt;Having a &lt;strong&gt;CI/CD pipeline&lt;/strong&gt; allows you to automate repetitive tasks, such as building deployment files, running unit and integration tests, and so on. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Versioning&lt;/strong&gt; on the other hand allows you to keep track of your deployments, and if an issue occurs, you can quickly pinpoint which version caused the issues.&lt;/p&gt;

&lt;p&gt;After addressing the infrastructure, it's time to review customer feedback. Make sure to allocate time to address issues raised by customers.&lt;/p&gt;

&lt;p&gt;Then here are ways to deal with different types of feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Positive feedback&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Can be published as customer testimonials (with permission)&lt;/li&gt;
&lt;li&gt;Builds credibility and trust&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Negative feedback&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Opportunity to learn, adapt, and adjust approach to better meet customer expectations&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Make sure to reflect the customer's voices into your products, be adaptable, and iterate as needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Document wins and failures
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://plan.io/blog/lessons-learned-from-failed-projects/" rel="noopener noreferrer"&gt;“We do not learn from experience... we learn from reflecting on experience.”&lt;/a&gt; ― John Dewey&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lastly, we should try to put as much as possible into writing. This means adding proper READMEs to code, creating diagrams on the system architecture and user journeys, and documenting decisions with &lt;a href="https://www.ietf.org/standards/rfcs/" rel="noopener noreferrer"&gt;RFCs&lt;/a&gt; and &lt;a href="https://adr.github.io/" rel="noopener noreferrer"&gt;ADRs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I haven't used RFCs and ADRs much, but there should be enough resources to help you get started in the links above.&lt;/p&gt;

&lt;p&gt;Also, here's a useful resource for RFCs, &lt;a href="https://blog.pragmaticengineer.com/rfcs-and-design-docs/" rel="noopener noreferrer"&gt;Companies Using RFCs or Design Docs and Examples of These&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My lack of experience in using tools like RFCs and ADRs showed me the bad side of not properly documenting architecture, code, and decisions. &lt;/p&gt;

&lt;p&gt;Some of the negatives when you don't document wins and failures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;harder to onboard new engineers.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.thrivelearning.com/lms-glossary/what-is-a-knowledge-silo" rel="noopener noreferrer"&gt;knowledge silos&lt;/a&gt;, where information is isolated to a few members of the team.&lt;/li&gt;
&lt;li&gt;issues repeat themselves (because of a lack of proper documentation).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By starting to document wins and failures, only then can we learn from our experiences and be better engineers, be better startups. &lt;/p&gt;

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

&lt;p&gt;To recap, I shared what I've learned in the AWS Startups Build Accelerator 2023, which are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bringing value to customers&lt;/li&gt;
&lt;li&gt;scoping out MVPs&lt;/li&gt;
&lt;li&gt;leveraging existing solutions from vendors&lt;/li&gt;
&lt;li&gt;testing and iterating towards an MLP (Minimum Lovable Product)&lt;/li&gt;
&lt;li&gt;documenting wins and failures. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you've picked up an idea or two from the lessons I shared, and may it help you in your own startup journey. &lt;/p&gt;

&lt;p&gt;Thank you for reading and if you have any questions or feedback, feel free to comment or connect with me &lt;a href="https://linktr.ee/jdg28" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://foundersatwork.posthaven.com/grow-the-puzzle-around-you/" rel="noopener noreferrer"&gt;Grow the Puzzle Around You - Jessica Livingston (Y Combinator)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.businessofbusiness.com/articles/y-combinator-where-are-they-now-first-batch-reddit-twitch/" rel="noopener noreferrer"&gt;Y Combinator's First Batch: Where are they now?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://about.crunchbase.com/blog/100-startup-accelerators-around-the-world/" rel="noopener noreferrer"&gt;100 Startup Accelerators Around the World You Need to Know About&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/startups/accelerators/build" rel="noopener noreferrer"&gt;AWS Startups Build Accelerator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.intercom.com/blog/making-things-people-want/" rel="noopener noreferrer"&gt;Making things people want&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.hubspot.com/marketing/buyer-persona-research" rel="noopener noreferrer"&gt;How to Create Detailed Buyer Personas for Your Business&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.codemotion.com/magazine/frontend/design-ux/ux-design-enhance-data-security/" rel="noopener noreferrer"&gt;7 Ways to Use UX Design to Enhance User Data Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.omniconvert.com/what-is/uvp-unique-value-proposition/" rel="noopener noreferrer"&gt;What is UVP (Unique Value Proposition)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/pulse/when-less-more-danger-over-engineering-trienpont-international/" rel="noopener noreferrer"&gt;When Less Is More: The Danger of Over-Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://softwareengineering.stackexchange.com/questions/29513/is-reinventing-the-wheel-really-all-that-bad" rel="noopener noreferrer"&gt;Is reinventing the wheel really all that bad?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.tokyodev.com/articles/all-code-is-technical-debt" rel="noopener noreferrer"&gt;All code is technical debt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/wellarchitected/latest/framework/welcome.html" rel="noopener noreferrer"&gt;AWS Well-Architected Framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.aha.io/roadmapping/guide/plans/what-is-a-minimum-lovable-product" rel="noopener noreferrer"&gt;What is a Minimum Lovable Product (MLP)?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.browserstack.com/guide/what-is-ux-testing" rel="noopener noreferrer"&gt;What is UX Testing with example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.productplan.com/glossary/beta-test/" rel="noopener noreferrer"&gt;What is Beta Testing?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.optimizely.com/optimization-glossary/ab-testing/" rel="noopener noreferrer"&gt;What is A/B Testing?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.userinterviews.com/blog/the-ultimate-guide-to-doing-kickass-customer-interviews" rel="noopener noreferrer"&gt;The Ultimate Guide to Doing Kickass Customer Interviews&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.questionpro.com/blog/focus-group/" rel="noopener noreferrer"&gt;Focus group: What It Is and How to Conduct It + Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://about.gitlab.com/topics/ci-cd/" rel="noopener noreferrer"&gt;What is CI/CD?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://plan.io/blog/lessons-learned-from-failed-projects/" rel="noopener noreferrer"&gt;What to Do When a Project Fails: How to Document and Share Lessons Learned&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ietf.org/standards/rfcs/" rel="noopener noreferrer"&gt;IETF: Requests For Comment (RFCs)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.pragmaticengineer.com/rfcs-and-design-docs/" rel="noopener noreferrer"&gt;Companies Using RFCs or Design Docs and Examples of These&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://adr.github.io/" rel="noopener noreferrer"&gt;Architectural Decision Records (ADRs)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>startup</category>
      <category>awsstartups</category>
      <category>accelerator</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Starting My AWS Certification Journey as a Certified Cloud Practitioner</title>
      <dc:creator>Jasper Gabriel</dc:creator>
      <pubDate>Sun, 10 Dec 2023 13:58:05 +0000</pubDate>
      <link>https://dev.to/jdg2896/starting-my-aws-certification-journey-as-a-certified-cloud-practitioner-5cec</link>
      <guid>https://dev.to/jdg2896/starting-my-aws-certification-journey-as-a-certified-cloud-practitioner-5cec</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As software engineers, we need to keep up with the pace of technology evolution by constantly learning. One example of evolving tech is cloud computing, which saw the rise of cloud providers like &lt;a href="https://aws.amazon.com/" rel="noopener noreferrer"&gt;AWS&lt;/a&gt; being used in modern-day applications. Since cloud technologies are constantly evolving, certain standards for validating one's skills in the cloud are needed, which is where &lt;a href="https://aws.amazon.com/certification/" rel="noopener noreferrer"&gt;AWS Certifications&lt;/a&gt; come in. &lt;/p&gt;

&lt;p&gt;Getting a certification isn't necessarily needed for most jobs, but having one gives you a sense of accomplishment and something to brag about.&lt;/p&gt;

&lt;p&gt;In this article, I'll share how I got my first AWS certification, starting from my Google Cloud certification, my experience with AWS, scheduling and canceling my AWS Certified Solutions Architect - Associate exam, and finally taking and passing the AWS Certified Cloud Practitioner exam.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before starting my AWS certification journey
&lt;/h2&gt;

&lt;p&gt;Before I share my AWS certification journey, it would be helpful to share my professional background since my previous experiences helped me in getting my first certification.&lt;/p&gt;

&lt;p&gt;Back in 2019, I passed my &lt;a href="https://www.credential.net/947b6933-cf14-4a79-b094-37381ca4d4c3" rel="noopener noreferrer"&gt;Google Cloud Certified Associate Cloud Engineer&lt;/a&gt; exam. &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%2Fayouo0cb5oa6nempjyhe.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%2Fayouo0cb5oa6nempjyhe.png" alt="Google Cloud Certified Associate Cloud Engineer certificate" width="800" height="616"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was my first experience taking a certification exam at a testing center near my previous workplace. Then for my exam preparation, I mostly did hands-on labs in &lt;a href="https://go.qwiklabs.com/" rel="noopener noreferrer"&gt;Qwiklabs&lt;/a&gt;. These hands-on activities helped me retain cloud concepts since Google Cloud (GCP) was my first experience with cloud computing.&lt;/p&gt;

&lt;p&gt;Then in 2020, I started working with AWS. My first two years with AWS were mostly interacting with the Node.js apps I've deployed in &lt;a href="https://aws.amazon.com/ec2/" rel="noopener noreferrer"&gt;EC2&lt;/a&gt; and reviewing logs since we had a DevOps engineer who managed the cloud infrastructure.&lt;/p&gt;

&lt;p&gt;After two years, I moved to a Web3 startup where I was given a lead software engineer role. This new role gave me more hands-on experience with AWS, where  I've learned to implement serverless technologies like &lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;Lambda&lt;/a&gt; and &lt;a href="https://aws.amazon.com/dynamodb/" rel="noopener noreferrer"&gt;DynamoDB&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After a year, I joined a new startup founded by my previous colleagues, where I managed to explore AWS more deeply since I'm the only backend engineer. I architected backend systems using serverless technologies for the POCs and MVPs.&lt;/p&gt;

&lt;p&gt;Here's a summary of the technologies I've used in AWS to give you a sense of my knowledge before taking my AWS certification exam:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/api-gateway/" rel="noopener noreferrer"&gt;Amazon API Gateway&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/step-functions/" rel="noopener noreferrer"&gt;AWS Step Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/dynamodb/" rel="noopener noreferrer"&gt;Amazon DynamoDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/rds/" rel="noopener noreferrer"&gt;Amazon RDS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/s3/" rel="noopener noreferrer"&gt;Amazon S3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/ec2/" rel="noopener noreferrer"&gt;Amazon EC2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/ecs/" rel="noopener noreferrer"&gt;Amazon ECS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/fargate/" rel="noopener noreferrer"&gt;AWS Fargate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/sqs/" rel="noopener noreferrer"&gt;Amazon SQS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/sns/" rel="noopener noreferrer"&gt;Amazon SNS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/ses/" rel="noopener noreferrer"&gt;Amazon SES&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/ecr/" rel="noopener noreferrer"&gt;Amazon ECR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/cognito/" rel="noopener noreferrer"&gt;Amazon Cognito&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/cloudwatch/" rel="noopener noreferrer"&gt;Amazon CloudWatch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/amplify/" rel="noopener noreferrer"&gt;AWS Amplify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/systems-manager/" rel="noopener noreferrer"&gt;AWS Systems Manager&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/systems-manager/features/#Parameter_Store" rel="noopener noreferrer"&gt;AWS Parameter Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/systems-manager/features/#AppConfig" rel="noopener noreferrer"&gt;AWS AppConfig&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://aws.amazon.com/vpc/" rel="noopener noreferrer"&gt;Amazon VPC&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://aws.amazon.com/route53/" rel="noopener noreferrer"&gt;Amazon Route 53&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://aws.amazon.com/serverless/sam/" rel="noopener noreferrer"&gt;AWS SAM&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://aws.amazon.com/cdk/" rel="noopener noreferrer"&gt;AWS CDK&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;With that out of the way, let's continue with my journey.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scheduling and canceling my AWS Certified Solutions Architect - Associate exam
&lt;/h2&gt;

&lt;p&gt;Back in September, I saw a Facebook ad for the &lt;strong&gt;Get AWS Certified: Associate Challenge&lt;/strong&gt; where you can get a &lt;strong&gt;50% discount&lt;/strong&gt; on the exam fee. The fee costs &lt;strong&gt;150 USD&lt;/strong&gt; at the time of writing, so you only need to pay &lt;strong&gt;75 USD&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcxzruup7mh5azbrl1877.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%2Fcxzruup7mh5azbrl1877.png" alt="Get AWS Certified: Associate Challenge ad" width="715" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I signed up for the challenge and received an email with the voucher code.&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%2Fqvg47st5zsev2a7rg9e1.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%2Fqvg47st5zsev2a7rg9e1.png" alt="Get AWS Certified: Associate Challenge email with voucher code" width="717" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then I scheduled my exam in October and reviewed the &lt;a href="https://aws.amazon.com/certification/certified-solutions-architect-associate/" rel="noopener noreferrer"&gt;landing page&lt;/a&gt; and &lt;a href="https://training.resources.awscloud.com/get-certified-solutions-architect-associate" rel="noopener noreferrer"&gt;resource hub&lt;/a&gt; to learn more about the AWS Certified Solutions Architect - Associate certification.&lt;/p&gt;

&lt;p&gt;For my preparation, I did the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reviewed the &lt;a href="https://training.resources.awscloud.com/get-certified-solutions-architect-associate/aws-certified-solutions-architect-associate-exam-guide-2" rel="noopener noreferrer"&gt;exam guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Answered the &lt;a href="https://d1.awsstatic.com/training-and-certification/docs-sa-assoc/AWS-Certified-Solutions-Architect-Associate_Sample-Questions.pdf" rel="noopener noreferrer"&gt;sample exam questions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Took the following &lt;a href="https://skillbuilder.aws/" rel="noopener noreferrer"&gt;AWS Skill Builder&lt;/a&gt; free courses:

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/13266/aws-certified-solutions-architect-associate-official-practice-question-set-saa-c03-english" rel="noopener noreferrer"&gt;Exam Prep Official Practice Question Set&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/14760/exam-prep-aws-certified-solutions-architect-associate-saa-c03" rel="noopener noreferrer"&gt;Exam Prep Standard Course&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/1851/aws-technical-essentials" rel="noopener noreferrer"&gt;AWS Technical Essentials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/8319/architecting-on-aws-online-course-supplement" rel="noopener noreferrer"&gt;Architecting on AWS - Online Course Supplement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://explore.skillbuilder.aws/learn/public/learning_plan/view/1044/solutions-architect-learning-plan" rel="noopener noreferrer"&gt;Solutions Architect Knowledge Badge Assessment&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;For the &lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/13266/aws-certified-solutions-architect-associate-official-practice-question-set-saa-c03-english" rel="noopener noreferrer"&gt;official practice question set&lt;/a&gt;, I scored &lt;strong&gt;50%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy4iv2djl3lx0ydvfke65.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%2Fy4iv2djl3lx0ydvfke65.png" alt="AWS Certified Solutions Architect - Associate Official Practice Question Set (SAA-C03) results" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then for the &lt;a href="https://explore.skillbuilder.aws/learn/public/learning_plan/view/1044/solutions-architect-learning-plan" rel="noopener noreferrer"&gt;Solutions Architect Knowledge Badge Assessment&lt;/a&gt;, I didn't pass. My score was &lt;strong&gt;62.3%&lt;/strong&gt; and the passing score was &lt;strong&gt;80% out of 50 questions&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;If you didn't pass, you can always retake this assessment after 24 hours.&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%2Fq00e8nz5tbuq4b8nmqmq.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%2Fq00e8nz5tbuq4b8nmqmq.png" alt="Solutions Architect Knowledge Badge Assessment results" width="800" height="259"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Given the results of the assessments above and my exam schedule getting nearer, I didn't feel confident enough to proceed with the certification exam. &lt;/p&gt;

&lt;p&gt;Then I decided to reschedule my exam to a later date. When I still felt that I lacked preparation, I finally canceled my certification exam and got a refund.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scheduling my AWS Certified Cloud Practitioner exam
&lt;/h2&gt;

&lt;p&gt;After the Get AWS Certified: Associate Challenge ended in October, I saw another ad for the &lt;strong&gt;Get AWS Certified: Cloud Practitioner Challenge&lt;/strong&gt; where you can get a &lt;strong&gt;25% discount&lt;/strong&gt; on the exam fee. The fee for the AWS Certified Cloud Practitioner exam costs &lt;strong&gt;100 USD&lt;/strong&gt; at the time of writing, so you only need to pay &lt;strong&gt;75 USD&lt;/strong&gt;, which was the same price I paid for the AWS Certified Solutions Architect - Associate exam.&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%2F31fgw30dl2j3quqq7wl3.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%2F31fgw30dl2j3quqq7wl3.png" alt="Get AWS Certified: Cloud Practitioner Challenge ad" width="716" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I signed up for the new challenge and received an email with another voucher code.&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%2Fl2txpr8u8k6os6pspcev.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%2Fl2txpr8u8k6os6pspcev.png" alt="Get AWS Certified: Cloud Practitioner Challenge email with voucher code" width="713" height="596"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing for my AWS Certified Cloud Practitioner exam
&lt;/h2&gt;

&lt;p&gt;To be honest, I only had one day of preparation for this exam. I scheduled the exam on a Monday and ended up cramming my review on a Sunday night.&lt;/p&gt;

&lt;p&gt;But as I've mentioned earlier, I already have over three years of professional experience with AWS. I have also previously attempted to take the AWS Certified Solutions Architect - Associate certification, where the preparation I did carried over. &lt;/p&gt;

&lt;p&gt;For my short preparation, I reviewed the &lt;a href="https://aws.amazon.com/certification/certified-cloud-practitioner/" rel="noopener noreferrer"&gt;AWS Certified Cloud Practitioner page&lt;/a&gt; and took the following &lt;a href="https://skillbuilder.aws/" rel="noopener noreferrer"&gt;AWS Skill Builder&lt;/a&gt; free courses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/14050/aws-certified-cloud-practitioner-official-practice-question-set-clf-c02-english" rel="noopener noreferrer"&gt;Exam Prep Official Question Set: AWS Certified Cloud Practitioner (CLF-C02 - English)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/134/aws-cloud-practitioner-essentials" rel="noopener noreferrer"&gt;AWS Cloud Practitioner Essentials&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here are my results on the assessment tests. &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%2Fhknik7p96fk1df2s2snj.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%2Fhknik7p96fk1df2s2snj.png" alt="AWS Certified Cloud Practitioner Official Practice Question Set results" width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbf5sco73oe860p5g5kih.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%2Fbf5sco73oe860p5g5kih.png" alt="AWS Cloud Practitioner Essentials assessment results" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the &lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/134/aws-cloud-practitioner-essentials" rel="noopener noreferrer"&gt;AWS Cloud Practitioner Essentials course&lt;/a&gt;, I skimmed through the transcripts, finishing the course in three hours. &lt;/p&gt;

&lt;p&gt;Having passed both assessments on the first try, I was more confident going into exam day. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There's also the &lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/16434/exam-prep-standard-course-aws-certified-cloud-practitioner-clf-c02-english" rel="noopener noreferrer"&gt;Exam Prep Standard Course: AWS Certified Cloud Practitioner&lt;/a&gt;, which I didn't take due to lack of time. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Taking my AWS Certified Cloud Practitioner exam
&lt;/h2&gt;

&lt;p&gt;On the exam day, I received a text message saying that I could take the exam earlier from 11:00 am onwards if I wanted to. My exam is scheduled at noon and I'm already planning to go to the testing center one hour early to give myself time to settle down. &lt;/p&gt;

&lt;p&gt;After arriving at the testing center, I did the registration steps; verifying my identity, signing terms and conditions, and emptying my pockets. Then I took a few deep breaths before asking the proctor to start my exam. The proctor showed me to my computer, then I started the test. &lt;/p&gt;

&lt;p&gt;The exam has &lt;strong&gt;65 questions&lt;/strong&gt; with a &lt;strong&gt;90-minute time limit&lt;/strong&gt;. After completing and submitting my answers, I filled up a post-exam survey. Then, the final screen showed that &lt;strong&gt;I had passed the exam&lt;/strong&gt;! &lt;/p&gt;

&lt;p&gt;I finished the exam in &lt;strong&gt;30 minutes&lt;/strong&gt;, which surprised the proctors, and then I happily shared that I passed the exam.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some tips I found helpful when taking the exam
&lt;/h2&gt;

&lt;p&gt;For taking certification exams, or any exam in general, here are tips that I've found helpful.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Rest&lt;/strong&gt; well the night before the exam day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read&lt;/strong&gt; the whole question and understand what is being asked.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you're not sure about your answer to a question:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Skip&lt;/strong&gt; questions you're not sure of and flag them for review later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spend&lt;/strong&gt; one minute max per question, if you still can't answer, review it later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eliminate&lt;/strong&gt; choices when you know it isn't the answer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sometimes, our brains fill in the gaps which ends up misinterpreting the question. That's why I recommend being &lt;strong&gt;intentional&lt;/strong&gt; when reading the question. &lt;/p&gt;

&lt;p&gt;Then for questions you're not sure of, always answer with your &lt;strong&gt;best guess&lt;/strong&gt; and avoid spending &lt;strong&gt;too much time&lt;/strong&gt; on one question. It's important to &lt;strong&gt;keep moving&lt;/strong&gt; since you have &lt;strong&gt;limited time and resources&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For eliminating choices, let's say "a company requires an object storage solution" and you're given four choices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amazon DynamoDB&lt;/li&gt;
&lt;li&gt;AWS Lambda&lt;/li&gt;
&lt;li&gt;Amazon S3&lt;/li&gt;
&lt;li&gt;Amazon RDS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Continuing with the example, you're not familiar with object storage solutions in AWS, but know what DynamoDB, Lambda, and RDS are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DynamoDB is a serverless key-value NoSQL database.&lt;/li&gt;
&lt;li&gt;Lambda is a serverless function.&lt;/li&gt;
&lt;li&gt;RDS is a fully managed relational database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Knowing that none of the services you know are "object storage", you can eliminate them when deciding on your best guess. Then you'll end up answering &lt;strong&gt;Amazon S3&lt;/strong&gt;, which is the correct answer.&lt;/p&gt;

&lt;p&gt;This is a simple example. In actual exams, you might find it harder to eliminate more than one choice for difficult questions. The point is increasing your odds of having a correct answer for questions you're not sure of. This in turn maximizes your chances for passing the exam.&lt;/p&gt;

&lt;h2&gt;
  
  
  Passing the AWS Certified Cloud Practitioner exam
&lt;/h2&gt;

&lt;p&gt;When I got home, I received an email for my &lt;a href="https://www.credly.com/badges/bfdf4f0d-3e2f-4b00-8827-3954e00afc54/public_url" rel="noopener noreferrer"&gt;digital badge&lt;/a&gt; on Credly.&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%2Fghqzop23ydzn01gqh8zv.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%2Fghqzop23ydzn01gqh8zv.png" alt="AWS Certified Cloud Practitioner Digital Badge" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also checked my &lt;a href="https://www.aws.training/certification" rel="noopener noreferrer"&gt;AWS Certification account&lt;/a&gt; and saw the results along with the perks for passing a certification exam, which includes a &lt;strong&gt;50% discount voucher&lt;/strong&gt; for my next certification exam. &lt;/p&gt;

&lt;p&gt;Here are my exam results, where I scored &lt;strong&gt;739/1000&lt;/strong&gt;, which is just a little above the passing score of &lt;strong&gt;700&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fegqki82r05c4rsfvodwi.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%2Fegqki82r05c4rsfvodwi.png" alt="AWS Certified Cloud Practitioner exam result" width="719" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The exam results showed me that my one-day preparation was good enough to pass the exam, while also realizing that I need to have better preparation for my future certification attempts. Ideally, I'd like to pass my future certification exams with a higher buffer from the passing score, scoring at least 800 and above.&lt;/p&gt;

&lt;p&gt;And finally here's my digital certificate.&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%2Fweilhqj2hkc2411wesan.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%2Fweilhqj2hkc2411wesan.png" alt="AWS Certified Cloud Practitioner Digital Certificate" width="800" height="610"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next for me?
&lt;/h2&gt;

&lt;p&gt;In starting my AWS certification journey, I achieved what I set out to do. By passing the AWS Certified Cloud Practitioner foundational certification, it helped me familiarize myself with the certification process and gave me a boost in confidence, while also showing areas for improvement in my preparation and review processes.&lt;/p&gt;

&lt;p&gt;For 2024, I'm targeting the &lt;strong&gt;Application Architect certification path&lt;/strong&gt; shown &lt;a href="https://d1.awsstatic.com/training-and-certification/docs/AWS_certification_paths.pdf" rel="noopener noreferrer"&gt;here&lt;/a&gt;, which consists of the following certifications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/certification/certified-cloud-practitioner/" rel="noopener noreferrer"&gt;AWS Certified Cloud Practitioner&lt;/a&gt; - PASSED&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/certification/certified-solutions-architect-associate/" rel="noopener noreferrer"&gt;AWS Certified Solutions Architect - Associate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/certification/certified-developer-associate/" rel="noopener noreferrer"&gt;AWS Certified Developer - Associate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/certification/certified-devops-engineer-professional/" rel="noopener noreferrer"&gt;AWS Certified DevOps Engineer - Professional&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/certification/certified-solutions-architect-professional/" rel="noopener noreferrer"&gt;AWS Certified Solutions Architect - Professional&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then I'd also want to take the &lt;a href="https://aws.amazon.com/certification/certified-security-specialty/" rel="noopener noreferrer"&gt;AWS Certified Security - Specialty&lt;/a&gt; certification if I still have time, since security is important for cloud-based solutions.&lt;/p&gt;

&lt;p&gt;I hope my experience can help and give you ideas for your own AWS certification journey. &lt;/p&gt;

&lt;p&gt;Thank you for reading and if you have any questions or feedback, feel free to comment or connect with me &lt;a href="https://linktr.ee/jdg28" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;h3&gt;
  
  
  AWS Certified Cloud Practitioner
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/certification/certified-cloud-practitioner/" rel="noopener noreferrer"&gt;AWS Certified Cloud Practitioner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/14050/aws-certified-cloud-practitioner-official-practice-question-set-clf-c02-english" rel="noopener noreferrer"&gt;Exam Prep Official Question Set&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/134/aws-cloud-practitioner-essentials" rel="noopener noreferrer"&gt;AWS Cloud Practitioner Essentials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/16434/exam-prep-standard-course-aws-certified-cloud-practitioner-clf-c02-english" rel="noopener noreferrer"&gt;Exam Prep Standard Course&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  AWS Certified Solutions Architect - Associate
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/certification/certified-solutions-architect-associate/" rel="noopener noreferrer"&gt;AWS Certified Solutions Architect - Associate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/13266/aws-certified-solutions-architect-associate-official-practice-question-set-saa-c03-english" rel="noopener noreferrer"&gt;Exam Prep Official Practice Question Set&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/14760/exam-prep-aws-certified-solutions-architect-associate-saa-c03" rel="noopener noreferrer"&gt;Exam Prep Standard Course&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/1851/aws-technical-essentials" rel="noopener noreferrer"&gt;AWS Technical Essentials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://explore.skillbuilder.aws/learn/course/external/view/elearning/8319/architecting-on-aws-online-course-supplement" rel="noopener noreferrer"&gt;Architecting on AWS - Online Course Supplement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://explore.skillbuilder.aws/learn/public/learning_plan/view/1044/solutions-architect-learning-plan" rel="noopener noreferrer"&gt;Solutions Architect Knowledge Badge Assessment&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>certification</category>
      <category>cloudpractitioner</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>A Developer's Journal: Simplifying the Twelve-Factor App</title>
      <dc:creator>Jasper Gabriel</dc:creator>
      <pubDate>Sun, 03 Dec 2023 14:06:00 +0000</pubDate>
      <link>https://dev.to/jdg2896/a-developers-journal-simplifying-the-twelve-factor-app-25o</link>
      <guid>https://dev.to/jdg2896/a-developers-journal-simplifying-the-twelve-factor-app-25o</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In my journey of constantly learning, while going through week 7 of the &lt;a href="https://aws.amazon.com/startups/accelerators/build" rel="noopener noreferrer"&gt;AWS Build Accelerator 2023&lt;/a&gt; on software engineering best practices, I encountered the concept of the &lt;a href="https://12factor.net/" rel="noopener noreferrer"&gt;Twelve-Factor App&lt;/a&gt;. Naturally, I was curious and read the document to learn about the best practices derived from the authors' experiences in building, deploying, and scaling production applications. &lt;/p&gt;

&lt;p&gt;If you're a developer looking for a quick read on what the Twelve-Factor app is, then you've come to the right place.&lt;/p&gt;

&lt;p&gt;In this article, I try to simplify the concepts that I've read from the Twelve-Factor App. I've also included high-level illustrations that use practical examples and AWS services.&lt;/p&gt;

&lt;p&gt;Then, let's define what a Twelve-Factor App is.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Twelve-Factor App?
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://12factor.net/" rel="noopener noreferrer"&gt;Twelve-Factor App&lt;/a&gt; is a collection of best practices for building scalable applications. These were documented from the experiences and observations of contributors from &lt;a href="https://www.heroku.com/" rel="noopener noreferrer"&gt;Heroku&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;According to them, &lt;strong&gt;Twelve-Factor Apps&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;automate setup processes&lt;/strong&gt; to minimize friction when onboarding new developers&lt;/li&gt;
&lt;li&gt;are &lt;strong&gt;portable&lt;/strong&gt; between different execution environments&lt;/li&gt;
&lt;li&gt;can be deployed on &lt;strong&gt;modern cloud providers&lt;/strong&gt; such as AWS, GCP, and Azure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;minimize differences&lt;/strong&gt; between development and production environments and &lt;strong&gt;use CI/CD&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;can &lt;strong&gt;scale out&lt;/strong&gt; without significant changes to the architecture.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To make our applications compliant with the definition of Twelve-Factor Apps, there are twelve guidelines to consider.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Codebase
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;One codebase tracked in revision control, many deploys&lt;/em&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  A Twelve-Factor App is:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;tracked in a &lt;a href="https://en.wikipedia.org/wiki/Version_control" rel="noopener noreferrer"&gt;version control system (VCS)&lt;/a&gt;.

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/" rel="noopener noreferrer"&gt;Git&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mercurial-scm.org/" rel="noopener noreferrer"&gt;Mercurial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://subversion.apache.org/" rel="noopener noreferrer"&gt;Subversion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;correlated to &lt;strong&gt;one codebase&lt;/strong&gt;.&lt;/li&gt;

&lt;li&gt;deployed to different environments using the same codebase.

&lt;ul&gt;
&lt;li&gt;Production&lt;/li&gt;
&lt;li&gt;Staging&lt;/li&gt;
&lt;li&gt;Local development&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F03fqf4si7qj1q3snz2kv.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%2F03fqf4si7qj1q3snz2kv.png" alt="Twelve-Factor App Codebase" width="525" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  A Twelve-Factor App &lt;strong&gt;does not&lt;/strong&gt;:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;have &lt;strong&gt;multiple codebases&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;Multiple codebases are &lt;strong&gt;distributed systems&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Each &lt;strong&gt;component&lt;/strong&gt; of the distributed system is an &lt;strong&gt;app&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;share the &lt;strong&gt;same code&lt;/strong&gt; with &lt;strong&gt;different apps&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;Use shared libraries for sharing code to multiple apps.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0vjc0hzosncmlpouas35.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%2F0vjc0hzosncmlpouas35.png" alt="Twelve-Factor App Distributed System" width="550" height="739"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Dependencies
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Explicitly declare and isolate dependencies&lt;/em&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  A Twelve-Factor App:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;explicitly declare dependencies.&lt;/li&gt;
&lt;li&gt;uses package managers.

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/" rel="noopener noreferrer"&gt;npm&lt;/a&gt; (JavaScript)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pypi.org/project/pip/" rel="noopener noreferrer"&gt;pip&lt;/a&gt; (Python)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;doesn't rely on system-wide packages.&lt;/li&gt;

&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Not relying on system-wide packages means that you should declare all dependencies needed to run your application. &lt;/p&gt;

&lt;p&gt;An alternative here is using &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; to build your application, then you can be sure that your app has access to packages in the operating system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By following the guidelines on app dependencies, developers can run the app locally with only the language runtime and dependency manager (JavaScript and npm, Python and pip).&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%2Fhgv8gi153vzfp9oecb6g.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%2Fhgv8gi153vzfp9oecb6g.png" alt="Twelve-Factor App Dependencies" width="562" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Config
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Store config in the environment&lt;/em&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  A Twelve-Factor App:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;stores configs in the environment (&lt;code&gt;.env&lt;/code&gt; file).&lt;/li&gt;
&lt;li&gt;has &lt;strong&gt;different configs&lt;/strong&gt; for each deployment. &lt;/li&gt;
&lt;li&gt;has &lt;strong&gt;no hard-coded configs&lt;/strong&gt; in the codebase.

&lt;ul&gt;
&lt;li&gt;A codebase doesn't have hard-coded configs if you can &lt;strong&gt;open-source&lt;/strong&gt; it without leaking credentials.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frftsshb4mv8cqjxbfg88.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%2Frftsshb4mv8cqjxbfg88.png" alt="Twelve-Factor App Config" width="724" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Backing services
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Treat backing services as attached resources&lt;/em&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  A Twelve-Factor App can:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;use &lt;strong&gt;local&lt;/strong&gt; and &lt;strong&gt;third-party services&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;The app can use a local &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt; and has no issues using a cloud service like &lt;a href="https://aws.amazon.com/rds/" rel="noopener noreferrer"&gt;Amazon RDS&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;add, remove, or replace backing services as needed.

&lt;ul&gt;
&lt;li&gt;If there is a database issue, you can spin up a new database restored from a recent backup.&lt;/li&gt;
&lt;li&gt;There should be no code changes needed.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Backing services are used by the app over the network.&lt;/p&gt;

&lt;h4&gt;
  
  
  Examples of backing services are:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data Stores&lt;/strong&gt; (&lt;a href="https://aws.amazon.com/rds/" rel="noopener noreferrer"&gt;Amazon RDS&lt;/a&gt;, &lt;a href="https://www.mysql.com/" rel="noopener noreferrer"&gt;MySQL&lt;/a&gt;, &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Messaging/Queueing Systems&lt;/strong&gt; (&lt;a href="https://aws.amazon.com/sqs/" rel="noopener noreferrer"&gt;Amazon SQS&lt;/a&gt;, &lt;a href="https://www.rabbitmq.com/" rel="noopener noreferrer"&gt;RabbitMQ&lt;/a&gt;, &lt;a href="https://beanstalkd.github.io/" rel="noopener noreferrer"&gt;Beanstalkd&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SMTP&lt;/strong&gt; (&lt;a href="https://aws.amazon.com/ses/" rel="noopener noreferrer"&gt;Amazon SES&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching Systems&lt;/strong&gt; (&lt;a href="https://aws.amazon.com/elasticache/" rel="noopener noreferrer"&gt;Amazon ElastiCache&lt;/a&gt;, &lt;a href="https://memcached.org/" rel="noopener noreferrer"&gt;Memcached&lt;/a&gt;, &lt;a href="https://redis.io/" rel="noopener noreferrer"&gt;Redis&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3htx8lfuxsl1ebjtylw2.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%2F3htx8lfuxsl1ebjtylw2.png" alt="Twelve-Factor App Backing Services" width="401" height="543"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Build, release, run
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Strictly separate build and run stages&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Build stage&lt;/strong&gt; converts code into an executable bundle, fetches dependencies, and compiles binaries and assets.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A build is triggered by developers when &lt;strong&gt;new code is deployed&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The build stage allows &lt;strong&gt;complex workflows&lt;/strong&gt; such as adding &lt;strong&gt;unit and integration tests&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;Release stage&lt;/strong&gt; combines the build with deployment configs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A release should have a &lt;strong&gt;unique release ID&lt;/strong&gt;, with a timestamp, or an incrementing number.&lt;/li&gt;
&lt;li&gt;Deployment tools have &lt;strong&gt;release management tools&lt;/strong&gt;, where you can roll back to a previous release.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;Runtime stage&lt;/strong&gt; runs the app in the execution environment.&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%2Fgwi9eummmni1r0454e9v.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%2Fgwi9eummmni1r0454e9v.png" alt="Twelve-Factor App Build, Release, Run" width="749" height="559"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Processes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Execute the app as one or more stateless processes&lt;/em&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  A Twelve-Factor App:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;is &lt;strong&gt;stateless&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;never assumes that anything cached will be available for a future request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;stores data&lt;/strong&gt; that needs to be persisted in a &lt;strong&gt;stateful backing service&lt;/strong&gt; like a database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;stores session state&lt;/strong&gt; in a &lt;strong&gt;session store&lt;/strong&gt; like &lt;a href="https://memcached.org/" rel="noopener noreferrer"&gt;Memcached&lt;/a&gt; or &lt;a href="https://redis.io/" rel="noopener noreferrer"&gt;Redis&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;The memory or filesystem can be used as cache for a single transaction. &lt;/p&gt;
&lt;/blockquote&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%2Fgbn188kzy7ksdaqffn1y.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%2Fgbn188kzy7ksdaqffn1y.png" alt="Twelve-Factor App Processes" width="552" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Port binding
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Export services via port binding&lt;/em&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  A Twelve-Factor App:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;exposes HTTP endpoints by port binding.&lt;/li&gt;
&lt;li&gt;listens to incoming requests from the port.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With port binding, an app can be the backing service for another app by providing the backing service URL. For example, a frontend app using a backend app. &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%2Fsc5vqwg8ka6t2si114vo.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%2Fsc5vqwg8ka6t2si114vo.png" alt="Twelve-Factor App Port Binding" width="522" height="585"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Concurrency
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Scale out via the process model&lt;/em&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  A Twelve-Factor App:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;scales out (horizontal scaling) when needing more capacity.&lt;/li&gt;
&lt;li&gt;handles diverse workloads.

&lt;ul&gt;
&lt;li&gt;HTTP requests are handled by a web process.&lt;/li&gt;
&lt;li&gt;Long-running tasks are handled by a worker process.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Scaling out (horizontal scaling)&lt;/strong&gt; is the preferred scaling solution since if you follow the guidelines of the Twelve-Factor App, your application can support more requests by &lt;strong&gt;adding more instances&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scaling up (Vertical scaling)&lt;/strong&gt; is limited in scalability since it only &lt;strong&gt;upgrades the instance configuration&lt;/strong&gt; (memory, CPU, GPU), not to mention you also need to stop that instance to perform the upgrade. &lt;/p&gt;

&lt;p&gt;When building scalable applications, a &lt;strong&gt;mix of scaling up and scaling out&lt;/strong&gt; is ideal. &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%2F1dwhjnas0pmalioiowr8.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%2F1dwhjnas0pmalioiowr8.png" alt="Twelve-Factor App Concurrency" width="527" height="852"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Disposability
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Maximize robustness with fast startup and graceful shutdown&lt;/em&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  A Twelve-Factor App:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;can be started or stopped quickly.&lt;/li&gt;
&lt;li&gt;minimizes startup time.&lt;/li&gt;
&lt;li&gt;shuts down gracefully.&lt;/li&gt;
&lt;li&gt;can handle unexpected, non-graceful terminations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For shutting down gracefully:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;process current requests before shutting down.&lt;/li&gt;
&lt;li&gt;worker process should return unprocessed jobs to the queue.&lt;/li&gt;
&lt;li&gt;jobs should be &lt;a href="https://en.wikipedia.org/wiki/Reentrancy_(computing)" rel="noopener noreferrer"&gt;reentrant&lt;/a&gt; and workers should be &lt;a href="https://en.wikipedia.org/wiki/Idempotence" rel="noopener noreferrer"&gt;idempotent&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkys9nyibg08x8q2l6w7d.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%2Fkys9nyibg08x8q2l6w7d.png" alt="Twelve-Factor App Disposability" width="662" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Dev/prod parity
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Keep development, staging, and production as similar as possible&lt;/em&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  A Twelve-Factor App:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;supports &lt;strong&gt;continuous deployment&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;minimizes time gaps, personnel gaps, and tools gaps.&lt;/li&gt;
&lt;li&gt;has &lt;strong&gt;similar backing services&lt;/strong&gt; for development and production.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Backing services like database, queue, and cache should have dev/prod parity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Types of development process gaps:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time gap&lt;/strong&gt; - A developer works on a feature or bug fix, which takes time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personnel gap&lt;/strong&gt; - A developer writes code, while another developer deploys it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools gap&lt;/strong&gt; - Different tools are used in development and production.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  To &lt;strong&gt;minimize development process gaps&lt;/strong&gt; and &lt;strong&gt;support continuous deployment&lt;/strong&gt;:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Developers should be able to &lt;strong&gt;write code&lt;/strong&gt; and &lt;strong&gt;deploy&lt;/strong&gt; it after a &lt;strong&gt;few minutes&lt;/strong&gt; or a &lt;strong&gt;few hours&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Developers are closely involved in &lt;strong&gt;deploying&lt;/strong&gt; and &lt;strong&gt;observing their code&lt;/strong&gt; in &lt;strong&gt;production&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Development and production should be &lt;strong&gt;as similar as possible&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Tools like &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; and &lt;a href="https://www.vagrantup.com/" rel="noopener noreferrer"&gt;Vagrant&lt;/a&gt; can be used to allow local environments to mimic production environments.&lt;/p&gt;
&lt;/blockquote&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%2F53eacv876x5pgzztav1c.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%2F53eacv876x5pgzztav1c.png" alt="Twelve-Factor App Dev/Prod Parity" width="552" height="651"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  11. Logs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Treat logs as event streams&lt;/em&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  A Twelve-Factor App:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;doesn't route or store it's output logs.&lt;/li&gt;
&lt;li&gt;doesn't write or manage log files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;stream&lt;/strong&gt; logs to different services for &lt;strong&gt;analysis&lt;/strong&gt; and &lt;strong&gt;monitoring&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndk37cz3k0ha8xaidg0r.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%2Fndk37cz3k0ha8xaidg0r.png" alt="Twelve-Factor App Logs" width="444" height="186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  12. Admin processes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Run admin/management tasks as one-off processes&lt;/em&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  A Twelve-Factor App:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;runs admin processes in identical environments.&lt;/li&gt;
&lt;li&gt;deploys admin process code along with the application code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Admin processes can include:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;running database migrations.&lt;/li&gt;
&lt;li&gt;running console commands via SSH.&lt;/li&gt;
&lt;li&gt;running one-time scripts (like fixing bad records).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6gh7qwj0mtmyzo9n5fb.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%2Fs6gh7qwj0mtmyzo9n5fb.png" alt="Twelve-Factor App Admin Processes" width="434" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;To recap, we've learned how we can make our applications more secure and scalable by following the &lt;a href="https://12factor.net/" rel="noopener noreferrer"&gt;Twelve-Factor App&lt;/a&gt; guidelines.&lt;/p&gt;

&lt;p&gt;The Twelve-Factor App consists of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Codebase&lt;/strong&gt; – One codebase tracked in revision control, many deploys&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependencies&lt;/strong&gt; – Explicitly declare and isolate dependencies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration&lt;/strong&gt; – Store configuration in the environment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backing services&lt;/strong&gt; – Treat backing services as attached resources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build, release, run&lt;/strong&gt; – Strictly separate build and run stages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Processes&lt;/strong&gt; – Execute the app as one or more stateless processes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port binding&lt;/strong&gt; – Export services via port binding&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency&lt;/strong&gt; – Scale-out via the process model&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disposability&lt;/strong&gt; – Maximize robustness with fast start-up and graceful shutdown&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dev/prod parity&lt;/strong&gt; – Keep development, staging, and production as similar as possible&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logs&lt;/strong&gt; – Treat logs as event streams&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Admin processes&lt;/strong&gt; – Run admin/management tasks as one-off processes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I recommend reading through the &lt;a href="https://12factor.net/" rel="noopener noreferrer"&gt;Twelve-Factor App&lt;/a&gt; since it's always a good thing to read through the source material. It should take you about an hour or two to finish reading the entire document. &lt;/p&gt;

&lt;p&gt;Thank you for reading and if you have any questions or feedback, feel free to comment or connect with me &lt;a href="https://linktr.ee/jdg28" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://12factor.net/" rel="noopener noreferrer"&gt;The Twelve-Factor App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/compute/applying-the-twelve-factor-app-methodology-to-serverless-applications/" rel="noopener noreferrer"&gt;Applying the Twelve-Factor App Methodology to Serverless Applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://repost.aws/articles/ARYSH2AsjKRnaXhRHrn0HDgA/aws-and-the-12-factor-app-methodology-maximizing-efficiency-and-scalability" rel="noopener noreferrer"&gt;AWS and the 12 Factor App Methodology: Maximizing Efficiency and Scalability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/architecture/twelve-factor-app-development-on-gcp" rel="noopener noreferrer"&gt;Twelve-factor app development on Google Cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.ibm.com/articles/creating-a-12-factor-application-with-open-liberty/" rel="noopener noreferrer"&gt;Creating cloud-native applications: 12-factor applications&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>softwareengineering</category>
      <category>twelvefactorapp</category>
      <category>bestpractices</category>
      <category>aws</category>
    </item>
    <item>
      <title>How I Contributed One Line of Code to Ethereum</title>
      <dc:creator>Jasper Gabriel</dc:creator>
      <pubDate>Sun, 26 Nov 2023 14:18:26 +0000</pubDate>
      <link>https://dev.to/jdg2896/how-i-contributed-one-line-of-code-to-ethereum-3poh</link>
      <guid>https://dev.to/jdg2896/how-i-contributed-one-line-of-code-to-ethereum-3poh</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As a software engineer who has never contributed to &lt;a href="https://opensource.com/resources/what-open-source" rel="noopener noreferrer"&gt;open-source&lt;/a&gt; before 2023, I've been looking for ways to contribute. Being passionate about &lt;a href="https://ethereum.org/en/web3/" rel="noopener noreferrer"&gt;Web3&lt;/a&gt;, I looked for interesting projects in this space. It was not hard to find one where I could contribute since Web3 is about &lt;strong&gt;openness&lt;/strong&gt; and &lt;strong&gt;decentralization&lt;/strong&gt;. Eventually, I found a project where I made my first &lt;a href="https://dev.to/jdg2896/my-first-open-source-contribution-how-i-did-it-1jh6"&gt;open-source contribution&lt;/a&gt; which is &lt;a href="https://taiko.xyz/" rel="noopener noreferrer"&gt;Taiko&lt;/a&gt;, a &lt;a href="https://taiko.mirror.xyz/w7NSKDeKfJoEy0p89I9feixKfdK-20JgWF9HZzxfeBo" rel="noopener noreferrer"&gt;type 1 ZK-EVM&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;After my first open-source contribution, I looked for other projects where I could contribute. One of those projects was &lt;a href="https://ethereum.org/en/" rel="noopener noreferrer"&gt;Ethereum&lt;/a&gt;, which is a blockchain network that enables &lt;a href="https://ethereum.org/en/defi/" rel="noopener noreferrer"&gt;Decentralized Finance&lt;/a&gt;, &lt;a href="https://ethereum.org/en/nft/" rel="noopener noreferrer"&gt;tokenization of assets&lt;/a&gt;, and an &lt;a href="https://ethereum.org/en/dapps/?category=technology" rel="noopener noreferrer"&gt;open internet&lt;/a&gt;. While reading through their contributing guidelines, I found an issue in their documentation and ended up fixing it, making my second open-source contribution.&lt;/p&gt;

&lt;p&gt;In this article, I'll be sharing my journey on how I contributed exactly one line of code to one of Ethereum's open-source repositories, &lt;a href="https://github.com/ethereum/ethereum-org-website" rel="noopener noreferrer"&gt;Ethereum.org&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Looking for ways to contribute to Ethereum
&lt;/h2&gt;

&lt;p&gt;Ethereum has a lot of open-source repositories on their &lt;a href="https://github.com/ethereum" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Some notable repositories I was looking at were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/ethereum/go-ethereum" rel="noopener noreferrer"&gt;Geth&lt;/a&gt; - Official Go implementation of the Ethereum protocol.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ethereum/solidity" rel="noopener noreferrer"&gt;Solidity&lt;/a&gt; - Smart contract programming language.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ethereum/remix-project" rel="noopener noreferrer"&gt;Remix&lt;/a&gt; - Browser-based compiler and IDE for Ethereum smart contracts written with Solidity.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ethereum/ethereum-org-website" rel="noopener noreferrer"&gt;Ethereum.org&lt;/a&gt; - Official website and online resource for the Ethereum community.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When choosing which repository I could contribute to, I had to consider my current skill sets. &lt;/p&gt;

&lt;p&gt;Being proficient in &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript" rel="noopener noreferrer"&gt;JavaScript&lt;/a&gt; and &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt;, Geth and Solidity are out of the question, since Geth requires knowledge of &lt;a href="https://go.dev/" rel="noopener noreferrer"&gt;Go&lt;/a&gt;, while Solidity requires knowing &lt;a href="https://isocpp.org/" rel="noopener noreferrer"&gt;C++&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Remix on the other hand is mostly written in &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt;, while Ethereum.org uses &lt;a href="https://www.markdownguide.org/" rel="noopener noreferrer"&gt;Markdown&lt;/a&gt;. These are the Ethereum projects that I focused on contributing to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding a bug on Ethereum.org's website
&lt;/h2&gt;

&lt;p&gt;After choosing Ethereum.org as a potential repository where I could contribute, I reviewed their website's &lt;a href="https://ethereum.org/en/contributing/" rel="noopener noreferrer"&gt;contributing&lt;/a&gt; section.&lt;/p&gt;

&lt;p&gt;While browsing through the different &lt;a href="https://ethereum.org/en/contributing/" rel="noopener noreferrer"&gt;ways to contribute&lt;/a&gt; to Ethereum.org, I saw their &lt;a href="https://ethereum.org/en/contributing/translation-program/" rel="noopener noreferrer"&gt;translation program&lt;/a&gt; and checked if I could contribute by translating their documentation. As I was reading through the &lt;a href="https://ethereum.org/en/contributing/translation-program/resources" rel="noopener noreferrer"&gt;translation program resources page&lt;/a&gt;, I noticed a broken Discord link in the &lt;a href="https://ethereum.org/en/contributing/translation-program/resources/#office-hours" rel="noopener noreferrer"&gt;Office hours for translators section&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyd91sre3u58ibf6zvb3f.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%2Fyd91sre3u58ibf6zvb3f.png" alt="Ethereum translation program resources: Office hours for translators" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Discord link should redirect to &lt;a href="https://discord.com/invite/rZz26QWfCg" rel="noopener noreferrer"&gt;Ethereum.org's Discord server&lt;/a&gt;. Instead, I got an &lt;code&gt;Invite Invalid&lt;/code&gt; error message.&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%2Fmctcfbri2aqzgbk25dwd.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%2Fmctcfbri2aqzgbk25dwd.png" alt="Ethereum.org Discord " width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Reviewing Ethereum.org's open-source contribution guidelines
&lt;/h2&gt;

&lt;p&gt;Before proceeding to fix the invalid Discord invite link, I reviewed Ethereum.org's &lt;a href="https://github.com/ethereum/ethereum-org-website/blob/dev/CONTRIBUTING.md" rel="noopener noreferrer"&gt;CONTRIBUTING.md&lt;/a&gt; file to make sure I was following their open-source contributing guidelines. &lt;/p&gt;

&lt;p&gt;The guide pointed to the contributing sections in Ethereum.org's &lt;a href="https://ethereum.org/en/contributing/" rel="noopener noreferrer"&gt;website&lt;/a&gt; and &lt;a href="https://github.com/ethereum/ethereum-org-website/tree/dev#-welcome-to-ethereumorg" rel="noopener noreferrer"&gt;README.md&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzglm2jc59tkimjf7o1b5.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%2Fzglm2jc59tkimjf7o1b5.png" alt="Ethereum.org CONTRIBUTING.md" width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an issue on Ethereum.org's GitHub repository
&lt;/h2&gt;

&lt;p&gt;After reviewing the contributing guidelines, I looked at existing &lt;a href="https://github.com/ethereum/ethereum-org-website/issues" rel="noopener noreferrer"&gt;issues&lt;/a&gt; to see if someone else had already reported the &lt;strong&gt;broken Discord invite link&lt;/strong&gt; on the &lt;strong&gt;translation program resources page&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Once I verified that no one else reported the issue, I created an &lt;a href="https://github.com/ethereum/ethereum-org-website/issues/10530" rel="noopener noreferrer"&gt;issue&lt;/a&gt; on Ethereum.org's GitHub repository. &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%2Fib6eg9ps8pw0skdssi0o.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%2Fib6eg9ps8pw0skdssi0o.png" alt="Invalid Discord invite GitHub issue" width="800" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Creating an issue was easy since there are templates for different types of issues. In my case, I needed to create a &lt;strong&gt;Bug report issue&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fro3xx2grnzs4qatfmb62.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%2Fro3xx2grnzs4qatfmb62.png" alt="Creating a bug report issue on Ethereum.org's GitHub repository" width="800" height="298"&gt;&lt;/a&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%2Fvwfgm7imyvqcmbm6ttz1.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%2Fvwfgm7imyvqcmbm6ttz1.png" alt="Creating a bug report issue using a template" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Forking Ethereum.org's repository and testing the fix
&lt;/h2&gt;

&lt;p&gt;After creating the issue, I &lt;a href="https://github.com/jdg2896/ethereum-org-website" rel="noopener noreferrer"&gt;forked Ethereum.org's GitHub repository&lt;/a&gt; and followed their &lt;a href="https://github.com/ethereum/ethereum-org-website#3-set-up-your-local-environment-optional" rel="noopener noreferrer"&gt;local environment setup guide&lt;/a&gt;. Once I've set up my local environment, I started working on the fix. &lt;/p&gt;

&lt;p&gt;The fix was easy since I only needed to replace the Discord invite link with a working one. &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%2Fppyvuyd9j64h04kq7wxq.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%2Fppyvuyd9j64h04kq7wxq.png" alt="Commit that fixes the invalid Ethereum.org Discord invite link" width="800" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I tested the fix locally to verify that the translation page is still working and that my commit fixed the issue. &lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a pull request on Ethereum.org's GitHub repository
&lt;/h2&gt;

&lt;p&gt;After verifying that my commit fixed the &lt;a href="https://github.com/ethereum/ethereum-org-website/issues/10530" rel="noopener noreferrer"&gt;issue&lt;/a&gt;, I created a &lt;a href="https://github.com/ethereum/ethereum-org-website/pull/10531" rel="noopener noreferrer"&gt;pull request&lt;/a&gt; to Ethereum.org's repository with the fix for the invalid Discord invite link.&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%2Fwi0u4nv5irdsfrcp6kuc.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%2Fwi0u4nv5irdsfrcp6kuc.png" alt="Pull request with the fix for the invalid Ethereum.org Discord invite link" width="800" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pull request reviewed and merged!
&lt;/h2&gt;

&lt;p&gt;After creating the pull request, I waited for the code owners and maintainers to review the pull request. &lt;/p&gt;

&lt;p&gt;A few days later, &lt;a href="https://github.com/corwintines" rel="noopener noreferrer"&gt;corwintines&lt;/a&gt; reviewed my &lt;a href="https://github.com/ethereum/ethereum-org-website/pull/10531" rel="noopener noreferrer"&gt;pull request&lt;/a&gt;. In his code review, he gave valuable feedback and updated my code changes by replacing the Discord invite link with the official Ethereum.org Discord invite link.&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%2Fpxgo3rldj27joyz78wrz.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%2Fpxgo3rldj27joyz78wrz.png" alt="Code owner reviews the pull request" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, he approved and merged my pull request. He also thanked me for my contribution, which left a warm feeling even though I only contributed one line of code (less than that if you consider that he updated my code changes).&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%2Fyqiy1s2927crd8zbyklp.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%2Fyqiy1s2927crd8zbyklp.png" alt="Approving and merging the pull request" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the pull request was merged, I also got a &lt;a href="https://www.gitpoap.io/" rel="noopener noreferrer"&gt;GitPOAP&lt;/a&gt;, as recognition for my contribution to Ethereum.org in 2023.&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%2F7svmzijxx87caj8njye9.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%2F7svmzijxx87caj8njye9.png" alt="Ethereum.org GitPOAP" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In this journey, I've learned that it is possible to make small contributions to large projects such as Ethereum. The beauty of open-source is that anyone can make changes, &lt;strong&gt;no matter how small&lt;/strong&gt;. In fact, the majority of open-source contributions fix small issues like the one I encountered. These small changes are also easier for the open-source maintainers to review. &lt;/p&gt;

&lt;p&gt;As the scouts' saying goes, "Always leave the campground cleaner than you found it". For us open-source contributors and software engineers, we should also leave the codebase &lt;strong&gt;better than we first saw it&lt;/strong&gt;. That means if you see a mistake on an open-source documentation, you can suggest a fix to the maintainers. &lt;/p&gt;

&lt;p&gt;If you're looking to make open-source contributions yourself, I hope my story has inspired you to do the same.&lt;/p&gt;

&lt;p&gt;Thank you for reading and if you have any questions or feedback, feel free to comment or connect with me &lt;a href="https://linktr.ee/jdg28" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>opensource</category>
      <category>ethereum</category>
      <category>softwareengineering</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to Implement and Deploy a Smart Contract Event Listener with AWS CDK</title>
      <dc:creator>Jasper Gabriel</dc:creator>
      <pubDate>Sun, 19 Nov 2023 04:26:06 +0000</pubDate>
      <link>https://dev.to/jdg2896/how-to-implement-and-deploy-a-smart-contract-event-listener-with-aws-cdk-b1</link>
      <guid>https://dev.to/jdg2896/how-to-implement-and-deploy-a-smart-contract-event-listener-with-aws-cdk-b1</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When you think of blockchain technologies, Ethereum, and smart contracts come to mind. Ethereum is one of the leading decentralized blockchains that pioneered smart contracts, which are programmable contracts that automatically execute the contract's terms. &lt;/p&gt;

&lt;p&gt;A powerful feature of smart contracts is their ability to emit events after successful transactions. For example, a &lt;code&gt;Transfer&lt;/code&gt; event is emitted when a cryptocurrency like USDT is transferred from one person to another. This feature opens up a lot of possibilities for developers, such as implementing real-time updates into their applications.&lt;/p&gt;

&lt;p&gt;This tutorial will guide you through setting up a smart contract event listener for Ethereum's USDT contract. You'll also learn to deploy the smart contract event listener to AWS using AWS CDK. After that, I'll share my personal experiences in using a smart contract event listener.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before starting
&lt;/h2&gt;

&lt;p&gt;This guide assumes that you're familiar with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript" rel="noopener noreferrer"&gt;JavaScript&lt;/a&gt;, &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt;, and &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ethereum.org/en/" rel="noopener noreferrer"&gt;Ethereum&lt;/a&gt; and &lt;a href="https://ethereum.org/en/developers/docs/smart-contracts/" rel="noopener noreferrer"&gt;Smart Contracts&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then you should be familiar with &lt;a href="https://aws.amazon.com/?nc2=h_lg" rel="noopener noreferrer"&gt;AWS&lt;/a&gt; resources and already have an AWS account. &lt;/p&gt;

&lt;p&gt;If not, then you can follow this &lt;a href="https://docs.aws.amazon.com/accounts/latest/reference/manage-acct-creating.html" rel="noopener noreferrer"&gt;guide&lt;/a&gt; on setting up your AWS account. &lt;/p&gt;

&lt;p&gt;Knowledge of the following is helpful, but not required:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/cli/" rel="noopener noreferrer"&gt;AWS CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/cdk/" rel="noopener noreferrer"&gt;AWS CDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://web3js.org/" rel="noopener noreferrer"&gt;Web3.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ethereum.org/en/developers/tutorials/using-websockets/" rel="noopener noreferrer"&gt;WebSockets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With that out of the way, let's start with setting up the smart contract event listener.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the smart contract event listener
&lt;/h2&gt;

&lt;p&gt;Before we start, make sure to check or clone the &lt;a href="https://github.com/jdg2896/smart-contract-event-listener" rel="noopener noreferrer"&gt;sample repository&lt;/a&gt;, which contains all the necessary code and files for the smart contract event listener. We'll refer to this repository throughout the guide.&lt;/p&gt;

&lt;p&gt;By the end of this section, you'll have a working smart contract event listener that is ready for deployment. &lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the environment variables
&lt;/h2&gt;

&lt;p&gt;To listen to smart contract events, you'll first need to configure two environment variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebSocket endpoint&lt;/li&gt;
&lt;li&gt;Contract address&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Getting the WebSocket endpoint
&lt;/h3&gt;

&lt;p&gt;For this guide, we'll use a WebSocket endpoint from Alchemy, which looks like &lt;code&gt;wss://eth-mainnet.g.alchemy.com/v2/&amp;lt;YOUR_API_KEY&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can get a WebSocket from popular providers such as &lt;a href="https://www.alchemy.com/" rel="noopener noreferrer"&gt;Alchemy&lt;/a&gt; and &lt;a href="https://www.infura.io/" rel="noopener noreferrer"&gt;Infura&lt;/a&gt;. Here's a &lt;a href="https://ethereum.org/en/developers/tutorials/using-websockets/" rel="noopener noreferrer"&gt;guide&lt;/a&gt; for using WebSockets with Alchemy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Getting the smart contract address
&lt;/h3&gt;

&lt;p&gt;For the smart contract address, we'll use Ethereum's &lt;a href="https://etherscan.io/token/0xdac17f958d2ee523a2206206994597c13d831ec7" rel="noopener noreferrer"&gt;USDT&lt;/a&gt; contract, with an address of &lt;code&gt;0xdAC17F958D2ee523a2206206994597C13D831ec7&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Alternatively, if you prefer to use a different smart contract, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find Ethereum smart contracts on &lt;a href="https://etherscan.io/" rel="noopener noreferrer"&gt;Etherscan&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;Locate ERC20 token addresses on &lt;a href="https://www.coingecko.com/" rel="noopener noreferrer"&gt;Coingecko&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Or, use your own deployed contract address.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Remember to update the &lt;code&gt;src/abi.json&lt;/code&gt; file with the ABI for your chosen smart contract. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Depending on your use case, you can choose to listen to events of popular smart contracts or your deployed smart contracts. You can also choose to listen to smart contracts in different blockchain networks as long as it's EVM-compatible and you have a WebSocket endpoint for that blockchain network. &lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring the .env file
&lt;/h3&gt;

&lt;p&gt;Once you have both the &lt;strong&gt;WebSocket endpoint&lt;/strong&gt; and the &lt;strong&gt;smart contract address&lt;/strong&gt;, you can configure your &lt;code&gt;.env&lt;/code&gt; file like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;ETH_WSS_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;wss://eth-mainnet.g.alchemy.com/v2/&amp;lt;YOUR_API_KEY&amp;gt;
&lt;span class="nv"&gt;ETH_SMART_CONTRACT_ADDRESS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0xdac17f958d2ee523a2206206994597c13d831ec7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Reviewing and testing the code
&lt;/h2&gt;

&lt;p&gt;Now that you've set up the environment variables, let's review the code to understand how the smart contract event listener works. We'll also test the code to verify that it works before we deploy it to AWS. &lt;/p&gt;

&lt;h3&gt;
  
  
  Reviewing the smart contract event listener code
&lt;/h3&gt;

&lt;p&gt;The code can be divided into several parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Imports and Workarounds&lt;/strong&gt;:   &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We import the following libraries:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;dotenv&lt;/code&gt; - to load environment variables from &lt;code&gt;.env&lt;/code&gt; files for local development.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;abi.json&lt;/code&gt; - the ABI of the smart contract you plan to listen to. In this case, an ERC20 ABI.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;web3&lt;/code&gt; - library to allow subscription to smart contract events. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Then a workaround is implemented for &lt;code&gt;BigInt&lt;/code&gt; to allow JSON.stringify() of smart contract event logs, which improves the readability of CloudWatch logs when we deploy to AWS later.
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;erc20abi&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./abi.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Web3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Contract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WebSocketProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;web3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/* 
Workaround for JSON.stringify() event logs with BigInt values. 
We need to stringify event logs for more readable logging in CloudWatch.
https://github.com/GoogleChromeLabs/jsbi/issues/30
*/&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toJSON&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&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;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Main Function - &lt;code&gt;startEventListener()&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This function creates a WebSocket connection using your WebSocket endpoint. &lt;/li&gt;
&lt;li&gt;Then, the function subscribes to the smart contract address that you've specified. &lt;/li&gt;
&lt;li&gt;Finally, the function subscribes to the &lt;code&gt;Transfer&lt;/code&gt; and &lt;code&gt;Approval&lt;/code&gt; events using the &lt;code&gt;subscribeToEvent()&lt;/code&gt; function.
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Starts the smart contract event listener. 
 * Websocket Provider config: https://docs.web3js.org/api/web3-providers-ws/class/WebSocketProvider
 * @param chain - Name of the blockchain network for logging purposes.
 * @param wssEndpoint - Websocket endpoint for the blockchain network.
 * @param contractAddress - Smart contract address.
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startEventListener&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;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;wssEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;provider&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;WebSocketProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;wssEndpoint&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="na"&gt;autoReconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Default: 5000 ms&lt;/span&gt;
    &lt;span class="na"&gt;maxAttempts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Default: 5&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Connected to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; websocket provider`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;disconnect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Closed &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; webSocket connection`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;web3&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;Web3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/*
    Smart contract event listeners

    Listening to events:
    - Transfer
    - Approval
*/&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;web3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Contract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;erc20abi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;subscribeToEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Transfer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;subscribeToEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Approval&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Helper Function:  &lt;code&gt;subscribeToEvent()&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This makes the event subscription reusable, especially if you plan to listen to multiple smart contract events. &lt;/li&gt;
&lt;li&gt;After creating a smart contract event subscription, we listen to these subscription events:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;connected&lt;/strong&gt; - it means that you've successfully subscribed to a smart contract event.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;data&lt;/strong&gt; - every time an event is generated by smart contract interactions, you'll receive event logs here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;changed&lt;/strong&gt; - if for some reason the event has been changed or reverted by the blockchain network, you'll receive event logs here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;error&lt;/strong&gt; - if there's an error while listening to smart contract events, you'll receive the error details here.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Subscribes to a smart contract event.
 * @param chain - Name of the blockchain network for logging purposes.
 * @param contract - Smart contract address.
 * @param eventName - Name of the event to subscribe to.
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subscribeToEvent&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;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Contract&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;erc20abi&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;subscription&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;contract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;]();&lt;/span&gt;

&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subscriptionId&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; USDT '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' SubID:`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subscriptionId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; USDT '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="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;event&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt; &lt;span class="c1"&gt;// cannot json.stringify BigInt...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;changed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Remove event from local database&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; USDT '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' error:`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Starting the Listener&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finally, the &lt;code&gt;startEventListener()&lt;/code&gt; function is called to start listening to smart contract events.
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
Start smart contract event listeners

Chains:
    - Ethereum
*/&lt;/span&gt;
&lt;span class="nf"&gt;startEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ethereum&lt;/span&gt;&lt;span class="dl"&gt;'&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;ETH_WSS_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;!&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;ETH_SMART_CONTRACT_ADDRESS&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the full snippet of the smart contract event listener code. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jdg2896/smart-contract-event-listener/blob/main/src/app.ts" rel="noopener noreferrer"&gt;src/app.ts&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;erc20abi&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./abi.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Web3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Contract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WebSocketProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;web3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/* 
  Workaround for JSON.stringify() event logs with BigInt values. 
  We need to stringify event logs for more readable logging in CloudWatch.
  https://github.com/GoogleChromeLabs/jsbi/issues/30
*/&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toJSON&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Starts the smart contract event listener.
 * Websocket Provider config: https://docs.web3js.org/api/web3-providers-ws/class/WebSocketProvider
 * @param chain - Name of the blockchain network for logging purposes.
 * @param wssEndpoint - Websocket endpoint for the blockchain network.
 * @param contractAddress - Smart contract address.
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startEventListener&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;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;wssEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;provider&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;WebSocketProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;wssEndpoint&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="na"&gt;autoReconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Default: 5000 ms&lt;/span&gt;
      &lt;span class="na"&gt;maxAttempts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Default: 5&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Connected to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; websocket provider`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;disconnect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Closed &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; webSocket connection`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;web3&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;Web3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="cm"&gt;/*
    Smart contract event listeners

    Listening to events:
      - Transfer
      - Approval
  */&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;web3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Contract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;erc20abi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;subscribeToEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Transfer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;subscribeToEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Approval&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Subscribes to a smart contract event.
 * @param chain - Name of the blockchain network for logging purposes.
 * @param contract - Smart contract address.
 * @param eventName - Name of the event to subscribe to.
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subscribeToEvent&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;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Contract&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;erc20abi&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="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;subscription&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;contract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;]();&lt;/span&gt;

  &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subscriptionId&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; USDT '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' SubID:`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subscriptionId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; USDT '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="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;event&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt; &lt;span class="c1"&gt;// cannot json.stringify BigInt...&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;changed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Remove event from local database&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; USDT '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;eventName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' error:`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="cm"&gt;/*
  Start smart contract event listeners

  Chains:
    - Ethereum
*/&lt;/span&gt;
&lt;span class="nf"&gt;startEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ethereum&lt;/span&gt;&lt;span class="dl"&gt;'&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;ETH_WSS_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;!&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;ETH_SMART_CONTRACT_ADDRESS&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing the smart contract event listener code
&lt;/h3&gt;

&lt;p&gt;Now that we've reviewed the code, let's test the code to make sure everything is working as expected.&lt;/p&gt;

&lt;p&gt;There are multiple ways to test the code locally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript&lt;/strong&gt;: Run the TypeScript file using &lt;code&gt;ts-node&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm run start:dev&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;JavaScript&lt;/strong&gt;: Build and run the JavaScript file using &lt;code&gt;node&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm run build&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm run start&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Docker:&lt;/strong&gt;: Build the Docker image and run the container:

&lt;ol&gt;
&lt;li&gt;Build the TypeScript file: &lt;code&gt;npm run build&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Build the Docker image: &lt;code&gt;docker build -t smart-contract-event-listener:latest .&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run the Docker container in detached mode: &lt;code&gt;docker run -d --env-file .env --name smart-contract-event-listener smart-contract-event-listener:latest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Get the Docker container logs: &lt;code&gt;docker logs smart-contract-event-listener&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Stop the Docker container: &lt;code&gt;docker stop smart-contract-event-listener&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;I recommend building the Docker image and running the container locally to make sure the code works as expected before deploying to AWS. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After testing, you should see some Ethereum USDT &lt;code&gt;Transfer&lt;/code&gt; and &lt;code&gt;Approval&lt;/code&gt; events in your logs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Ethereum USDT &lt;span class="s1"&gt;'Transfer'&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"event"&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"address"&lt;/span&gt;:&lt;span class="s2"&gt;"0xdac17f958d2ee523a2206206994597c13d831ec7"&lt;/span&gt;,&lt;span class="s2"&gt;"topics"&lt;/span&gt;:[&lt;span class="s2"&gt;"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"&lt;/span&gt;,&lt;span class="s2"&gt;"0x0000000000000000000000001fbcb0803529aea20d6b4af5845fd041e54c50d0"&lt;/span&gt;,&lt;span class="s2"&gt;"0x0000000000000000000000009a4b7d5916d750b9a864f316b9a2483576412bb1"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,&lt;span class="s2"&gt;"data"&lt;/span&gt;:&lt;span class="s2"&gt;"0x000000000000000000000000000000000000000000000000000000000ee6b280"&lt;/span&gt;,&lt;span class="s2"&gt;"blockNumber"&lt;/span&gt;:&lt;span class="s2"&gt;"18597353"&lt;/span&gt;,&lt;span class="s2"&gt;"transactionHash"&lt;/span&gt;:&lt;span class="s2"&gt;"0x61adfbd4a045c02d1b5fea0cce8747dab9b969d552db6091c19168176da6d04c"&lt;/span&gt;,&lt;span class="s2"&gt;"transactionIndex"&lt;/span&gt;:&lt;span class="s2"&gt;"116"&lt;/span&gt;,&lt;span class="s2"&gt;"blockHash"&lt;/span&gt;:&lt;span class="s2"&gt;"0xdc592d23957f1a9fe63e2bd7e03c394b759b7bf48139845877bf0098e82aa8c4"&lt;/span&gt;,&lt;span class="s2"&gt;"logIndex"&lt;/span&gt;:&lt;span class="s2"&gt;"445"&lt;/span&gt;,&lt;span class="s2"&gt;"removed"&lt;/span&gt;:false,&lt;span class="s2"&gt;"returnValues"&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;:&lt;span class="s2"&gt;"0x1fBCb0803529AeA20d6B4AF5845FD041E54c50d0"&lt;/span&gt;,&lt;span class="s2"&gt;"1"&lt;/span&gt;:&lt;span class="s2"&gt;"0x9A4b7D5916D750B9A864F316b9a2483576412BB1"&lt;/span&gt;,&lt;span class="s2"&gt;"2"&lt;/span&gt;:&lt;span class="s2"&gt;"250000000"&lt;/span&gt;,&lt;span class="s2"&gt;"__length__"&lt;/span&gt;:3,&lt;span class="s2"&gt;"from"&lt;/span&gt;:&lt;span class="s2"&gt;"0x1fBCb0803529AeA20d6B4AF5845FD041E54c50d0"&lt;/span&gt;,&lt;span class="s2"&gt;"to"&lt;/span&gt;:&lt;span class="s2"&gt;"0x9A4b7D5916D750B9A864F316b9a2483576412BB1"&lt;/span&gt;,&lt;span class="s2"&gt;"value"&lt;/span&gt;:&lt;span class="s2"&gt;"250000000"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,&lt;span class="s2"&gt;"event"&lt;/span&gt;:&lt;span class="s2"&gt;"Transfer"&lt;/span&gt;,&lt;span class="s2"&gt;"signature"&lt;/span&gt;:&lt;span class="s2"&gt;"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"&lt;/span&gt;,&lt;span class="s2"&gt;"raw"&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"data"&lt;/span&gt;:&lt;span class="s2"&gt;"0x000000000000000000000000000000000000000000000000000000000ee6b280"&lt;/span&gt;,&lt;span class="s2"&gt;"topics"&lt;/span&gt;:[&lt;span class="s2"&gt;"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"&lt;/span&gt;,&lt;span class="s2"&gt;"0x0000000000000000000000001fbcb0803529aea20d6b4af5845fd041e54c50d0"&lt;/span&gt;,&lt;span class="s2"&gt;"0x0000000000000000000000009a4b7d5916d750b9a864f316b9a2483576412bb1"&lt;/span&gt;&lt;span class="o"&gt;]}}}&lt;/span&gt;

Ethereum USDT &lt;span class="s1"&gt;'Approval'&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"event"&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"address"&lt;/span&gt;:&lt;span class="s2"&gt;"0xdac17f958d2ee523a2206206994597c13d831ec7"&lt;/span&gt;,&lt;span class="s2"&gt;"topics"&lt;/span&gt;:[&lt;span class="s2"&gt;"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"&lt;/span&gt;,&lt;span class="s2"&gt;"0x00000000000000000000000062844dc43c064253e21b2b8ac830b28f307184f0"&lt;/span&gt;,&lt;span class="s2"&gt;"0x000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,&lt;span class="s2"&gt;"data"&lt;/span&gt;:&lt;span class="s2"&gt;"0x000000000000000000000000000000000000000000000000000000012a05f200"&lt;/span&gt;,&lt;span class="s2"&gt;"blockNumber"&lt;/span&gt;:&lt;span class="s2"&gt;"18597353"&lt;/span&gt;,&lt;span class="s2"&gt;"transactionHash"&lt;/span&gt;:&lt;span class="s2"&gt;"0x29de66457b8cd4895e354aee842404e66ed34e176fdd3582bb3b9352d9ac7c8f"&lt;/span&gt;,&lt;span class="s2"&gt;"transactionIndex"&lt;/span&gt;:&lt;span class="s2"&gt;"129"&lt;/span&gt;,&lt;span class="s2"&gt;"blockHash"&lt;/span&gt;:&lt;span class="s2"&gt;"0xdc592d23957f1a9fe63e2bd7e03c394b759b7bf48139845877bf0098e82aa8c4"&lt;/span&gt;,&lt;span class="s2"&gt;"logIndex"&lt;/span&gt;:&lt;span class="s2"&gt;"465"&lt;/span&gt;,&lt;span class="s2"&gt;"removed"&lt;/span&gt;:false,&lt;span class="s2"&gt;"returnValues"&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;:&lt;span class="s2"&gt;"0x62844Dc43C064253E21B2b8aC830B28f307184F0"&lt;/span&gt;,&lt;span class="s2"&gt;"1"&lt;/span&gt;:&lt;span class="s2"&gt;"0x000000000022D473030F116dDEE9F6B43aC78BA3"&lt;/span&gt;,&lt;span class="s2"&gt;"2"&lt;/span&gt;:&lt;span class="s2"&gt;"5000000000"&lt;/span&gt;,&lt;span class="s2"&gt;"__length__"&lt;/span&gt;:3,&lt;span class="s2"&gt;"owner"&lt;/span&gt;:&lt;span class="s2"&gt;"0x62844Dc43C064253E21B2b8aC830B28f307184F0"&lt;/span&gt;,&lt;span class="s2"&gt;"spender"&lt;/span&gt;:&lt;span class="s2"&gt;"0x000000000022D473030F116dDEE9F6B43aC78BA3"&lt;/span&gt;,&lt;span class="s2"&gt;"value"&lt;/span&gt;:&lt;span class="s2"&gt;"5000000000"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,&lt;span class="s2"&gt;"event"&lt;/span&gt;:&lt;span class="s2"&gt;"Approval"&lt;/span&gt;,&lt;span class="s2"&gt;"signature"&lt;/span&gt;:&lt;span class="s2"&gt;"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"&lt;/span&gt;,&lt;span class="s2"&gt;"raw"&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"data"&lt;/span&gt;:&lt;span class="s2"&gt;"0x000000000000000000000000000000000000000000000000000000012a05f200"&lt;/span&gt;,&lt;span class="s2"&gt;"topics"&lt;/span&gt;:[&lt;span class="s2"&gt;"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"&lt;/span&gt;,&lt;span class="s2"&gt;"0x00000000000000000000000062844dc43c064253e21b2b8ac830b28f307184f0"&lt;/span&gt;,&lt;span class="s2"&gt;"0x000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3"&lt;/span&gt;&lt;span class="o"&gt;]}}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploying the smart contract event listener
&lt;/h2&gt;

&lt;p&gt;Now that you have a working smart contract event listener, we'll deploy the resources to AWS using &lt;a href="https://aws.amazon.com/cdk/" rel="noopener noreferrer"&gt;AWS CDK&lt;/a&gt;, which is an Infrastructure as Code (IaC) tool. AWS CDK allows you to configure, deploy, and manage AWS cloud resources using popular programming languages such as TypeScript. &lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/jdg2896/smart-contract-event-listener" rel="noopener noreferrer"&gt;sample repository&lt;/a&gt; I shared with you earlier is generated with AWS CDK. The smart contract listener code and cloud resources are added after. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For more info on generating your own AWS CDK TypeScript boilerplate, check this &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-typescript.html#typescript-newproject" rel="noopener noreferrer"&gt;AWS documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Installing the AWS CLI
&lt;/h3&gt;

&lt;p&gt;If you don't have AWS CLI installed, you can go to the &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html" rel="noopener noreferrer"&gt;Get Started&lt;/a&gt; section and &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" rel="noopener noreferrer"&gt;Install/Update&lt;/a&gt; section of the AWS CLI documentation. &lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring a named profile in AWS CLI
&lt;/h3&gt;

&lt;p&gt;Now you'll configure your AWS CLI credentials so that you have the permissions needed to deploy AWS resources in the region that you specify.&lt;/p&gt;

&lt;p&gt;You can either configure a &lt;strong&gt;default profile&lt;/strong&gt; or use a &lt;strong&gt;named profile&lt;/strong&gt; for your AWS CLI credentials. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I recommend configuring a named profile especially if you're working with multiple AWS accounts. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Make sure you already have your own AWS IAM account or access keys. If not, then you can refer to this &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html" rel="noopener noreferrer"&gt;guide&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  To configure an AWS CLI named profile:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Run the &lt;code&gt;aws configure --name profile-name&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;Add your AWS IAM account &lt;code&gt;Access Key&lt;/code&gt; and &lt;code&gt;Secret Access Key&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;Specify the &lt;a href="https://aws.amazon.com/about-aws/global-infrastructure/regions_az/?p=ngi&amp;amp;loc=2&amp;amp;refid=c4f45c53-585c-4b31-8fbf-d39fbcdc603a&amp;amp;trkcampaign=innovate-mad-apj" rel="noopener noreferrer"&gt;region&lt;/a&gt; where you'll deploy your AWS resources.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Then to use the credentials in the named profile:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;For Linux or macOS: &lt;code&gt;export AWS_PROFILE=profile-name&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;For Windows: &lt;code&gt;setx AWS_PROFILE profile-name&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information, refer to the &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html#cli-configure-files-using-profiles" rel="noopener noreferrer"&gt;AWS CLI documentation&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Installing the AWS CDK CLI
&lt;/h3&gt;

&lt;p&gt;Now that you've installed and configured AWS CLI, it's time to install AWS CDK CLI. &lt;/p&gt;

&lt;p&gt;To install AWS CDK:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run the install command: &lt;code&gt;npm install -g aws-cdk&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Then check that AWS CDK is installed correctly: &lt;code&gt;cdk --version&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information, refer to the &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_install" rel="noopener noreferrer"&gt;AWS CDK documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reviewing the AWS CDK code
&lt;/h3&gt;

&lt;p&gt;Before we deploy the smart contract event listener, let's review the AWS CDK code and the AWS resources that we'll deploy. &lt;/p&gt;

&lt;p&gt;The first file &lt;code&gt;bin/smart-contract-event-listener.ts&lt;/code&gt; imports the &lt;code&gt;SmartContractEventListenerStack&lt;/code&gt;, then instantiates a CDK app where we can specify the &lt;code&gt;stack name&lt;/code&gt; and optional properties. &lt;/p&gt;

&lt;p&gt;If you noticed in the comments, you can also configure your AWS account and region in the properties. But since you've already configured your AWS CLI credentials earlier, you don't need to uncomment these. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jdg2896/smart-contract-event-listener/blob/main/bin/smart-contract-event-listener.ts" rel="noopener noreferrer"&gt;bin/smart-contract-event-listener.ts&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cp"&gt;#!/usr/bin/env node
&lt;/span&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;source-map-support/register&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SmartContractEventListenerStack&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../lib/smart-contract-event-listener-stack&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SmartContractEventListenerStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SmartContractEventListenerStack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/* If you don't specify 'env', this stack will be environment-agnostic.
   * Account/Region-dependent features and context lookups will not work,
   * but a single synthesized template can be deployed anywhere. */&lt;/span&gt;
  &lt;span class="cm"&gt;/* Uncomment the next line to specialize this stack for the AWS Account
   * and Region that are implied by the current CLI configuration. */&lt;/span&gt;
  &lt;span class="c1"&gt;// env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },&lt;/span&gt;
  &lt;span class="cm"&gt;/* Uncomment the next line if you know exactly what Account and Region you
   * want to deploy the stack to. */&lt;/span&gt;
  &lt;span class="c1"&gt;// env: { account: '123456789012', region: 'us-east-1' },&lt;/span&gt;
  &lt;span class="cm"&gt;/* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the &lt;code&gt;lib/smart-contract-event-listener-stack.ts&lt;/code&gt; file defined the AWS cloud resources that we'll deploy.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;SmartContractEventListenerStack&lt;/code&gt; will deploy the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html" rel="noopener noreferrer"&gt;VPC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/ecs/" rel="noopener noreferrer"&gt;ECS Cluster&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/fargate/" rel="noopener noreferrer"&gt;Fargate Service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/userguide/task_definitions.html" rel="noopener noreferrer"&gt;Fargate Task Definition&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdlieqpdfd%2Fimage%2Fupload%2Fv1700360758%2FSmart%2520Contract%2520Event%2520Listener%2Fecs_kr5yio.svg" 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%2Fres.cloudinary.com%2Fdlieqpdfd%2Fimage%2Fupload%2Fv1700360758%2FSmart%2520Contract%2520Event%2520Listener%2Fecs_kr5yio.svg" alt="SmartContractEventListenerStack Diagram" width="281" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jdg2896/smart-contract-event-listener/blob/main/lib/smart-contract-event-listener-stack.ts" rel="noopener noreferrer"&gt;lib/smart-contract-event-listener-stack.ts&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Construct&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;constructs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-ec2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ecs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-ecs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SmartContractEventListenerVPC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;vpcName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SmartContractEventListenerVPC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// EIP soft limit is 5, need to increase limit to increase AZ&lt;/span&gt;
      &lt;span class="na"&gt;maxAzs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&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;cluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Cluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SmartContractEventListenerCluster&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;clusterName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SmartContractEventListenerCluster&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&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;taskDefinition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FargateTaskDefinition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SmartContractEventListenerTaskDef&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;TaskDef&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;taskDefinition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SmartContractEventListener&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;containerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;ETH_WSS_ENDPOINT&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;ETH_WSS_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;ETH_SMART_CONTRACT_ADDRESS&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;ETH_SMART_CONTRACT_ADDRESS&lt;/span&gt;&lt;span class="o"&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;// can be .fromContainerRegistry() if available to ECR&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ContainerImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AwsLogDriver&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;streamPrefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SmartContractEventListener&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AwsLogDriverMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NON_BLOCKING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ecs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FargateService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SmartContractEventListenerFargateService&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;serviceName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FargateService&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;taskDefinition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploying the AWS resources using AWS CDK
&lt;/h3&gt;

&lt;p&gt;Now that we've reviewed the AWS CDK code and AWS resources, it's time to deploy your smart contract event listener.&lt;/p&gt;

&lt;p&gt;To deploy your smart contract event listener:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build the source files: &lt;code&gt;npm run build&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Deploy the AWS resources: &lt;code&gt;cdk deploy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Review the changes, then when prompted with &lt;code&gt;Do you wish to deploy these changes (y/n)?&lt;/code&gt;, enter &lt;code&gt;y&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You should see a progress bar of the AWS resources that are being deployed. &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjyz2571d18ze1rdc9w7.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%2Fcjyz2571d18ze1rdc9w7.png" alt="AWS CDK deployment progress bar" width="800" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The deployment should take around 5 minutes to complete, so in the meantime, you can take a quick break. &lt;/p&gt;

&lt;p&gt;Once the deployment completes, you should see the deployment time and the CloudFormation stack ARN. &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg3kdjqd4sksgotvdnu2d.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%2Fg3kdjqd4sksgotvdnu2d.png" alt="AWS CDK deployment complete" width="800" height="146"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If your deployment takes longer than 5 minutes and seems to be stuck, then you can check the ECS service logs, as shown in this section. &lt;/p&gt;

&lt;p&gt;If the logs show runtime errors, then you can do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Follow this &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-console-delete-stack.html" rel="noopener noreferrer"&gt;guide&lt;/a&gt; to delete the &lt;code&gt;SmartContractEventListenerStack&lt;/code&gt; in CloudFormation. &lt;/li&gt;
&lt;li&gt;Review and test the code and Docker build locally to verify it's working as intended.&lt;/li&gt;
&lt;li&gt;Build and redeploy using the above steps.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Check the smart contract event listener logs in AWS
&lt;/h3&gt;

&lt;p&gt;Now that you've successfully deployed a smart contract event listener, it's time to verify if it's receiving events from the Ethereum USDT contract or your contract.&lt;/p&gt;

&lt;p&gt;Here are the steps to check the logs from your smart contract event listener:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In the AWS console, go to the &lt;strong&gt;ECS&lt;/strong&gt;, then click on &lt;strong&gt;SmartContractEventListenerCluster&lt;/strong&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F898b5wodxy9go1y6mwbr.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%2F898b5wodxy9go1y6mwbr.png" alt="AWS Console ECS Dashboard" width="800" height="302"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then, go to &lt;strong&gt;Services&lt;/strong&gt;, and click &lt;strong&gt;FargateService&lt;/strong&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foeja446r1bf8820a74zp.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%2Foeja446r1bf8820a74zp.png" alt="AWS Console ECS Services" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, click &lt;strong&gt;Logs&lt;/strong&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7d0p9bzcx09uuv3o444e.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%2F7d0p9bzcx09uuv3o444e.png" alt="AWS Console ECS Logs" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You should now be seeing the logging of events from the Ethereum USDT contract or the smart contract you specified. &lt;/p&gt;

&lt;h3&gt;
  
  
  Cleaning up the AWS resources (Optional)
&lt;/h3&gt;

&lt;p&gt;After testing the smart contract event listener, it's recommended to clean up the deployed AWS resources especially if you're just doing a proof of concept. &lt;/p&gt;

&lt;p&gt;To delete the deployed AWS resources, run the &lt;code&gt;cdk destroy&lt;/code&gt; command. &lt;/p&gt;

&lt;p&gt;This makes sure that you &lt;strong&gt;avoid incurring unnecessary charges&lt;/strong&gt; on your AWS account, since running an ECS cluster is not part of the &lt;a href="https://aws.amazon.com/free/" rel="noopener noreferrer"&gt;AWS Free Tier&lt;/a&gt;, and would incur charges if it's left running in the cloud. &lt;/p&gt;

&lt;h2&gt;
  
  
  Some caveats and improvements to consider
&lt;/h2&gt;

&lt;p&gt;We've verified that the smart contract event listener is working. Now I'll go through some of the caveats and improvements to consider since I've personally implemented a smart contract event listener at the &lt;a href="https://p33r.finance/" rel="noopener noreferrer"&gt;startup&lt;/a&gt; I'm currently working at.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integrating smart contract events into other services
&lt;/h3&gt;

&lt;p&gt;You might be wondering how you can integrate smart contract events into your backend systems, so here are some ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/services-cloudwatchlogs.html" rel="noopener noreferrer"&gt;Trigger a Lambda with CloudWatch Logs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Add code in the smart contract event listener subscriptions to trigger other parts of your system. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would recommend the first idea since Lambda is flexible and can fit a lot of use cases. You can also trigger Lambda functions every time a smart contract event is logged into CloudWatch. &lt;/p&gt;

&lt;p&gt;At &lt;a href="https://www.rails.p33r.finance/" rel="noopener noreferrer"&gt;RAILS by P33R&lt;/a&gt;, we use this approach. The app allows customers to off-ramp their crypto &lt;a href="https://www.investopedia.com/terms/s/stablecoin.asp" rel="noopener noreferrer"&gt;stablecoins&lt;/a&gt; (&lt;a href="https://tether.to/en/" rel="noopener noreferrer"&gt;USDT&lt;/a&gt;, &lt;a href="https://www.circle.com/en/usdc" rel="noopener noreferrer"&gt;USDC&lt;/a&gt;, and &lt;a href="https://makerdao.com/en/" rel="noopener noreferrer"&gt;DAI&lt;/a&gt;) into fiat currencies (SGD, PHP). &lt;/p&gt;

&lt;p&gt;A high-level implementation of the app's crypto-to-fiat use case is shown below. The flow is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Customer&lt;/strong&gt; deposits &lt;strong&gt;crypto stablecoins&lt;/strong&gt; to the &lt;strong&gt;escrow smart contract&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escrow smart contract&lt;/strong&gt; emits a &lt;code&gt;Deposit&lt;/code&gt; event.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart contract event listener&lt;/strong&gt; receives the &lt;code&gt;Deposit&lt;/code&gt; event, and logs to &lt;strong&gt;CloudWatch&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudWatch log&lt;/strong&gt; triggers the &lt;strong&gt;Fiat Disbursement Lambda function&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customer&lt;/strong&gt; receives &lt;strong&gt;fiat&lt;/strong&gt; in their &lt;strong&gt;bank account&lt;/strong&gt; or &lt;strong&gt;e-wallet&lt;/strong&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fdlieqpdfd%2Fimage%2Fupload%2Fv1700309954%2FSmart%2520Contract%2520Event%2520Listener%2FRAILS_High_Level.drawio_rwiyga.svg" 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%2Fres.cloudinary.com%2Fdlieqpdfd%2Fimage%2Fupload%2Fv1700309954%2FSmart%2520Contract%2520Event%2520Listener%2FRAILS_High_Level.drawio_rwiyga.svg" alt="RAILS" width="596" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is an example implementation that you can reference for your own use cases. &lt;/p&gt;

&lt;h3&gt;
  
  
  Health checks and error handling
&lt;/h3&gt;

&lt;p&gt;If you plan to use smart contract event listeners in production, monitoring the health of the service and handling errors is a requirement. &lt;/p&gt;

&lt;p&gt;At the time of writing this, I hadn't figured out how to implement health checks for the smart contract event listeners in ECS. A workaround for this is to implement &lt;a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html" rel="noopener noreferrer"&gt;CloudWatch alarms&lt;/a&gt;. You can send email alerts when the smart contract event listener throws an error. &lt;/p&gt;

&lt;p&gt;I also encountered a specific issue related to the &lt;strong&gt;block limit when querying smart contract events over 10,000 blocks&lt;/strong&gt;. This was an issue with &lt;a href="https://www.quicknode.com/" rel="noopener noreferrer"&gt;QuickNode&lt;/a&gt;, but other providers also have a 10,000 block limit for querying logs and events. For more information, here is &lt;a href="https://support.quicknode.com/hc/en-us/articles/10258449939473-Is-there-a-block-range-limit-for-querying-logs-and-events" rel="noopener noreferrer"&gt;QuickNode's support article&lt;/a&gt; on this topic.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This 10,000 block limit error happens because when you create a smart contract event subscription in &lt;code&gt;Web3.js&lt;/code&gt;, it automatically filters for smart contract events, starting from the block number at the time of the subscription. Let's assume that the current block number is at 1,001. Then the smart contract event listener can safely query for events until block number 11,001. The WebSocket provider will throw an error when the block number exceeds 11,001. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Fortunately, whenever the smart contract event listener throws an error, the ECS cluster will automatically restart the service. This is the default behavior since ECS is a fully managed AWS service for container orchestration. Even with this, it's still important to improve the health checks and error handling, and not fully rely on AWS error handling. &lt;/p&gt;

&lt;h3&gt;
  
  
  Improving reliability with the AWS Well-Architected framework
&lt;/h3&gt;

&lt;p&gt;As we're building cloud infrastructure in AWS, it's important to follow the &lt;a href="https://aws.amazon.com/architecture/well-architected/?wa-lens-whitepapers.sort-by=item.additionalFields.sortDate&amp;amp;wa-lens-whitepapers.sort-order=desc&amp;amp;wa-guidance-whitepapers.sort-by=item.additionalFields.sortDate&amp;amp;wa-guidance-whitepapers.sort-order=desc" rel="noopener noreferrer"&gt;AWS Well-Architected framework&lt;/a&gt;. One of the pillars of the Well-Architected framework is &lt;a href="https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/welcome.html" rel="noopener noreferrer"&gt;Reliability&lt;/a&gt;. This means removing single points of failure in the smart contract event listener, resulting in more resilient architectures. &lt;/p&gt;

&lt;p&gt;One way of improving the reliability of the smart contract event listener is to support multiple availability zones in the ECS cluster. This ensures redundancy in the event of a failure in one availability zone. For more information, here's a blog on &lt;a href="https://aws.amazon.com/blogs/containers/amazon-ecs-availability-best-practices/" rel="noopener noreferrer"&gt;Amazon ECS availability best practices&lt;/a&gt; and AWS' &lt;a href="https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/shared-responsibility-model-for-resiliency.html" rel="noopener noreferrer"&gt;Shared Responsibility Model for Resiliency&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you've implemented the smart contract event listener cluster to be in multiple availability zones, you'll need your systems to be &lt;a href="https://en.wikipedia.org/wiki/Idempotence" rel="noopener noreferrer"&gt;idempotent&lt;/a&gt;. This means that when you receive the same smart contract event multiple times, it should only be processed once in your system. &lt;/p&gt;

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

&lt;p&gt;To recap, we've gone through the process of implementing and deploying a smart contract event listener with the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configuring the &lt;strong&gt;WebSocket endpoint&lt;/strong&gt; and &lt;strong&gt;smart contract address&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Reviewing and testing the smart contract event listener code.&lt;/li&gt;
&lt;li&gt;Deploying the smart contract event listener to AWS using &lt;strong&gt;AWS CDK&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Verifying the deployed smart contract event listener is working. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've also shared some caveats and improvements to consider as you build on top of the listener:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integrating the smart contract event listener with different AWS services such as &lt;strong&gt;Lambda functions&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Improving reliability by deploying the smart contract event listener to multiple &lt;strong&gt;availability zones (AZ)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Setting up CloudWatch alarms for error monitoring.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Listening to smart contract events enables developers to integrate smart contracts into different APIs and enable real-time updates. AWS CDK allows you to deploy reliable cloud infrastructure with just a few lines of code, giving you more confidence in your deployments, and allowing you to focus on solving real-world problems. &lt;/p&gt;

&lt;p&gt;If you've made it this far, thank you for reading! If you have any questions, feel free to comment or contact me &lt;a href="https://linktr.ee/jdg28" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>node</category>
      <category>smartcontract</category>
      <category>web3</category>
      <category>aws</category>
    </item>
    <item>
      <title>OpenAI DevDay and GitHub Universe 2023: What It Means for Us Software Engineers</title>
      <dc:creator>Jasper Gabriel</dc:creator>
      <pubDate>Sun, 12 Nov 2023 15:13:37 +0000</pubDate>
      <link>https://dev.to/jdg2896/openai-devday-and-github-universe-2023-what-it-means-for-us-software-engineers-297e</link>
      <guid>https://dev.to/jdg2896/openai-devday-and-github-universe-2023-what-it-means-for-us-software-engineers-297e</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Earlier this week, the team and I rented an Airbnb to prepare for our upcoming &lt;a href="https://www.eventbrite.co.uk/e/tenity-singapore-incubation-batch-vi-demoday-tickets-740213898697" rel="noopener noreferrer"&gt;demo day&lt;/a&gt; on November 23rd. We had internal discussions and started preparing our pitch deck. Then while on a break, looking for videos to watch on YouTube, we happened to see a recent video on &lt;a href="https://www.youtube.com/watch?v=U9mJuUkhUzk&amp;amp;ab_channel=OpenAI" rel="noopener noreferrer"&gt;OpenAI's DevDay&lt;/a&gt;. After watching the video, we were amazed, and we started discussing the possibilities enabled by OpenAI's new features. After a few days, &lt;a href="https://www.youtube.com/watch?v=NrQkdDVupQE" rel="noopener noreferrer"&gt;GitHub Universe 2023&lt;/a&gt; started. We binged the keynotes which added to our excitement and slight worries.&lt;/p&gt;

&lt;p&gt;Our feelings of excitement stemmed from discussions on how we can leverage AI to improve developer workflows and stay lean at our startup. Meaning not needing to hire additional engineering resources while we build out our MVPs. There are also new features that make it easier to integrate AI assistants into our future applications, which helps in providing a modern experience. &lt;/p&gt;

&lt;p&gt;Our worries came from the disruptions caused by AI advancements. We can't help but think about our future job security since AI is becoming more capable of doing development tasks. We also thought about how certain startups can become obsolete after OpenAI's announcements. &lt;/p&gt;

&lt;p&gt;If you're a software engineer wondering what these developments mean for you, then you've come to the right place. In this article, I'll recap what we've witnessed from OpenAI and GitHub. Then I'll share some thoughts on its impact on us software engineers. &lt;/p&gt;

&lt;h2&gt;
  
  
  OpenAI DevDay
&lt;/h2&gt;

&lt;p&gt;OpenAI had its first &lt;a href="https://devday.openai.com/" rel="noopener noreferrer"&gt;DevDay&lt;/a&gt;, which generated a lot of buzz throughout the AI and developer communities. Let's go through the key features.&lt;/p&gt;

&lt;h3&gt;
  
  
  GPT-4 Turbo
&lt;/h3&gt;

&lt;p&gt;The first announcement introduced &lt;a href="https://help.openai.com/en/articles/8555510-gpt-4-turbo" rel="noopener noreferrer"&gt;GPT-4 Turbo&lt;/a&gt;, the latest generation model from OpenAI that had the following updates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Four times more &lt;strong&gt;context length&lt;/strong&gt; than the previous GPT-4 model (32k tokens) at &lt;strong&gt;128k tokens&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cheaper pricing&lt;/strong&gt; for input and output tokens.&lt;/li&gt;
&lt;li&gt;More recent knowledge cut-off date of &lt;strong&gt;April 2023&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Support for &lt;strong&gt;function calling&lt;/strong&gt; and &lt;strong&gt;JSON mode&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Support for &lt;strong&gt;code interpreter&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Reproducible outputs with &lt;strong&gt;seed&lt;/strong&gt; parameter.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Context length is important in GPTs because the more details and instructions you can provide, the more accurate the GPTs' responses will be. Combined with cheaper pricing, you can provide more context that is cost-effective. &lt;/p&gt;

&lt;p&gt;Support for function calling and JSON mode allows for easier API integrations when using GPT-4 Turbo and other supported models. &lt;/p&gt;

&lt;p&gt;Then support for code interpreters allows GPTs to generate and run Python code as needed. This allows for use cases that need to parse and process files, calculate data, and a lot more.&lt;/p&gt;

&lt;h3&gt;
  
  
  "GPTs"
&lt;/h3&gt;

&lt;p&gt;The next announcement was about "GPTs", where users can create their own GPT versions for different use cases without having to write code. Sam Altman demoed this functionality by creating a "Startup Mentor" GPT since he usually gets similar questions from early-stage startup founders during &lt;a href="https://www.ycombinator.com/blog/open-office-hours-sign-up-for-office-hours-with-yc-partners" rel="noopener noreferrer"&gt;YC office hours&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzwypbj4yyr0ttpodmp1.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%2Fqzwypbj4yyr0ttpodmp1.png" alt="OpenAI DevDay - Sam Altman's Demo" width="800" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Screenshot from &lt;a href="https://www.youtube.com/watch?v=U9mJuUkhUzk&amp;amp;ab_channel=OpenAI" rel="noopener noreferrer"&gt;OpenAI's DevDay video&lt;/a&gt; on OpenAI's YouTube channel.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A GPT store will also be rolled out later this month allowing users to share their work with the public and possibly earn money depending on their GPTs' usage and popularity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Assistants API
&lt;/h3&gt;

&lt;p&gt;After that, they showed the new Assistants API. With similar capabilities to GPTs, this enables developers to leverage GPTs programmatically for their use cases. &lt;/p&gt;

&lt;p&gt;The demo shown using this feature was on a sample travel website, where users can use an AI assistant to plan their travels. &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%2Fcj26shu1raa5y7vpk7yu.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%2Fcj26shu1raa5y7vpk7yu.png" alt="OpenAI DevDay - Assistants API Demo" width="800" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Screenshot from &lt;a href="https://www.youtube.com/watch?v=U9mJuUkhUzk&amp;amp;ab_channel=OpenAI" rel="noopener noreferrer"&gt;OpenAI's DevDay video&lt;/a&gt; on OpenAI's YouTube channel.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  GitHub Universe 2023
&lt;/h2&gt;

&lt;p&gt;After a few days, GitHub Universe 2023 opened up with some exciting announcements. Let's walk through the key highlights.&lt;/p&gt;

&lt;h3&gt;
  
  
  Copilot Chat
&lt;/h3&gt;

&lt;p&gt;The first announcement made was with &lt;a href="https://docs.github.com/en/copilot/github-copilot-chat/using-github-copilot-chat-in-your-ide" rel="noopener noreferrer"&gt;Copilot Chat&lt;/a&gt;, which is coming in December. &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%2Fvlcz6cnwshxzfszbbqnf.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%2Fvlcz6cnwshxzfszbbqnf.png" alt="GitHub Universe 2023 - Copilot Chat Demo" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Screenshot from &lt;a href="https://www.youtube.com/watch?v=NrQkdDVupQE&amp;amp;ab_channel=GitHub" rel="noopener noreferrer"&gt;GitHub Universe 2023 video&lt;/a&gt; on GitHub's YouTube channel.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This brings different features such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using GPT-4 models&lt;/li&gt;
&lt;li&gt;Code-aware guidance and code generation&lt;/li&gt;
&lt;li&gt;Iterate on code in line&lt;/li&gt;
&lt;li&gt;Shortcuts to generate unit tests, fix suggestions, pull request descriptions, and much more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these features are integrated into popular IDEs such as VS Code, which helps with staying in the development flow. &lt;/p&gt;

&lt;h3&gt;
  
  
  Copilot Enterprise
&lt;/h3&gt;

&lt;p&gt;While Copilot Chat is integrated per repository, Copilot Enterprise is instead integrated with your organization's codebase. &lt;/p&gt;

&lt;p&gt;This helps developers quickly get insights, especially in large organizations with thousands of repositories and billions of lines of code. &lt;/p&gt;

&lt;h3&gt;
  
  
  AI-Powered Security
&lt;/h3&gt;

&lt;p&gt;Then, an announcement on AI-powered security was made. This helps minimize insecure coding practices by detecting and correcting hard-coded credentials and secrets, and vulnerabilities such as SQL injection.&lt;/p&gt;

&lt;h2&gt;
  
  
  What These AI Announcements Mean for Us Software Engineers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Positives
&lt;/h3&gt;

&lt;p&gt;Most of the announced features are aimed at improving developer experiences. Whether you're a front-end, back-end, full-stack, or any other engineering role, these changes can help you be more productive and allow you to focus on building creative solutions to engineering problems.&lt;/p&gt;

&lt;p&gt;Here are some ways these AI tools help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integrate AI assistants in your applications with &lt;strong&gt;OpenAI Assistants API&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Create &lt;strong&gt;GPTs&lt;/strong&gt; for your specific use cases (Code reviewer, Mentor, etc.).&lt;/li&gt;
&lt;li&gt;Implement Test-Driven Development (TDD) with &lt;strong&gt;GitHub Copilot&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Improve developer workflows with &lt;strong&gt;GitHub Copilot Chat&lt;/strong&gt; and &lt;strong&gt;Copilot Enterprise&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Build documentation&lt;/li&gt;
&lt;li&gt;Suggest code based on open files and repositories&lt;/li&gt;
&lt;li&gt;Generate pull request summaries&lt;/li&gt;
&lt;li&gt;Review pull requests&lt;/li&gt;
&lt;li&gt;Fix bugs and issues&lt;/li&gt;
&lt;li&gt;Remediate security vulnerabilities&lt;/li&gt;
&lt;li&gt;Ask Copilot Chat questions about the codebase&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Not So Positives
&lt;/h3&gt;

&lt;p&gt;While these AI tools improve developer workflows and productivity, you can also argue that this might lead to a reduction in engineering resources for some companies. Some startups might even become obsolete if they do not pivot or solidify their &lt;a href="https://www.omniconvert.com/what-is/uvp-unique-value-proposition/" rel="noopener noreferrer"&gt;unique value proposition (UVP)&lt;/a&gt;, which will inevitably cause some job losses. Startups have always been risky, and disruptions are always bound to happen. It's just that advancements in AI accelerated this &lt;a href="https://gongos.com/thinking-post/how-disruptions-are-born-and-how-it-applies-to-the-market-research-discipline/" rel="noopener noreferrer"&gt;disruption cycle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Even with these concerns, I wouldn't worry too much about the job market, especially if you're continuously improving yourself. While there is a &lt;strong&gt;surplus&lt;/strong&gt; of &lt;strong&gt;software engineers&lt;/strong&gt;, there's also a &lt;strong&gt;shortage&lt;/strong&gt; of &lt;strong&gt;talented software engineers&lt;/strong&gt;. If you start learning and leveraging these AI tools in your everyday workflows, you can keep up with the latest trends in tech, and in turn, be a valuable asset for any tech company. &lt;/p&gt;

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

&lt;p&gt;The opening keynotes from &lt;a href="https://www.youtube.com/watch?v=U9mJuUkhUzk&amp;amp;ab_channel=OpenAI" rel="noopener noreferrer"&gt;OpenAI's DevDay&lt;/a&gt; and &lt;a href="https://www.youtube.com/watch?v=NrQkdDVupQE&amp;amp;ab_channel=GitHub" rel="noopener noreferrer"&gt;GitHub Universe 2023&lt;/a&gt; showcased new and improved AI tools that software engineers can use to make their development experiences more enjoyable, from prompting ChatGPT and Copilot Chat to generating documentation and unit tests. As tech keeps on evolving, it's important for us as engineers to also adapt, innovate, and continuously learn to keep up with the trend. &lt;/p&gt;

&lt;p&gt;Our team and I have already availed &lt;a href="https://openai.com/blog/chatgpt-plus" rel="noopener noreferrer"&gt;ChatGPT Plus&lt;/a&gt;, &lt;a href="https://platform.openai.com/docs/overview" rel="noopener noreferrer"&gt;OpenAI Platform APIs&lt;/a&gt;, and &lt;a href="https://github.com/features/copilot" rel="noopener noreferrer"&gt;GitHub Copilot&lt;/a&gt;. I'll be playing around and experimenting with these new features and how they can enhance my developer workflows, and I'll be sure to write about interesting stuff I learn along the way.&lt;/p&gt;

&lt;p&gt;As we part ways, I thank you for reading and I'll leave you with one question, &lt;strong&gt;How will you leverage these new AI tools in your development workflows?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading and Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=U9mJuUkhUzk&amp;amp;ab_channel=OpenAI" rel="noopener noreferrer"&gt;OpenAI DevDay Opening Keynote&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=NrQkdDVupQE&amp;amp;ab_channel=GitHub" rel="noopener noreferrer"&gt;GitHub Universe 2023 Opening Keynote&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devday.openai.com/" rel="noopener noreferrer"&gt;OpenAI DevDay Landing Page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/2023-11-08-universe-2023-copilot-transforms-github-into-the-ai-powered-developer-platform/" rel="noopener noreferrer"&gt;GitHub Universe 2023 Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.latent.space/p/ai-engineer" rel="noopener noreferrer"&gt;The Rise of the AI Engineer - swyx&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>openai</category>
      <category>githubcopilot</category>
      <category>ai</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>How to Reliably Read QR Codes in Node.js</title>
      <dc:creator>Jasper Gabriel</dc:creator>
      <pubDate>Sat, 04 Nov 2023 11:16:02 +0000</pubDate>
      <link>https://dev.to/jdg2896/how-to-reliably-read-qr-codes-in-nodejs-502i</link>
      <guid>https://dev.to/jdg2896/how-to-reliably-read-qr-codes-in-nodejs-502i</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In today's digital landscape, QR codes are widely used. Thanks to the QR code's efficiency in storing and reading data, you can see QR codes being used in restaurants, public transportation, app downloads, survey forms, and a whole lot of other applications. &lt;/p&gt;

&lt;p&gt;Reading QR codes is usually handled by frontend applications via scanners or image uploads, but if you need a way to read QR codes in the backend, then you've come to the right place!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I made this blog post
&lt;/h2&gt;

&lt;p&gt;I was figuring out how to read QR codes in Node.js, so I've tried following existing guides from &lt;a href="https://blog.logrocket.com/create-read-qr-codes-node-js/" rel="noopener noreferrer"&gt;LogRocket&lt;/a&gt; and &lt;a href="https://www.geeksforgeeks.org/reading-qr-codes-using-node-js/" rel="noopener noreferrer"&gt;GeeksforGeeks&lt;/a&gt;. They both had similar solutions using &lt;a href="https://www.npmjs.com/package/qrcode-reader" rel="noopener noreferrer"&gt;qrcode-reader&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Upon testing the solution multiple times, I've encountered &lt;a href="https://github.com/edi9999/jsqrcode/issues/65" rel="noopener noreferrer"&gt;occasional bugs&lt;/a&gt; with &lt;code&gt;qrcode-reader&lt;/code&gt;, which made it unsuitable for production workloads. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;qrcode-reader&lt;/code&gt; package is &lt;a href="https://github.com/edi9999/jsqrcode/issues/32#issuecomment-575042561" rel="noopener noreferrer"&gt;no longer maintained&lt;/a&gt; and the owner recommended &lt;a href="https://www.npmjs.com/package/jsqr" rel="noopener noreferrer"&gt;jsqr&lt;/a&gt; as an alternative, which is what we're going to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  QR Code Reader Solution
&lt;/h2&gt;

&lt;p&gt;Now let's walk through the solution for reading QR codes in Node.js. You can follow along or check the sample repository &lt;a href="https://github.com/jdg2896/qrcode-decoder-nodejs" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing Jimp and jsQR
&lt;/h3&gt;

&lt;p&gt;For the npm packages, we'll be using &lt;a href="https://www.npmjs.com/package/jimp" rel="noopener noreferrer"&gt;jimp&lt;/a&gt; for the image loader and &lt;a href="https://www.npmjs.com/package/jsqr" rel="noopener noreferrer"&gt;jsqr&lt;/a&gt; for the QR code reader.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install jimp jsqr&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  TypeScript Code (src/app.ts)
&lt;/h3&gt;

&lt;p&gt;The sample QR code &lt;code&gt;src/qr.png&lt;/code&gt; is in the &lt;a href="https://github.com/jdg2896/qrcode-decoder-nodejs" rel="noopener noreferrer"&gt;sample repository&lt;/a&gt;. You can also replace &lt;code&gt;src/qr.png&lt;/code&gt; and use any QR code image if you want.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Jimp&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jimp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;jsQR&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jsqr&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;decodeQR&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Load the image with Jimp&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;image&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;Jimp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/qr.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Get the image data&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imageData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8ClampedArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bitmap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bitmap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bitmap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="c1"&gt;// Use jsQR to decode the QR code&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decodedQR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;jsQR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;imageData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;imageData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&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;decodedQR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;QR code not found in the image.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;decodedQR&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error decoding QR code:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Test the decodeQR() function&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;decodeQR&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Optional:&lt;/strong&gt; If you need to read base64 string QR codes, replace the &lt;code&gt;Jimp.read()&lt;/code&gt; function with this.&lt;/p&gt;


&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;base64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data:image/png;base64,iVBORw0KGgo...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// replace with your base64 string&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;qrBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^data:image&lt;/span&gt;&lt;span class="se"&gt;\/[&lt;/span&gt;&lt;span class="sr"&gt;a-z&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+;base64,/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&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;image&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;Jimp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;qrBuffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Testing the Code
&lt;/h3&gt;

&lt;p&gt;To test the solution, you can build and start the function, which will retrieve the data from the &lt;code&gt;src/qr.png&lt;/code&gt; image file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm build &lt;span class="o"&gt;(&lt;/span&gt;or tsc&lt;span class="o"&gt;)&lt;/span&gt;
npm start &lt;span class="o"&gt;(&lt;/span&gt;or node src/app.js&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; qrcode-decoder-nodejs@1.0.0 start
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; node src/app.js

Sample QR code data &lt;span class="k"&gt;for &lt;/span&gt;testing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we decoded the data and received &lt;code&gt;"Sample QR code data for testing."&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;To recap, we implemented a QR code reader in Node.js using &lt;a href="https://www.npmjs.com/package/jimp" rel="noopener noreferrer"&gt;jimp&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/jsqr" rel="noopener noreferrer"&gt;jsqr&lt;/a&gt;. We also tested the &lt;code&gt;decodeQR()&lt;/code&gt; function, which decoded the sample QR image. Also, here's the &lt;a href="https://github.com/jdg2896/qrcode-decoder-nodejs" rel="noopener noreferrer"&gt;sample repository&lt;/a&gt; with the code shown in this guide if you've missed it.&lt;/p&gt;

&lt;p&gt;I hope this helped you with implementing a QR code reader in Node.js. Thank you for reading, and feel free to connect with me on &lt;a href="https://twitter.com/jdg2896" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/jaspergabriel/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>node</category>
      <category>typescript</category>
      <category>qr</category>
    </item>
    <item>
      <title>My First Open Source Contribution: How I Did It</title>
      <dc:creator>Jasper Gabriel</dc:creator>
      <pubDate>Tue, 08 Aug 2023 13:50:16 +0000</pubDate>
      <link>https://dev.to/jdg2896/my-first-open-source-contribution-how-i-did-it-1jh6</link>
      <guid>https://dev.to/jdg2896/my-first-open-source-contribution-how-i-did-it-1jh6</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Contributing to open source can seem intimidating, especially to those who've never done open source before. I know I felt intimidated, thinking that open source is only for talented and senior developers. &lt;/p&gt;

&lt;p&gt;While that may be true for those who've made packages and tooling used by thousands (or even millions) of devs, it's not true if you want to contribute to an existing open source project. I've realized that and I'm here to share how I made my first open source contribution. &lt;/p&gt;

&lt;p&gt;If that sounds interesting, then let's continue!&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding an Open Source Project to Contribute to
&lt;/h2&gt;

&lt;p&gt;There are a lot of open source projects out there, but where do you start? &lt;/p&gt;

&lt;p&gt;I narrowed it down using these three helpful prompts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What specific area of tech am I interested in?&lt;/li&gt;
&lt;li&gt;What are my current skills, or skills I want to improve?&lt;/li&gt;
&lt;li&gt;What's the tech stack of the open source project?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What specific area of tech am I interested in?
&lt;/h3&gt;

&lt;p&gt;Looking for projects that fit your interests would help you get started. Your interests can be anywhere from frontend templates, developer tools, AI, smart contracts, cybersecurity, etc.&lt;/p&gt;

&lt;p&gt;I'm passionate in &lt;a href="https://ethereum.org/en/web3/" rel="noopener noreferrer"&gt;Web3&lt;/a&gt;, so I tried to find Web3 projects that are open source. Web3 also encourages open source so it wasn't hard looking for one. &lt;/p&gt;

&lt;h3&gt;
  
  
  What are my current skills, or skills I want to improve?
&lt;/h3&gt;

&lt;p&gt;As for skills, what are you currently good at? or want to gain more experience at?&lt;/p&gt;

&lt;p&gt;For me, I'm a backend developer that specializes in &lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; and &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt;. I've integrated Web3 libraries to Node.js apps, and I've also written technical documentations for previous projects.&lt;/p&gt;

&lt;p&gt;With that, I'd look for Node.js and TypeScript projects, where I'm already good at. I won't look for a &lt;a href="https://go.dev/" rel="noopener noreferrer"&gt;Go&lt;/a&gt; or &lt;a href="https://www.rust-lang.org/" rel="noopener noreferrer"&gt;Rust&lt;/a&gt; project where I don't have the necessary skills to contribute. &lt;/p&gt;

&lt;h3&gt;
  
  
  What's the tech stack of the open source project?
&lt;/h3&gt;

&lt;p&gt;Combining my interests and skills, I've looked at a few open source projects and their tech stacks. &lt;/p&gt;

&lt;p&gt;Ethereum scaling solutions and &lt;strong&gt;zero knowledge (ZK)&lt;/strong&gt; are two areas I'm interested in Web3. I've read &lt;a href="https://en.wikipedia.org/wiki/Vitalik_Buterin" rel="noopener noreferrer"&gt;Vitalik's&lt;/a&gt; article on &lt;a href="https://vitalik.ca/general/2022/08/04/zkevm.html" rel="noopener noreferrer"&gt;the different types of ZK-EVMs&lt;/a&gt;. I saw &lt;a href="https://taiko.xyz/" rel="noopener noreferrer"&gt;Taiko&lt;/a&gt; as one of the current Type 1 ZK-EVMs in development.&lt;/p&gt;

&lt;p&gt;Reviewing Taiko's &lt;a href="https://github.com/taikoxyz/taiko-mono" rel="noopener noreferrer"&gt;monorepo&lt;/a&gt; tech stack, I saw that they use TypeScript. Their documentations use &lt;a href="https://mdxjs.com/" rel="noopener noreferrer"&gt;MDX&lt;/a&gt;, which is an improved version of &lt;a href="https://www.markdownguide.org/" rel="noopener noreferrer"&gt;markdown&lt;/a&gt;. I've used markdown before so contributing to their docs in MDX is doable.&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%2F0kj7gzcwep2cr3cl9tsr.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%2F0kj7gzcwep2cr3cl9tsr.png" alt="Tech stack" width="327" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With that, I started preparing to make my first open source contribution with Taiko. &lt;/p&gt;

&lt;h2&gt;
  
  
  Contributing to Taiko
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Reviewing contributing guidelines
&lt;/h3&gt;

&lt;p&gt;Before anything else, I first looked at Taiko's &lt;a href="https://github.com/taikoxyz/taiko-mono/blob/main/CONTRIBUTING.md" rel="noopener noreferrer"&gt;CONTRIBUTING.md&lt;/a&gt; file to orient myself on their contributing guidelines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; how to contribute&lt;/li&gt;
&lt;li&gt; coding standards&lt;/li&gt;
&lt;li&gt; documentation standards&lt;/li&gt;
&lt;li&gt; helpful tips&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ucthdolatp43er0izui.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%2F9ucthdolatp43er0izui.png" alt="Contributing manual" width="800" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then I saw two ways to contribute in the &lt;strong&gt;Make a contribution&lt;/strong&gt; section:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Opening a new issue&lt;/li&gt;
&lt;li&gt; Working on an existing issue &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've chosen to work on an existing issue.&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%2Foa989hbbf6tyy8kkof8l.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%2Foa989hbbf6tyy8kkof8l.png" alt="Make a contribution" width="800" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For coding standards, I looked at the standards and conventions used in the project. I saw that they are using &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/" rel="noopener noreferrer"&gt;conventional commits&lt;/a&gt; for pull request titles and commits. &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%2F3p0neitt3we82fqv6490.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%2F3p0neitt3we82fqv6490.png" alt="Coding standards" width="800" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then for branch naming, I saw that there was no particular convention, so a short branch name describing what it is for should be enough.&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%2Fpb0n66i261ri2ooflwqp.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%2Fpb0n66i261ri2ooflwqp.png" alt="Branches" width="800" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Finding an existing issue to work on
&lt;/h3&gt;

&lt;p&gt;I've tried to look at some &lt;strong&gt;good first issues&lt;/strong&gt;, since these are usually not difficult issues, and are meant to help onboard first time contributors. &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%2Fhbsyb8gignrzlwp69836.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%2Fhbsyb8gignrzlwp69836.png" alt="Good first issues" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I ended up choosing the issue to &lt;strong&gt;improve their "Node running guide for setting RPC endpoints"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Then I reviewed the issue, and looked at the description and comments. I also reviewed the &lt;a href="https://taiko.xyz/docs" rel="noopener noreferrer"&gt;website&lt;/a&gt; where the docs are located. &lt;/p&gt;

&lt;p&gt;I made sure I understood what was needed. &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%2Fqsr2m2xpwru7g98r5v3y.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%2Fqsr2m2xpwru7g98r5v3y.png" alt="Issue" width="800" height="480"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Forking, cloning, and working on the changes
&lt;/h3&gt;

&lt;p&gt;After reviewing the issue, I forked and cloned Taiko's &lt;a href="https://github.com/taikoxyz/taiko-mono/tree/main" rel="noopener noreferrer"&gt;monorepo&lt;/a&gt;. Then I started working on a proof of concept.&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%2F936j2h4ftm07pu02o74z.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%2F936j2h4ftm07pu02o74z.png" alt="Fork" width="472" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Locating the code that needs improvement was pretty straight-forward, since the project is structured as a monorepo. The &lt;strong&gt;website&lt;/strong&gt; package contains Taiko's guides, so I worked on that.&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%2Frks18f1v6yu7qs7sm0as.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%2Frks18f1v6yu7qs7sm0as.png" alt="Monorepo packages" width="562" height="838"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After I was able to run my local setup and test the changes, I made some comments on the &lt;a href="https://github.com/taikoxyz/taiko-mono/issues/13986" rel="noopener noreferrer"&gt;issue&lt;/a&gt; and asked for a review to verify if the changes would solve the issue.&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%2Fqf26mzj59fkwacecty21.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%2Fqf26mzj59fkwacecty21.png" alt="Issue comment 1" width="800" height="545"&gt;&lt;/a&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%2Feif6c7w3nio9e7bn9pfy.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%2Feif6c7w3nio9e7bn9pfy.png" alt="Issue comment 2" width="800" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After getting approval from Dave (d1onys1us), I proceeded to open a &lt;a href="https://github.com/taikoxyz/taiko-mono/pull/14029" rel="noopener noreferrer"&gt;pull request&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcmzofi6xd9w8qh9ehmmp.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%2Fcmzofi6xd9w8qh9ehmmp.png" alt="Issue comment 3" width="800" height="242"&gt;&lt;/a&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%2Feicguqb8xrqjvrlwg3w0.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%2Feicguqb8xrqjvrlwg3w0.png" alt="PR" width="800" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Going through the pull request review process
&lt;/h3&gt;

&lt;p&gt;The review process was interesting. While waiting for reviews, I've noticed that there were changes on the main branch that was merged to my feature branch. &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%2Feu14su0spl8xczv62zqa.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%2Feu14su0spl8xczv62zqa.png" alt="Merged main" width="800" height="54"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then I reviewed the changes, and it affected my changes, which didn't make sense when combined with the changes from the main branch. So I decided to take the initiative to improve the section and propose the changes on my ongoing pull request review. &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%2Fs3cmwuv067wkmj2sludq.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%2Fs3cmwuv067wkmj2sludq.png" alt="PR comment" width="800" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The team liked the change, so I proceeded to commit the changes. &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%2Fcfucosqpqryof2kuyxl8.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%2Fcfucosqpqryof2kuyxl8.png" alt="Reviewer comment 1" width="800" height="93"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then another reviewer commented that I had API keys exposed on the guide images, so I quickly fixed these to resolve the review comment.&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%2F7m1y8p4zepp8k4c1zx3b.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%2F7m1y8p4zepp8k4c1zx3b.png" alt="Reviewer comment 2" width="800" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After all of that, my pull request was finally approved and merged!&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%2Fsulv6xzgiupcane2h302.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%2Fsulv6xzgiupcane2h302.png" alt="PR approved 1" width="800" height="101"&gt;&lt;/a&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%2Fmtb8ns7favyzw9urypy3.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%2Fmtb8ns7favyzw9urypy3.png" alt="PR approved 2 and merged" width="800" height="173"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, I can say that I've contributed to open source! Got a cool &lt;a href="https://www.gitpoap.io/" rel="noopener noreferrer"&gt;GitPOAP&lt;/a&gt; to prove it too! 🙂&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%2Fuzznv5ozs03s5g6bjbjs.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%2Fuzznv5ozs03s5g6bjbjs.png" alt="Git POAP" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Takeaways (Conclusion)
&lt;/h2&gt;

&lt;p&gt;Making my first open source contribution helped me realize what open source meant. The value of open source is in its contributors and their contributions, no matter how big or how small. &lt;/p&gt;

&lt;p&gt;Being an open source contributor can also be compared to a boy or girl scout, where the scouts leave the campsite cleaner than when they've found it. When a contributor encounters a bug in a feature or a typo in the documentation of an open source project, they can create an issue along with the fix, leaving the code cleaner than when they've first encountered it.&lt;/p&gt;

&lt;p&gt;I also want to thank the team at &lt;a href="https://taiko.xyz/" rel="noopener noreferrer"&gt;Taiko&lt;/a&gt; for being welcoming, supportive, and making my first open source contribution a fun experience. Do check out the project if you're interested! &lt;/p&gt;

&lt;p&gt;If you've missed it, here's the &lt;a href="https://github.com/taikoxyz/taiko-mono/issues/13986" rel="noopener noreferrer"&gt;issue&lt;/a&gt; that I've worked on at Taiko and the &lt;a href="https://github.com/taikoxyz/taiko-mono/pull/14029" rel="noopener noreferrer"&gt;pull request&lt;/a&gt; that solves the issue.&lt;/p&gt;

&lt;p&gt;And here's a summary of what I did:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Found an open source project:

&lt;ul&gt;
&lt;li&gt;What specific area of tech am I interested in?&lt;/li&gt;
&lt;li&gt;What are my current skills, or skills I want to improve?&lt;/li&gt;
&lt;li&gt;What's the tech stack of the open source project?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Reviewed contributing guidelines (CONTRIBUTING.md)&lt;/li&gt;
&lt;li&gt;Looked at good first issues&lt;/li&gt;
&lt;li&gt;Chose an existing issue, then reviewed the description and comments (if any)&lt;/li&gt;
&lt;li&gt;Forked and cloned the repo&lt;/li&gt;
&lt;li&gt;Set up my local environment&lt;/li&gt;
&lt;li&gt;Worked on and tested the changes&lt;/li&gt;
&lt;li&gt;Opened a pull request&lt;/li&gt;
&lt;li&gt;Went through the review process and resolved comments (if any)&lt;/li&gt;
&lt;li&gt;Pull request got merged!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I won't stop there. I'm excited on the journey ahead and looking forward to be a more consistent open source contributor. One contribution at a time. &lt;/p&gt;

&lt;p&gt;Thank you for reading and as always, I'm open to suggestions, feedback, and comments. Also feel free to contact me at my email (&lt;a href="mailto:jasper.d.gabriel@gmail.com"&gt;jasper.d.gabriel@gmail.com&lt;/a&gt;), and I'm available on &lt;a href="https://twitter.com/jdg2896" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/jaspergabriel/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, and &lt;a href="https://github.com/jdg2896" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>web3</category>
      <category>learning</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
