<?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: Lucas Andrade</title>
    <description>The latest articles on DEV Community by Lucas Andrade (@olucasandrade).</description>
    <link>https://dev.to/olucasandrade</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%2F484618%2Fb553305a-e6fd-48ed-a3e6-b94af5b5bd1b.png</url>
      <title>DEV Community: Lucas Andrade</title>
      <link>https://dev.to/olucasandrade</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/olucasandrade"/>
    <language>en</language>
    <item>
      <title>You just need Postgres</title>
      <dc:creator>Lucas Andrade</dc:creator>
      <pubDate>Thu, 26 Feb 2026 17:14:54 +0000</pubDate>
      <link>https://dev.to/olucasandrade/you-just-need-postgres-2jf5</link>
      <guid>https://dev.to/olucasandrade/you-just-need-postgres-2jf5</guid>
      <description>&lt;p&gt;You've heard the advice: "Use the right tool for the right job." Sounds reasonable. Even wise. So you followed it. You picked Redis for caching, Elasticsearch for search, Kafka for messaging, MongoDB for documents, Pinecone for vectors, InfluxDB for time-series, and Postgres for... well, the relational stuff.&lt;br&gt;&lt;br&gt;
                                                                                                                                                                                   Congratulations. You now have 7 databases to maintain, 7 backup strategies to manage, 7 monitoring dashboards to watch, 7 security audits to run, and 7 monsters that can break at 3 AM.&lt;/p&gt;

&lt;p&gt;The thing nobody talks about, cause it doesn't sell: that advice "the right tool for the right job" is the battle cry of every vendor's marketing department.&lt;/p&gt;

&lt;p&gt;The uncomfortable truth is that PostgreSQL is not "just a relational database." It hasn't been for over a decade. It's a data platform that does what most of these specialized tools do, using the same algorithms, with a single connection string, a single backup strategy, and a single place to debug when everything breaks at 3 AM.&lt;/p&gt;

&lt;p&gt;Not "close enough." Not "good enough at small scale." The same algorithms.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Redis&lt;/li&gt;
&lt;li&gt;Elasticsearch&lt;/li&gt;
&lt;li&gt;Pinecone&lt;/li&gt;
&lt;li&gt;Kafka&lt;/li&gt;
&lt;li&gt;MongoDB&lt;/li&gt;
&lt;li&gt;InfluxDB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these buzzwords, unless we're talking about truly unbelievable scale, are achievable with just Postgres.&lt;/p&gt;

&lt;p&gt;Let me show you. Actually, no... simulate it and see for yourself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youjustneedpostgres.com" rel="noopener noreferrer"&gt;https://youjustneedpostgres.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>database</category>
      <category>microservices</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Cleaning Github repositories, PRs and issues in bulk like a Pro</title>
      <dc:creator>Lucas Andrade</dc:creator>
      <pubDate>Wed, 28 Jan 2026 13:04:43 +0000</pubDate>
      <link>https://dev.to/olucasandrade/cleaning-github-repositories-prs-and-issues-in-bulk-like-a-pro-479e</link>
      <guid>https://dev.to/olucasandrade/cleaning-github-repositories-prs-and-issues-in-bulk-like-a-pro-479e</guid>
      <description>&lt;p&gt;Hey folks!&lt;/p&gt;

&lt;p&gt;If you maintain multiple repositories or work with organizations on GitHub, you probably know the pain: closing stale PRs, deleting merged branches, managing Dependabot alerts, archiving old repos... It's tedious, repetitive, and takes time away from actual coding. And it's not possible to do that in bulk, I don't know why, and it bothers me.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;GitHub AutoMaintainer&lt;/strong&gt;, a CLI tool in Go that automates all of this.&lt;/p&gt;




&lt;h3&gt;
  
  
  What it does
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Close stale PRs automatically
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;automaintainer close-prs &lt;span class="nt"&gt;--org&lt;/span&gt; my-org &lt;span class="nt"&gt;--days&lt;/span&gt; 30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Closes PRs older than X days&lt;/li&gt;
&lt;li&gt;Adds a comment explaining why&lt;/li&gt;
&lt;li&gt;Supports &lt;code&gt;--dry-run&lt;/code&gt; to preview changes&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Delete merged branches
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;automaintainer delete-branches &lt;span class="nt"&gt;--org&lt;/span&gt; my-org &lt;span class="nt"&gt;--exclude&lt;/span&gt; main,develop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Cleans up branches already merged into default&lt;/li&gt;
&lt;li&gt;Exclude specific branches from deletion&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Close inactive issues
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;automaintainer close-issues &lt;span class="nt"&gt;--org&lt;/span&gt; my-org &lt;span class="nt"&gt;--days&lt;/span&gt; 90
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Grace period with "stale" label before closing&lt;/li&gt;
&lt;li&gt;Option to lock issues after closing&lt;/li&gt;
&lt;li&gt;Filter by labels&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Manage repositories in bulk
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;automaintainer repos list &lt;span class="nt"&gt;--org&lt;/span&gt; my-org &lt;span class="nt"&gt;--inactive&lt;/span&gt; 365
automaintainer repos archive &lt;span class="nt"&gt;--org&lt;/span&gt; my-org &lt;span class="nt"&gt;-i&lt;/span&gt;
automaintainer repos delete &lt;span class="nt"&gt;--org&lt;/span&gt; my-org &lt;span class="nt"&gt;-i&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;List repos with filters (inactive, archived)&lt;/li&gt;
&lt;li&gt;Archive or delete in bulk&lt;/li&gt;
&lt;li&gt;Interactive mode (&lt;code&gt;-i&lt;/code&gt;) for visual selection&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Handle Dependabot alerts
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;automaintainer security list &lt;span class="nt"&gt;--org&lt;/span&gt; my-org &lt;span class="nt"&gt;--severity&lt;/span&gt; high
automaintainer security dismiss &lt;span class="nt"&gt;--org&lt;/span&gt; my-org &lt;span class="nt"&gt;--severity&lt;/span&gt; low &lt;span class="nt"&gt;--days&lt;/span&gt; 180
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;List alerts by severity and state&lt;/li&gt;
&lt;li&gt;Dismiss old low-priority alerts&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Nice terminal UI
&lt;/h3&gt;

&lt;p&gt;I used the &lt;a href="https://charm.sh/" rel="noopener noreferrer"&gt;Charmbracelet&lt;/a&gt; libraries to make the output actually pleasant:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Styled tables&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────────────────────────┬───────────────┬────────────┐
│ REPOSITORY             │ LAST ACTIVITY │ STATUS     │
├────────────────────────┼───────────────┼────────────┤
│ my-org/api             │ 2024-01-15    │ ● active   │
│ my-org/legacy          │ 2022-03-10    │ ○ archived │
└────────────────────────┴───────────────┴────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Progress bars&lt;/strong&gt; for long-running operations&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Scanning repos [████████████████░░░░] 42/100 my-org/current-repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Preview mode&lt;/strong&gt; - select before executing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;automaintainer close-prs &lt;span class="nt"&gt;--org&lt;/span&gt; my-org &lt;span class="nt"&gt;--preview&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Opens an interactive TUI where you navigate with arrows, toggle with space, and confirm only what you want.&lt;/p&gt;




&lt;h3&gt;
  
  
  Other features
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;GitHub URLs as arguments&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Both work&lt;/span&gt;
automaintainer close-prs &lt;span class="nt"&gt;--org&lt;/span&gt; my-org
automaintainer close-prs https://github.com/my-org
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Dry run mode&lt;/strong&gt; - preview everything before making changes&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Colored output&lt;/strong&gt; - green for active, gray for archived, red for critical alerts&lt;/p&gt;




&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;olucasandrade/automaintainer/automaintainer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or download the binary from &lt;a href="https://github.com/olucasandrade/homebrew-automaintainer/releases" rel="noopener noreferrer"&gt;releases&lt;/a&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why Go?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Single binary, no dependencies&lt;/li&gt;
&lt;li&gt;Cross-platform (Linux, macOS, Windows)&lt;/li&gt;
&lt;li&gt;Great performance for bulk operations&lt;/li&gt;
&lt;li&gt;Excellent CLI ecosystem (Cobra, Bubble Tea)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  What's next
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Full interactive dashboard&lt;/li&gt;
&lt;li&gt;Label sync between repos&lt;/li&gt;
&lt;li&gt;Exportable reports&lt;/li&gt;
&lt;li&gt;GitHub Enterprise support&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;The code is fully open source: &lt;a href="https://github.com/olucasandrade/homebrew-automaintainer" rel="noopener noreferrer"&gt;github.com/olucasandrade/homebrew-automaintainer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you maintain repos, work with open source, or just want to automate boring GitHub tasks, give it a try and let me know what you think.&lt;/p&gt;

&lt;p&gt;Issues, PRs, and suggestions are always welcome. The goal is simple: &lt;strong&gt;make life easier for those who already make life easier for others through code.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>automation</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I've created a leetcode-like platform for system design</title>
      <dc:creator>Lucas Andrade</dc:creator>
      <pubDate>Wed, 05 Nov 2025 13:12:22 +0000</pubDate>
      <link>https://dev.to/olucasandrade/ive-created-a-leetcode-like-platform-for-system-design-5dhc</link>
      <guid>https://dev.to/olucasandrade/ive-created-a-leetcode-like-platform-for-system-design-5dhc</guid>
      <description>&lt;p&gt;For the past few weeks, I've been working on one of the coolest things I've ever pushed to production: a LeetCode-style platform for system design.&lt;/p&gt;

&lt;p&gt;I've been writing about system design for a while now, and I genuinely love the topic (I talk about it weekly on my blog). I always wanted a tool to practice it without having to hunt down a billion references across the internet.&lt;/p&gt;

&lt;p&gt;Every tool I found was either paywalled for the basics or completely abandoned. So, I built my own, and I have no intention of letting it go.&lt;/p&gt;

&lt;p&gt;I believe this project has the potential to build a really great community. That's why I decided to "open-source" the entire platform. It's 100% open on GitHub, and I'm already creating issues for the next planned evolutions.&lt;/p&gt;

&lt;p&gt;How this can help you:&lt;br&gt;
The idea is simple: just like LeetCode, you can submit your solution (with a diagram + textual explanation), and you can view and interact with solutions from others. No favoritism here—I truly believe there's no better way to prepare for an interview or just sharpen your skills.&lt;/p&gt;

&lt;p&gt;I don't plan to fully "productize" this until I hit my first major goal, so feel free to play around as much as you want, and please let me know if you find any bugs.&lt;/p&gt;

&lt;p&gt;How you can help me:&lt;br&gt;
First and foremost, dropping a star on the repository is a huge boost. That alone is massive support.&lt;/p&gt;

&lt;p&gt;But if you want to help on a deeper level, feel free to open issues or even pull requests to add new features or work on existing ones. Honestly, the potential of this platform is not something I have enough bandwidth to explore alone.&lt;/p&gt;

&lt;p&gt;Finally, spreading the word is also a big help. I want this to reach as many people as possible who need it.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

&lt;p&gt;The link to the app is: &lt;a href="https://systemstudio.app" rel="noopener noreferrer"&gt;https://systemstudio.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If it gets some traction, I'll share the next steps for the roadmap.&lt;/p&gt;

&lt;h1&gt;
  
  
  lesgo
&lt;/h1&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>systemdesign</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>I've created an automated Github Maintainer</title>
      <dc:creator>Lucas Andrade</dc:creator>
      <pubDate>Mon, 13 Oct 2025 12:41:53 +0000</pubDate>
      <link>https://dev.to/olucasandrade/ive-created-a-automated-github-maintainer-2ef9</link>
      <guid>https://dev.to/olucasandrade/ive-created-a-automated-github-maintainer-2ef9</guid>
      <description>&lt;p&gt;Over the last few days, I found myself doing something boring.&lt;/p&gt;

&lt;p&gt;I was going through a few repositories at Criaway (my company), closing old PRs, deleting merged branches, and reviewing things that could have easily been automated.&lt;/p&gt;

&lt;p&gt;That’s when the thought that always drives me came up again:&lt;/p&gt;

&lt;p&gt;“If it can be automated, I’ll automate it.”&lt;/p&gt;

&lt;p&gt;And that’s how GitHub AutoMaintainer was born — a CLI tool written in Go to automate repetitive GitHub maintenance tasks, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Closing old pull requests automatically&lt;/li&gt;
&lt;li&gt;Deleting merged branches&lt;/li&gt;
&lt;li&gt;Running everything with --dry-run, colored logs, and structured terminal reports&lt;/li&gt;
&lt;li&gt;Operating globally for an organization or targeting a specific repository&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No YAML. No complex setup.&lt;br&gt;
Just install it with Homebrew and start using:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;brew install olucasandrade/automaintainer/automaintainer&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This project came from a real need I had, but the goal is for it to grow with the community.&lt;/p&gt;

&lt;p&gt;If you maintain GitHub repositories, contribute to open source, or simply care about productivity, take a look and let me know what you think.&lt;/p&gt;

&lt;p&gt;Check out the repository &lt;a href="https://github.com/olucasandrade/homebrew-automaintainer" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What’s next?&lt;/p&gt;

&lt;p&gt;I’m planning for the upcoming versions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Label synchronization across repositories&lt;/li&gt;
&lt;li&gt;Automatic removal of inactive collaborators&lt;/li&gt;
&lt;li&gt;Safe detection and deletion of unused repositories (still exploring the best approach)&lt;/li&gt;
&lt;li&gt;Improved Homebrew integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every suggestion, pull request, or piece of feedback is welcome.&lt;br&gt;
The goal is simple: make life easier for those who already make life easier through code.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>automation</category>
      <category>go</category>
      <category>opensource</category>
    </item>
    <item>
      <title>[PITCH] I built an online API Client (an alternative to Insomnia)</title>
      <dc:creator>Lucas Andrade</dc:creator>
      <pubDate>Thu, 20 Feb 2025 15:04:15 +0000</pubDate>
      <link>https://dev.to/olucasandrade/pitch-i-built-an-online-api-client-an-alternative-to-insomnia-133k</link>
      <guid>https://dev.to/olucasandrade/pitch-i-built-an-online-api-client-an-alternative-to-insomnia-133k</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flyleu75k21yk8awewchg.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%2Flyleu75k21yk8awewchg.png" alt=" " width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For those who don’t know me: I’m kind of a madman, been developing software for 4+ years, and I often create random projects based on some brief pain I experience. The latest one is Trevo.rest, an online API Client I built because I was tired of opening a full-blown app on a slow PC just to send a simple request.&lt;/p&gt;

&lt;p&gt;The other day, I had an issue with bomdemorar.com while I was out. If I could’ve tested the API from my phone—my god, life would’ve been so much easier.&lt;/p&gt;

&lt;p&gt;So I thought: why not build a lightweight, straightforward API Client that runs entirely in the browser?&lt;/p&gt;

&lt;p&gt;And just like that, Trevo was born. Open the site, and boom—you can send requests, test your APIs, and move on with your day. No downloads, no hassle.&lt;/p&gt;

&lt;p&gt;Besides the basics, I’m already working on some cool upgrades:&lt;/p&gt;

&lt;p&gt;✅ Request history to make life easier&lt;br&gt;
✅ Better UX for saving and organizing requests&lt;br&gt;
✅ WebSocket support (because real-time testing should be simpler)&lt;br&gt;
✅ Collection export/import&lt;/p&gt;

&lt;p&gt;I built this to solve my own problem, but if others find it useful, even better! No login required, fully online, and with request history. You can try it out right now at &lt;a href="http://www.trevo.rest" rel="noopener noreferrer"&gt;www.trevo.rest&lt;/a&gt; 🚀&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
      <category>api</category>
    </item>
    <item>
      <title>Streamlining Development Workflow: Automating Tasks with GitHub Actions</title>
      <dc:creator>Lucas Andrade</dc:creator>
      <pubDate>Tue, 25 Jun 2024 13:04:24 +0000</pubDate>
      <link>https://dev.to/olucasandrade/streamlining-development-workflow-automating-tasks-with-github-actions-58dg</link>
      <guid>https://dev.to/olucasandrade/streamlining-development-workflow-automating-tasks-with-github-actions-58dg</guid>
      <description>&lt;p&gt;&lt;a href="" class="article-body-image-wrapper"&gt;&lt;img alt="Github Actions Icon"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;During the entire development process, from code to deployment, we encounter many repeated processes: updating snapshots, running unit tests, deploying to staging, completing production deployments... all these types of processes will inevitably become part of every task developed, without exception.&lt;/p&gt;

&lt;p&gt;And like everything in life, it doesn't make sense to do something repetitive when you can automate it. Moreover, it doesn't make sense to work on improving other people's experiences without making our own lives easier, saving our time.&lt;/p&gt;

&lt;p&gt;There are MANY tools that help automate your development process (a practice known as &lt;a href="https://www.redhat.com/pt-br/topics/devops/what-is-ci-cd" rel="noopener noreferrer"&gt;CI/CD&lt;/a&gt;), and one of them is directly tied to the main platform for those who work with software: GitHub.&lt;/p&gt;

&lt;p&gt;Therefore, in this article, we will learn a bit more about GitHub Actions, so we can create, customize, and share automated workflows directly in the repository.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is GitHub Actions?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;GitHub Actions is a CI/CD service provided by GitHub. It allows you to automate various tasks in software development, such as testing, building, deployment, and much more. GitHub Actions is event-based, where each action is triggered by specific events, such as code pushes, pull request creations, or predefined schedules.&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%2F0omzcf88zcgs78k1xy3q.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%2F0omzcf88zcgs78k1xy3q.png" alt="CI/CD interface" width="800" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example above, we have an Express project with a MongoDB database. Here, as soon as we open a pull request, the pipeline defined with the help of GitHub Actions will run all the tests created in the API, in different versions of Node and the MongoDB driver (first and second number in parentheses, respectively).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workflows&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Workflows are the main units of automation in GitHub Actions. They are defined through YAML files that can be configured to respond to specific events or execute schedules. The file specifies the actions to be executed, in which environment, and in what order. These workflows can be easily configured and customized to meet the specific needs of a project.&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%2F9xanmhbnbi191e694oek.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%2F9xanmhbnbi191e694oek.png" alt="Workflow example" width="800" height="613"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Actions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Actions are the reusable components that make up a workflow. They are the fundamental building blocks of GitHub Actions. Actions can be created by the community or the development team and shared with other users. There are pre-made actions available on the GitHub Marketplace, as well as other custom actions that can be developed internally. Actions can be combined to create complex and customized workflows.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Creating Our Workflow&lt;br&gt;
*&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In a project, let's start by going to the "Actions" tab and clicking on "set up a workflow yourself";&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%2Fi2oti0itwz22yt6elvtm.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%2Fi2oti0itwz22yt6elvtm.png" alt="Github Actions Interface" width="800" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now, we can define the details of the YAML file on the next screen, that is, the definition of our workflow. On the right, we can see that GitHub Actions has a marketplace with several well-known and pre-made workflows (consider using this option to find a useful one and enhance it);&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%2Fo125pe46vh0f8w9i4mj6.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%2Fo125pe46vh0f8w9i4mj6.png" alt="Github Actions Interface" width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can define the events that will trigger the workflow. For example, to trigger the workflow whenever a push occurs on the main branch, we can do something like this:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;on:
  push:
    branches:
      - main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then, we add the steps that will be executed in the workflow. For example, let's add a step to install the project's dependencies and another to run the tests. In this case, we would do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v2

    - name: Install dependencies
      run: npm install

    - name: Run tests
      run: npm test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;jobs&lt;/code&gt; defines the tasks to be executed in the workflow. You can have multiple jobs within a workflow, allowing different actions to be executed simultaneously;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;build&lt;/code&gt; is the name given to the job. You can give a descriptive name to each job in your workflow, such as "build", "test", "deploy", among others;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;runs-on&lt;/code&gt; specifies the environment in which the job will be executed. In this example, we are using "ubuntu-latest", which is an Ubuntu operating system image in the most recent environment available on GitHub Actions. There are other options available, such as Windows and macOS;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;steps&lt;/code&gt; defines the individual steps that will be executed within the job;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt; is the name given to each step. It serves to identify the step in the workflow execution log, making it easier to understand what happens at each step;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;uses&lt;/code&gt; specifies a marketplace action that will be used in the step. In the given example, we are using the actions/checkout@v2 action, which allows checking out the repository's source code;
run executes commands or scripts in the step. In the given example, we are using the npm install command to install the project's dependencies and npm test to run the tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;The definition of the YAML file can also be done directly in your development environment; I just exemplified it with the more user-friendly approach.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Actions usage examples&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The test example is the most basic, but there are countless ways to leverage the power of GitHub Actions to automate tasks in a development workflow. Some common examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Continuous deployment to a production environment after a pull request approval;&lt;/li&gt;
&lt;li&gt;Automatic generation of documentation from the source code;&lt;/li&gt;
&lt;li&gt;Notifying the team about changes or issues in the repository;&lt;/li&gt;
&lt;li&gt;Performing routine tasks such as database cleaning or backup creation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Github Actions Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Seamless integration with GitHub: As a native GitHub feature, GitHub Actions integrates perfectly with the existing workflow and allows direct automation in the repository;&lt;/li&gt;
&lt;li&gt;Flexible configuration: Workflows can be easily configured and customized to fit the specific requirements of the project;&lt;/li&gt;
&lt;li&gt;Wide variety of actions: The GitHub Marketplace has a wide range of pre-made actions that can be used, covering various technologies and use cases;&lt;/li&gt;
&lt;li&gt;Efficient collaboration: Automated workflows facilitate collaboration among team members.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simple, right? Did you like the tip? Leave your suggestion or comment and see you next time!&lt;/p&gt;

</description>
      <category>github</category>
      <category>cicd</category>
      <category>git</category>
      <category>automation</category>
    </item>
    <item>
      <title>Boosting your code with Python Decorators</title>
      <dc:creator>Lucas Andrade</dc:creator>
      <pubDate>Thu, 22 Feb 2024 12:16:30 +0000</pubDate>
      <link>https://dev.to/olucasandrade/boosting-your-code-with-python-decorators-4jno</link>
      <guid>https://dev.to/olucasandrade/boosting-your-code-with-python-decorators-4jno</guid>
      <description>&lt;p&gt;There are various programming concepts that spread across different languages. One of them is the decorator, which exists in Python. In this article, we'll understand why to use it, how it works, and the different applications of decorators with Python.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What is a decorator?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A decorator is a feature that allows modifying or enhancing the behavior of functions, methods, or classes.&lt;/p&gt;

&lt;p&gt;They are functions that wrap around other functions to extend or modify them, adding behaviors without modifying the original code of the function.&lt;/p&gt;

&lt;p&gt;So imagine there are different functions going through the same step, but not necessarily a step that is part of the logic of the function itself. It's in this context that we'll use decorators.&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%2Faq9080pj2u8b2vwzvidp.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%2Faq9080pj2u8b2vwzvidp.png" alt="Analogy of decorator" width="800" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Still confused? Be relax, I'll start with some basic examples! But first, let's understand how the syntax of a decorator works.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How to declare a decorator?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A decorator in Python is created using the following syntax: you define a function that will act as the decorator and also receives a function as an argument. Inside it, we'll return another function that, in addition to executing the original function, will concentrate all the "extended" behavior. The syntax looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;innerFunction&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# additional behavior
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello world&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;innerFunction&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;How to call a decorator?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The syntax for calling a decorator is also simple. Basically, we use the symbol '@' followed by the name of the decorator function. This is placed above the function, method, or class you want to modify.&lt;/p&gt;

&lt;p&gt;When the "decorated" function is called, it is replaced by the modified version returned by the decorator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@decorator&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 4
&lt;/span&gt;                 &lt;span class="c1"&gt;# Hello world
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Importance of functools.wraps in decorators&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In my examples below, I'll use the &lt;code&gt;@wraps&lt;/code&gt; decorator from functools to declare the decorators. Decorators are usually declared like this to preserve the metadata of the original function. When you define a decorator without wraps, you may lose important information about the original function. This can affect, for example, the documentation of the function and access to specific attributes of it.&lt;/p&gt;

&lt;p&gt;Let's use an example of a decorator without functools.wraps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator_without_wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inner_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;This is a decorator&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@decorator_without_wraps&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# This is a decorator
&lt;/span&gt;              &lt;span class="c1"&gt;# Hello
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# inner_function
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that if I wrap the function in a decorator without wraps, the decorator will assume all the metadata of the decorated function.&lt;/p&gt;

&lt;p&gt;Using wraps, the entire signature of that function remains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wraps&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator_with_wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nd"&gt;@wraps&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inner_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;This is a decorator&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@decorator_without_wraps&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;# This is a decorator
&lt;/span&gt;                     &lt;span class="c1"&gt;# Hello world
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# hello_world
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Examples of decorator usage
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/timer"&gt;@timer&lt;/a&gt;&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wraps&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; took &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; seconds to complete&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, the timer function is defined as a decorator. Inside it, there is an inner function called wrapper. This function accepts any number of positional and named arguments.&lt;/p&gt;

&lt;p&gt;Next, the start time of the execution of the original function using time.perf_counter() is measured.&lt;/p&gt;

&lt;p&gt;The original function (func) is then called with the arguments passed to wrapper, and the result is stored. The end time of the execution is recorded using time.perf_counter() again.&lt;/p&gt;

&lt;p&gt;A message is printed, indicating the name of the function and the time it took to execute, formatted with six decimal places. Finally, the result of the original function is returned:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="nd"&gt;@timer&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_lorem_ipsum&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;rootApi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://asdfast.beobit.net/api/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rootApi&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;

&lt;span class="nf"&gt;generate_lorem_ipsum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# generate_lorem_ipsum took 1.063780 seconds to complete
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: here and in the other decorators, I'm using &lt;code&gt;*args&lt;/code&gt; and &lt;code&gt;**kwargs&lt;/code&gt; in the decorator parameters. This is to allow functions that accept a variable number of arguments and pass these arguments forward smoothly. You can read more about it here.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;@repeat&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_times&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator_repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper_repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_times&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper_repeat&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;decorator_repeat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that this decorator is wrapped in another wrapper, and this is because it receives a parameter. The outer function repeat accepts num_times as an argument and returns the inner function decorator_repeat.&lt;/p&gt;

&lt;p&gt;Inside decorator_repeat, which is the decorator itself, the inner function wrapper_repeat is defined. This function, in turn, wraps the execution of the original function in a loop, repeating it num_times times.&lt;/p&gt;

&lt;p&gt;The for loop iterates the number specified by num_times, calling the original function func on each iteration. The result of the last call is stored in value. Finally, wrapper_repeat returns this value, representing the result of the last execution of the original function after all repetitions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_times&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello world&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
&lt;span class="c1"&gt;# Output:
# Hello world
# Hello world
# Hello world
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;@login_required&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wraps&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;validate_token&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login_required&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inner_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;validate_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;inner_function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an example for a Flask API, but it can be adapted for any Python API. The login_required decorator is designed to ensure that only authenticated users can access certain routes or functions in your application.&lt;/p&gt;

&lt;p&gt;Inside the decorator, the inner function inner_function is defined. This function performs an authentication check before allowing the execution of the original function. If the Authorization header is somehow invalid, access is denied with an HTTP response code 401.&lt;/p&gt;

&lt;p&gt;If the authentication check is successful, the original function (func) is called with the passed arguments. This decorator can be applied to specific routes in a Flask application, ensuring that only authenticated users have access, improving the security of the API. This approach is easily adaptable to other Python APIs, providing an effective means of protecting sensitive resources:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/protected&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@login_required&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;protected&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Protected route&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;@rate_limit&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wraps&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Redis&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;

&lt;span class="n"&gt;redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Redis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6379&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rate_limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;per&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remote_addr&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
            &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;reset_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;per&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;X-RateLimit-Reset&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;reset_time&lt;/span&gt;
                           &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%Y-%m-%d %H:%M:%S&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;incr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;per&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;decorator&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This decorator is much more complex, using Redis and also receiving parameters. It should be used in an API context and is also highly adaptable.&lt;/p&gt;

&lt;p&gt;The rate_limit decorator is designed to apply rate limits to a function in an API, controlling the number of times it can be called within a certain interval. It uses Redis as an external storage to keep track of the number of allowed calls.&lt;/p&gt;

&lt;p&gt;By receiving the &lt;code&gt;limit&lt;/code&gt; (maximum call limit) and &lt;code&gt;per&lt;/code&gt; (time period in seconds) parameters, the decorator creates an inner function called wrapper. Within this function, a unique key is generated using the remote client's address and the name of the original function. This allows tracking the number of calls made by a client for a specific function.&lt;/p&gt;

&lt;p&gt;The counter associated with the key is retrieved from Redis, and if the number of calls exceeds the defined limit, a 429 (Rate Limit Exceeded) response is returned with a header indicating the reset time.&lt;/p&gt;

&lt;p&gt;If the rate limit is not exceeded, the counter in Redis is incremented, and the key is set to expire after the per period, ensuring that the counter is reset after the defined interval.&lt;/p&gt;

&lt;p&gt;Finally, the original function (&lt;code&gt;func&lt;/code&gt;) is called with the passed arguments.&lt;/p&gt;

&lt;p&gt;This decorator is highly adaptable and can be applied to different functions in an API, especially to enforce access limits to certain routes, preventing DDoS attacks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/limited&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@rate_limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;per&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;limited_route&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;You are within the rate limit!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Advantages of Decorator
&lt;/h3&gt;

&lt;p&gt;As you may have noticed in these examples, the decorator has numerous advantages in Python. Among them, we have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Modularity Improvement&lt;/strong&gt;: Decorators can be useful for separating specific concerns and improving code modularity. By applying decorators appropriately, it's possible to isolate specific functionalities, making it easier to maintain and understand each component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Reusability&lt;/strong&gt;: the use of decorators can promote code reuse since certain functionalities can be encapsulated and applied to various functions. This can reduce code duplication and facilitate the application of consistent patterns in different parts of the system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ease of Adding Functionality&lt;/strong&gt;: Decorators offer a flexible way to add functionality to existing functions without directly modifying the source code of the function. This can be useful for incorporating new features or behaviors without affecting existing code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Risks of Decorator
&lt;/h3&gt;

&lt;p&gt;Like everything in programming, the decorator also has its risks and dangers. These are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Traceability Loss&lt;/strong&gt;: Depending on the context, decorators can make code traceability difficult, making it challenging to understand the origin of modifications and identify the behavior of a decorated function.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Excessive Dependency&lt;/strong&gt;: Intensive use of decorators can create dependencies between functions, increasing complexity and making maintenance difficult, especially when many decorators are applied in various parts of the code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confusion in Decorator Chains&lt;/strong&gt;: by putting many decorators in a single function, reading the order of application and understanding the execution flow can cause potential confusion in the execution logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When using a decorator, it's important to keep it simple, readable, tested, and well-applied, avoiding excessive use, which can become a bad practice.&lt;/p&gt;




&lt;p&gt;Well, thank you for reading! I hope I've helped you better organize your journey. Well, if you have any suggestions or useful decorators to mention and contribute to the community, don't forget to leave your comment!&lt;/p&gt;

&lt;p&gt;Until next time!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>tutorial</category>
      <category>python</category>
    </item>
    <item>
      <title>Writing and "publishing" your first package in Go</title>
      <dc:creator>Lucas Andrade</dc:creator>
      <pubDate>Tue, 30 Jan 2024 12:14:05 +0000</pubDate>
      <link>https://dev.to/olucasandrade/writing-and-publishing-your-first-package-in-go-3o6l</link>
      <guid>https://dev.to/olucasandrade/writing-and-publishing-your-first-package-in-go-3o6l</guid>
      <description>&lt;p&gt;For a few months now I've been venturing into Go on my company projects. I have much more experience with Javascript/Typescript on the frontend, and on the backend and when writing scripts, I have much more experience with Python. So I'm trying to get used to some of Go's quirks, but there are many reasons why I chose Go as my main personal language. I will leave those reasons for another article.&lt;/p&gt;

&lt;p&gt;Oh, I swear, it's not because of the cuteness of the mascot...&lt;/p&gt;

&lt;p&gt;...but look at this...&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%2Fe82pf6rdnnskt8dxcwyr.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%2Fe82pf6rdnnskt8dxcwyr.png" alt="Go Mascots" width="600" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anyway!&lt;/p&gt;

&lt;p&gt;Recently I wrote a package that analyzes some data from an url and returns a relation with that data:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{ "LoadTime":"488.837125ms","HTTPRequestsCount":3,"PageSize":53 }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can check out and use this package here.&lt;/p&gt;

&lt;p&gt;In detail, it's not the focus of this article to explain why the package was made, how it was made, how to develop it... My goal is for this reading to end with you understanding how to release a package in Go, so that you can release any package you want.&lt;/p&gt;

&lt;p&gt;But without further ado, let's go step by step!&lt;/p&gt;

&lt;p&gt;Disclaimer: I'm assuming in this step-by-step guide that you've already created a Go project, whether it's a simple one or a more complex API, so I'll spare you some basic explanations.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Defining and creating your package
&lt;/h2&gt;

&lt;p&gt;Let's start with the basics, which is creating the package in Golang. In the example in the article, I'll explain it as if I were creating the package I've already created, url-analyzer itself.&lt;/p&gt;

&lt;p&gt;In theory, everything you create in go is a "package". So the first step will be no different from what is already done in any project, which is to start the package in go inside the project folder, either by cloning a repository created on Github, or by creating a folder directly with the project name:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;go mod init github.com/your-username/url-analyzer&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It will create a go.mod in your package with something like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module github.com/your-username/url-analyzer

go 1.21.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Creating your package features
&lt;/h2&gt;

&lt;p&gt;In the root of your project, create a file for the package that contains the functions, classes, or types you want to import externally. It can be called main.go, but it's recommended to create it with the name of your package, since it's not a program to run on its own, so I created a folder called url-analyzer, which contains the only method in my package:&lt;br&gt;
&lt;/p&gt;

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

import (
 "github.com/olucasandrade/url-analyzer/models"
 "github.com/olucasandrade/url-analyzer/services"
)

func Analyze(url string) (*models.PerformanceData, error) {
    as := &amp;amp;services.AnalyzerService{}
    return as.AnalyzeURL(url)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case, I use other folders for the architecture, such as models, services, and helpers, to facilitate unit testing and organization (you can see more at the &lt;a href="https://github.com/olucasandrade/url-analyzer" rel="noopener noreferrer"&gt;repository link)&lt;/a&gt;, but the same logic applies to any project, even if it's a method that adds two values.&lt;/p&gt;

&lt;p&gt;Step 3: Publish your package on Github&lt;/p&gt;

&lt;p&gt;With the package itself already created, we just need to follow the steps to host it correctly in your repository. In my case, I used Github.&lt;/p&gt;

&lt;p&gt;It's no different than uploading any code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add url-analyzer
git commit -m "..."
git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unlike Python with Pypi and Node with npm, in Go the download of a package happens directly where it is hosted, making life much easier for those who publish the package.&lt;/p&gt;

&lt;p&gt;That's it! Your package is now public and available to everyone.&lt;/p&gt;




&lt;h2&gt;
  
  
  Importing and Testing Your Package
&lt;/h2&gt;

&lt;p&gt;As mentioned above, in Go, downloading a package happens right where it is hosted, so we can create a project for testing in the same way:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;go mod init github.com/your-username/url-analyzer-tests&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then get the package with go get:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;go get github.com/olucasandrade/url-analyzer&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and in the main.go folder I'll test if my method &lt;code&gt;Analyze&lt;/code&gt; works correctly:&lt;br&gt;
&lt;/p&gt;

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

import (
  "fmt",
  "github.com/olucasandrade/url-analyzer"
)

func main() {
  response, err := url_analyzer.Analyze("www.criaway.com")
   if (err != nil) {
    panic(err)
   }
  fmt.Println(response.HTTPRequestsCount, "-", response.LoadTime, "-", response.PageSize)
  // 3 - 114.285791ms - 53
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;I hope you like it! As mentioned above, I'm also learning Go, so any comments, suggestions or the like are welcome! See you in the next article!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;del&gt;React 5 times to show support&lt;/del&gt;&lt;/em&gt; 🥰&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>learning</category>
    </item>
    <item>
      <title>10 Chrome extensions to increase your productivity as a developer</title>
      <dc:creator>Lucas Andrade</dc:creator>
      <pubDate>Tue, 22 Aug 2023 13:21:20 +0000</pubDate>
      <link>https://dev.to/olucasandrade/10-chrome-extensions-to-increase-your-productivity-as-a-developer-1bkf</link>
      <guid>https://dev.to/olucasandrade/10-chrome-extensions-to-increase-your-productivity-as-a-developer-1bkf</guid>
      <description>&lt;p&gt;As a developer, productivity is of utmost importance to achieve greater efficiency in our work. Fortunately, there are numerous resources available to aid in this endeavor, and some of them can be found in the form of Chrome extensions. These extensions are small add-ons that can be directly installed in Chrome, offering supplementary tools and enhancing the overall development experience.&lt;/p&gt;

&lt;p&gt;In this article, we will explore 10 Chrome extensions that can enhance our development process:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://chrome.google.com/webstore/detail/clear-cache/cppjkneekbjaeellbfkmgnhonkkjfpdn?hl=pt-BR" rel="noopener noreferrer"&gt;Clear Cache&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;This resource enables developers to easily clear their browser cache, ensuring that the most recent code and design changes are immediately reflected. By eliminating all cached data, this extension prevents display issues and facilitates a more agile development experience. With just one click and without any pop-ups, it effectively clears your data and can be customized in terms of the amount of data you wish to remove.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://chrome.google.com/webstore/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh?hl=pt-BR" rel="noopener noreferrer"&gt;JSON Viewer&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;This extension provides an efficient and improved method for viewing structured data in JSON format directly within your browser. When working with APIs or JSON files, you can utilize this viewer to easily analyze data in a more organized and readable manner. It highlights syntax and formatting clearly, allowing you to better understand and assess the information.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://chrome.google.com/webstore/detail/wappalyzer-technology-pro/gppongmhjkpfnbhagpmjfkannfbllamg?hl=pt-BR" rel="noopener noreferrer"&gt;Wappalyzer&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;This extension is truly remarkable. Once activated, Wappalyzer will identify the technologies and tools employed by any visited website. When activated, Wappalyzer analyzes the website's code and furnishes comprehensive details about the content management system (CMS), front-end frameworks, JavaScript libraries, web servers, plugins, and much more. Wappalyzer provides valuable insights into the technologies adopted across various websites, and this information can be leveraged for diverse purposes.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://chrome.google.com/webstore/detail/smart-color-picker/ilifjbbjhbgkhgabebllmlcldfdgopfl" rel="noopener noreferrer"&gt;Smart Color Picker&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;This extension enables developers to quickly identify the color their mouse is pointing to. You can hover over any color on your webpage and copy the RGB or hexadecimal value of that color. Moreover, Smart Color Picker provides extra features such as a color palette and the ability to save frequently used colors. This proves handy when you need to obtain a color from elsewhere to use in your webpage via CSS, for instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://chrome.google.com/webstore/detail/actitime-time-tracking-pr/oogddkbohgikljeadnkcepdmekigegck" rel="noopener noreferrer"&gt;actiTIME Time Tracking &amp;amp; Project Management&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;This extension provides an integrated solution for tracking your time and managing your projects, making it valuable for developers who aim to enhance their productivity and efficiency.&lt;/p&gt;

&lt;p&gt;With this extension, you can effortlessly log the time spent on specific tasks and allocate working hours to individual projects. Additionally, the extension includes time tracking dashboards, goal setting features, and can be used collaboratively among users, such as when working with a coworker, for instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://chrome.google.com/webstore/detail/window-resizer/kkelicaakdanhinjdeammmilcgefonfh?hl=pt-BR" rel="noopener noreferrer"&gt;Window Resizer&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;With this extension, you can resize the browser window to simulate common tablet, laptop, desktop, and mobile dimensions. This assists you in observing how your website or application will function on various devices. This is crucial to ensure a more consistent user experience based on window size. Additionally, the extension provides preset sizes and allows users to define custom dimensions.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://chrome.google.com/webstore/detail/cssviewer/ggfgijbpiheegefliciemofobhmofgce?hl=pt-BR" rel="noopener noreferrer"&gt;CSSViewer&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;This useful tool offers web developers a simple method to inspect and analyze CSS properties directly on any webpage. Once the extension is activated, developers can effortlessly hover over elements to instantly observe their applied CSS styles, such as font, color, margin, padding, and more. It's even more straightforward than using DevTools inspect. This real-time CSS inspection feature streamlines the process of comprehending and resolving issues in website designs.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi" rel="noopener noreferrer"&gt;React Developer Tools&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;Specifically tailored for React developers, this robust extension offers an indispensable tool for debugging and inspecting React components directly within the browser. Through seamless integration with the React ecosystem, "React DevTools" enables developers to delve into the component hierarchy, scrutinize component props and states, and monitor real-time component updates. This smooth integration streamlines the development process, empowering React developers to swiftly identify and address issues, enhance performance, and attain deeper insights into their application's behavior. Ultimately, this enriches the overall React development experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://chrome.google.com/webstore/detail/fake-filler/bnjjngeaknajbdcgpfkgnonkmififhfo" rel="noopener noreferrer"&gt;Fake Filler&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;This handy tool is specifically designed to streamline form filling during web development and testing. With "Fake Filler," developers can effortlessly generate realistic placeholder data for input fields, such as names, email addresses, phone numbers, addresses, and more. By automating the process of populating forms with diverse and authentic-looking information, "Fake Filler" saves developers valuable time during testing and debugging phases. This extension is particularly useful for ensuring proper functionality and responsiveness of web forms, without the need to manually input test data repeatedly. Overall, "Fake Filler" greatly enhances the efficiency and accuracy of form testing, making it an indispensable resource for web developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://chrome.google.com/webstore/detail/web-developer/bfbameneiokkgbdmiekhjnmfkcnldhhm?hl=pt-BR" rel="noopener noreferrer"&gt;Web Developer&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;Tailored for web developers and designers, this extension equips users with a comprehensive set of features to streamline their development workflow. From inspecting and modifying HTML/CSS elements to analyzing page performance and testing responsiveness, "Web Developer" offers an array of utilities in a user-friendly interface. Developers can easily disable JavaScript, clear cookies, display image dimensions, and examine page structure, among other functionalities. This all-in-one extension empowers developers with quick access to essential web development tools, facilitating efficient debugging, testing, and optimization of websites and web applications.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
      <category>beginners</category>
    </item>
    <item>
      <title>GraphQL vs. REST: Choosing the right approach for your application</title>
      <dc:creator>Lucas Andrade</dc:creator>
      <pubDate>Thu, 06 Jul 2023 14:35:46 +0000</pubDate>
      <link>https://dev.to/olucasandrade/graphql-vs-rest-choosing-the-right-approach-for-your-application-2ll8</link>
      <guid>https://dev.to/olucasandrade/graphql-vs-rest-choosing-the-right-approach-for-your-application-2ll8</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjkyh6vq1dpi26scv99e4.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%2Fjkyh6vq1dpi26scv99e4.png" alt="GraphQL x REST" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The API concept started some decades ago, and it is increasingly gaining popularity as time goes by until today. The acronym, which means &lt;strong&gt;&lt;em&gt;Application Programming Interface&lt;/em&gt;&lt;/strong&gt;, refers to an interface that intermediates between two or more applications. For example: A server connected to a database that delivers this data to a website asynchronously.&lt;/p&gt;

&lt;p&gt;Since then, the API concept has had different protocols and architectures until the early 2000s when REST consolidated as the main way to build APIs in most languages. It continues to be used in different software around the world. For most of these years, we didn't have a popular alternative to REST until 2012 &lt;strong&gt;when Facebook decided to release a new technology in their API called GraphQL&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;More than 10 years have passed, and this technology has grown in different use cases. However, there are many discussions about when and how to use GraphQL or REST. The answer will always be &lt;em&gt;"It depends"&lt;/em&gt;. That's why I decided to write this article explaining the proposed use of GraphQL over REST in an API.&lt;/p&gt;

&lt;h2&gt;
  
  
  How an REST API works?
&lt;/h2&gt;

&lt;p&gt;Basically, a REST API uses the HTTP protocol for data transfer and manipulation in most cases. It functions similarly to a website when it comes to the concept of requests. In summary, a client (another application) makes a call to the server, which then responds with data or modifies it based on the type of method used. The server can also provide conditional data based on its API.&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%2Fb9dr2aog9nsiashb2ms1.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%2Fb9dr2aog9nsiashb2ms1.png" alt="How a REST API works" width="800" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a basic example, our client will be a website that displays a list of profiles on the main screen. Each profile will be represented by a clickable card, showing the user's name, photo, and state.&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%2Fanq9n8ax29ri10b3xqeq.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%2Fanq9n8ax29ri10b3xqeq.png" alt="User's list page" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking on the card, the client navigates to another page that displays profile details, such as the user's job position and description.&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%2F0s8j2evyx8m7xb9f0ced.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%2F0s8j2evyx8m7xb9f0ced.png" alt="User profile page" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well, this data is not located in our client but on our server. When requested, the server provides the data as a JSON object, 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;{
 "name": "Lucas Andrade",
 "state": "Rio de Janeiro",
 "description": "Tech. Music. Society. Software Developer at Geekie, co-founder at Criaway, learning to learn and teach.",
 "employment": "Software Engineer"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Furthermore, we have another table in our database that contains user photos: one main photo and one secondary photo. Let's assume that the client needs to display the secondary photo on the first screen and the main photo on the details page. To fulfill this requirement, an additional request would be made, returning a JSON object 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;{
 "user": "1",
 "primaryPicture": "firsturl.png",
 "secondaryPicture": "secondurl.png"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For these two pages, our client will request the same server, which will provide this specific JSONs.&lt;/p&gt;

&lt;p&gt;Although, this basic example exposes some problems, which GraphQL proposes to solve.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overfetching
&lt;/h3&gt;

&lt;p&gt;Basically, it occurs when a server provides unnecessary data that the client doesn't need. This results in increased resource usage on the server, leading to higher latency and expenses. In our example, the client only needs the user's name and state on the main page, while other information is required only on the details page. One solution for this example would be to create an additional endpoint, which would further increase the resource requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Underfetching
&lt;/h3&gt;

&lt;p&gt;On the other hand, underfetching occurs when there is not enough data retrieved with a single call to an endpoint, forcing you to make a second endpoint call. In our example, the client had to make two different requests for similar things (one to fetch users, another to fetch images). In addition to spending more resources, it also requires higher network performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Weak Typing
&lt;/h3&gt;

&lt;p&gt;In an API written in languages like JavaScript or Python, we sometimes encounter a problem when type checking is skipped. For example, it becomes more cumbersome to verify if the field &lt;code&gt;name&lt;/code&gt; is provided as a &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;undefined&lt;/code&gt;, or any other unexpected data type.&lt;/p&gt;

&lt;p&gt;These are the problems, along with several others, that GraphQL aims to solve.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a GraphQL API works?
&lt;/h2&gt;

&lt;p&gt;For the beginning, when we talk about GraphQL, we no longer discuss distinct routes or endpoints. Each request is made to the same route, using the &lt;code&gt;POST&lt;/code&gt; method, and the details are provided in the request body, 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;query getUser($where: UserInputWhere!, $pictureType: _PictureEnum) {
   name
   state
   description
   employment
   pictures (pictureType: $pictureType)
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Query&lt;/code&gt; is the type of operation (in this case, the client is making a query to retrieve information).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getUser&lt;/code&gt; is the name of the operation, allowing the API to identify the specific action to perform.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$id&lt;/code&gt; and $where are variable names used in the query. For instance, &lt;code&gt;id&lt;/code&gt; is being passed as a variable, enabling the API to find the user based on the provided ID.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt;, &lt;code&gt;state&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;employment&lt;/code&gt;, and &lt;code&gt;pictures&lt;/code&gt; are the fields returned by the API in response to the query.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To gain a basic understanding of how GraphQL works on the server side, I created a simple implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Firstly, we will define the &lt;code&gt;Input&lt;/code&gt;, which will be used as an argument for the query. In our example, we will call it &lt;code&gt;UserInputWhere&lt;/code&gt; and it will have a strongly-typed and required &lt;code&gt;ID&lt;/code&gt; (defined by &lt;code&gt;"!"&lt;/code&gt;):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input UserInputwhere {
  id: ID!,
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now, we define the &lt;code&gt;Type&lt;/code&gt; that will be used for the query return. In this case, we will have the same fields as our REST API, but they will be strongly typed and required. Additionally, we will have a field called pictures, which will be a list of strings. I will explain how it works later:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type User { 
  name: String!
  state: String!
  description: String!
  employment: String!
  pictures (picture Type: _PictureEnum): [String]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The pictures field will receive an argument, as a query inside another query. The argument is not required (indicated by the absence of "!") and has the type &lt;code&gt;_PictureEnum&lt;/code&gt;. This type is used to restrict the options that can be passed and ensure that only values from the Enum options are accepted:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enum _PictureEnum {
  PRIMARY 
  SECONDARY
  ALL
  NONE
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;After that, we will define the query as &lt;code&gt;getUser&lt;/code&gt;, with &lt;code&gt;Input&lt;/code&gt; being &lt;code&gt;UserInputWhere&lt;/code&gt; and returning the type &lt;code&gt;User&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query getUser(where: UserInputwhere!): User
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Finally, we will define the resolvers. A resolver is a function that's responsible for populating the data for a single field in your schema. Your can read more about this in &lt;a href="https://www.apollographql.com/docs/apollo-server/data/resolvers/" rel="noopener noreferrer"&gt;Apollo Docs&lt;/a&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const resolvers = {
  Query: {
    getUser: (root, args) =&amp;gt; users.findOne({ _id: args.id }),
  },
  User: {
    picture: (root, args) =&amp;gt; resolverPicture(args.where),
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A GraphQL advantage is the typing. If our client sends something like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{ id: "invalid id" }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;GraphQL will not accept this query because we don't have a valid &lt;code&gt;ID&lt;/code&gt;. This helps a lot in weakly typed languages. If our resolver returns a &lt;code&gt;null&lt;/code&gt; value in the &lt;code&gt;name&lt;/code&gt; field, for example, GraphQL will also throw an error.&lt;/p&gt;

&lt;p&gt;Another strong GraphQL advantage is the Query. In the case of our client above, if we need another page just for searching the user's &lt;code&gt;state&lt;/code&gt;, I can only remove the other fields inside the object, 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;query getUser($where: UserInputWhere!, $pictureType: PictureEnum) { 
  state
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, the query will not return any fields that our client doesn't need, avoiding the overfetching mentioned before.&lt;/p&gt;

&lt;p&gt;Furthermore, we have one of the biggest advantages of GraphQL. Do you remember the field &lt;code&gt;pictures&lt;/code&gt; defined above? We can use an intermediary function to find the images related to users according to the argument passed on &lt;code&gt;pictureType&lt;/code&gt; and return them all in the same query without needing different endpoints! When we don't need to get the images, we can just remove the field from the same object, avoiding another overfetching case and, in this case, saving up network bandwidth by making two database queries on the same endpoint!&lt;/p&gt;

&lt;p&gt;In our client example, we can pass a &lt;code&gt;{ pictureType: PRIMARY }&lt;/code&gt;  on the first page and a &lt;code&gt;{ pictureType: SECONDARY }&lt;/code&gt;  on the second page! Or even a &lt;code&gt;{ pictureType: ALL }&lt;/code&gt; in case we need all the photos.&lt;/p&gt;

&lt;p&gt;To finish this example, we will create another query responsible for finding all users, reusing the majority of &lt;code&gt;Types&lt;/code&gt; and &lt;code&gt;Inputs&lt;/code&gt;, and returning an user required array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query getUsers (where: Users Inputwhere!): [User]!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const resolvers = { 
const resolvers = {
  Query: {
    getUser: (root, args) =&amp;gt; users.findOne({ _id: args.id }),
    getUsers: (root, _args) =&amp;gt; users.find({}),
  },
  User: {
    picture: (root, args) =&amp;gt; resolverPicture(args.where),
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  GraphQL x REST
&lt;/h2&gt;

&lt;p&gt;Briefly, GraphQL is recommended and can be an alternative in cases of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Applications with different client types where we need to build different implementations&lt;/li&gt;
&lt;li&gt;Applications that need a lot of nested data&lt;/li&gt;
&lt;li&gt;Applications where our API finds data from another different API, also with nested data&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Even with its advantages, GraphQL definitely must not be used for situations with no difference or impact. Problems like overfetching or typing have different alternatives, and GraphQL is just one more. But an excellent alternative.&lt;/p&gt;

&lt;p&gt;In this article, we explored how to implement an API in two ways, and we explain basically why GraphQL gained so much strength in the last few years and is a valid alternative.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Useful links&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://graphql.org/learn/" rel="noopener noreferrer"&gt;GraphQL Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://restfulapi.net/" rel="noopener noreferrer"&gt;What is REST&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://santhosh-adiga-u.medium.com/evolution-of-api-architecture-228624472d79" rel="noopener noreferrer"&gt;Evolution of API Architecture&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>graphql</category>
      <category>programming</category>
      <category>api</category>
    </item>
    <item>
      <title>10 awesome Github repositories that everyone should know</title>
      <dc:creator>Lucas Andrade</dc:creator>
      <pubDate>Thu, 15 Jun 2023 18:25:30 +0000</pubDate>
      <link>https://dev.to/olucasandrade/10-awesome-github-repositories-that-everyone-should-know-2pcp</link>
      <guid>https://dev.to/olucasandrade/10-awesome-github-repositories-that-everyone-should-know-2pcp</guid>
      <description>&lt;p&gt;The technology field is vast, and many people may struggle to organize their studies and start a career, especially in the beginning. Despite the abundance of resources available, the sheer breadth of the field can leave us feeling lost when searching for resources, assistance, ideas, and other things.&lt;/p&gt;

&lt;p&gt;And that's completely normal! That's why there are numerous open repositories on GitHub created by people who want to help in various areas and cover different topics, precisely to enhance your studies. Knowing the abundance of useful repositories, I couldn't help but write about the 10 that I enjoyed the most on the platform and that can help you as they have helped me.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. &lt;a href="https://github.com/bradtraversy/design-resources-for-developers" rel="noopener noreferrer"&gt;Design Resources for developers&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;As the name implies, this repository stores a variety of free resources related to design, providing a one-stop destination for front-end developers to explore. From photos and icons to use in your projects, to CSS libraries or frameworks like React and Vue, it is indeed a vast and valuable repository for your projects or simply for learning purposes.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. &lt;a href="https://github.com/vitalysim/Awesome-Hacking-Resources" rel="noopener noreferrer"&gt;Awesome Hacking Resources&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;Ideally for info-sec students, this repository contains various study materials about this topic. YouTube channels, malware analysis, and forums are just a few of the many subjects that include valuable references and external links.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. &lt;a href="https://github.com/florinpop17/app-ideas" rel="noopener noreferrer"&gt;App Ideas&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;One of the most creative and organized repositories that I've ever seen is App Ideas. It is a repository that provides developers with several ideas to create their own applications. &lt;/p&gt;

&lt;p&gt;However, it has some distinctive features. Its readme file categorizes the ideas based on the knowledge level required. For beginners, there are calculators and previewers. Intermediate level ideas include currency converters and Chrome extensions. For more advanced individuals, there is even an Instagram clone.&lt;/p&gt;

&lt;p&gt;Furthermore, this repository includes a to-do list within each idea, serving as a requirement list to track progress over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. &lt;a href="https://github.com/EbookFoundation/free-programming-books" rel="noopener noreferrer"&gt;Free Programming Books&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The Ebook Foundation created this amazing repository full of free books for those who enjoy reading about programming and technology. The repository contains books in different languages and is categorized into various topics within the tech field. Just enjoy!&lt;/p&gt;

&lt;h2&gt;
  
  
  5. &lt;a href="https://github.com/public-apis/public-apis" rel="noopener noreferrer"&gt;Public APIs&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Who hasn't experienced a headache without ideas, and just by seeing an API, wanted to implement something with it? This repository includes several APIs to help you with that, sorted by themes and indicating whether they require authentication or not, among other things. I'm already going to use some APIs from there for a project, maybe...&lt;/p&gt;

&lt;h2&gt;
  
  
  6. &lt;a href="https://github.com/goldbergyoni/javascript-testing-best-practices" rel="noopener noreferrer"&gt;Javascript Testing: Best Pratices&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;This repository contains several texts, created and translated into multiple languages, about JavaScript testing and Node. Covering good practices on the topic, this repository will provide you with an enjoyable reading experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. &lt;a href="https://github.com/kamranahmedse/developer-roadmap" rel="noopener noreferrer"&gt;Developer Roadmap&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;This repository is really, really, really amazing! One of the most famous on GitHub, updated every year, The Developer Roadmap helps you follow a learning path to become a developer in various topics. There are many subjects for each area, ranging from optional to required.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Clean Code
&lt;/h2&gt;

&lt;p&gt;This book is famous, and you've probably heard about it. Clean Code helps you create clean, readable, and easily maintainable code. However, there are repositories on GitHub with information about this book adapted for various languages and technologies. So, here's a simple list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ryanmcdermott/clean-code-javascript" rel="noopener noreferrer"&gt;Clean Code - Javascript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/piotrplenik/clean-code-php" rel="noopener noreferrer"&gt;Clean Code - PHP
&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/thangchung/clean-code-dotnet" rel="noopener noreferrer"&gt;Clean Code - .NET&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/labs42io/clean-code-typescript" rel="noopener noreferrer"&gt;Clean Code - Typescript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/uohzxela/clean-code-ruby" rel="noopener noreferrer"&gt;Clean Code - Ruby&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  9. &lt;a href="https://github.com/jwasham/coding-interview-university" rel="noopener noreferrer"&gt;Coding Interview University&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Coding Interview University is a repository that gathers topics to prepare you in big tech selection processes as Google, Amazon, Facebook and Microsoft. If you study this repository, you definetly will be prepared.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. &lt;a href="https://github.com/jlevy/the-art-of-command-line" rel="noopener noreferrer"&gt;The Art of Command Line&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;For Linux enthusiasts, this repository allows you to explore the primary system resources, exclusively on the terminal. With detailed reading, you can learn numerous topics about Linux on the command line. I started reading more about it because there is a wealth of content available.&lt;/p&gt;

</description>
      <category>github</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
