<?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: Kevin Alemán</title>
    <description>The latest articles on DEV Community by Kevin Alemán (@kaleman15).</description>
    <link>https://dev.to/kaleman15</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F255126%2F6bdaeb84-6c1e-4e76-9d45-54c59eaac908.jpeg</url>
      <title>DEV Community: Kevin Alemán</title>
      <link>https://dev.to/kaleman15</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kaleman15"/>
    <language>en</language>
    <item>
      <title>What are your most liked agent skills?</title>
      <dc:creator>Kevin Alemán</dc:creator>
      <pubDate>Fri, 19 Jun 2026 14:41:59 +0000</pubDate>
      <link>https://dev.to/kaleman15/what-are-your-most-liked-agent-skills-1d0f</link>
      <guid>https://dev.to/kaleman15/what-are-your-most-liked-agent-skills-1d0f</guid>
      <description>&lt;p&gt;An space for sharing your go-to agent skills so everyone can use them.&lt;/p&gt;

&lt;p&gt;My list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Superpowers (planning &amp;amp; implementation)&lt;/li&gt;
&lt;li&gt;Caveman (for reducing token usage)&lt;/li&gt;
&lt;li&gt;Frontend Design (to help with styling)&lt;/li&gt;
&lt;li&gt;Remember (memory)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have one i created myself called &lt;code&gt;teachme&lt;/code&gt;, which uses a bit of thinking to explain topics to you and then it evaluates your understanding.&lt;/p&gt;

&lt;p&gt;:)&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>Gotta Earn 'Em All: The Gym Badges of Agentic Engineering (Part 1)</title>
      <dc:creator>Kevin Alemán</dc:creator>
      <pubDate>Wed, 17 Jun 2026 20:13:57 +0000</pubDate>
      <link>https://dev.to/kaleman15/gotta-earn-em-all-the-gym-badges-of-agentic-engineering-part-1-5bff</link>
      <guid>https://dev.to/kaleman15/gotta-earn-em-all-the-gym-badges-of-agentic-engineering-part-1-5bff</guid>
      <description>&lt;p&gt;There's a guy who stands at the entrance to the Indigo Plateau and will not let you through. Level 80 Charizard? Doesn't care. Seven gym badges pinned to your jacket? Come back when it's eight. No matter what you do, he won't let you pass until you meet the prerequisites.&lt;/p&gt;

&lt;p&gt;Kid-me thought he was the single most pointless NPC ever programmed. I wanted to go right to the action, not spending 5 hours to get all the badges. Replaying FireRed last month (the GOAT, don't @ me) I finally got what he's for. He isn't guarding the fun part. He's making sure that by the time you face the four people who can actually beat you, you've already survived the eight boring things that made you ready for them.&lt;/p&gt;

&lt;p&gt;Which is, more or less, my entire complaint about how we're using agents right now.&lt;/p&gt;

&lt;p&gt;Everybody wants to fight the Elite Four on day one. "I'll let the agent build the whole feature." "I'll let it refactor the repo while I grab a coffee." "I'll point Claude Code at the thing and vibe." And sometimes it works! Right up until it doesn't, and you genuinely cannot say &lt;em&gt;why&lt;/em&gt; because there were eight gyms between you and that gate and you strolled past every one.&lt;/p&gt;

&lt;p&gt;So here's the case, the way a Game Boy made it to me: before you're actually good with agents, there are badges to earn. Not tools to install, &lt;em&gt;things you have to know.&lt;/em&gt; Let's go gym by gym.&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%2Fkof97yqrvc9dgr53ha0s.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%2Fkof97yqrvc9dgr53ha0s.png" alt="Nintendo Pokemon Fire Red Brock Battle" width="686" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Badge 1: Boulder Badge: rock before copilot
&lt;/h2&gt;

&lt;p&gt;Brock. Rock type. The first gym. The place where you thought choosing charmander was a bad call (until you trained enough and it learned Metal Claw which helps a little bit).&lt;/p&gt;

&lt;p&gt;This is the badge of knowing how to code &lt;em&gt;without&lt;/em&gt; the agent holding your hand. The foundations.&lt;/p&gt;

&lt;p&gt;I've said this before and I'll keep saying it until they revoke my keyboard: &lt;strong&gt;you cannot prompt what you don't know exists.&lt;/strong&gt; If you don't know your project just changed a function's typings, you won't tell the agent, you won't catch it when it gets it wrong, and you'll merrily ship something that &lt;em&gt;looks&lt;/em&gt; right and isn't. The agent didn't fail there. You showed up to the gym with no Pokémon.&lt;/p&gt;

&lt;p&gt;You don't need to know &lt;em&gt;everything&lt;/em&gt;. You need bedrock. Otherwise every badge after this one is built on sand and you're gonna have a bad time.&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%2Ff6xzkd46wcpk757aj1jk.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%2Ff6xzkd46wcpk757aj1jk.png" alt="Nintendo Pokemon Fire Red Misty Battle" width="756" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Badge 2: Cascade Badge: the agent only knows what you pour in
&lt;/h2&gt;

&lt;p&gt;Water flows, context flows, you see where I'm going. An agent isn't psychic (we'll get to that gym), it knows &lt;em&gt;exactly&lt;/em&gt; what's in its context window and nothing else. Not your repo's weird conventions. Not the thing your team decided in Slack last Tuesday. Not the landmine that lives rent-free in one senior dev's brain.&lt;/p&gt;

&lt;p&gt;Look at these two and tell me they're getting the same result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// what most people send
"fix the bug in the user evaluation"
&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;// what you could be doing
"In src/users/evaluate.ts we hardcoded a company name to hit a deadline.
Now we ALSO need to exclude new users from company "bla",
WITHOUT touching how "fancy company" users get evaluated.
Here's the file, here's the test that has to stay green,
here's how we name things."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same model. The first one is basically throwing a Poké Ball at a wall. The second one is, you know, &lt;em&gt;engineering.&lt;/em&gt; Pour the context on purpose and everything downstream gets less cursed.&lt;/p&gt;

&lt;p&gt;Don't make your agent drink from a puddle.&lt;/p&gt;

&lt;p&gt;There's some cool skills that can make your agent "think" this way, but you have to think that way too, so both agent &amp;amp; you can work together on solving &amp;amp; creating.&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%2F94wqmxb7jd54nkdgp4xp.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%2F94wqmxb7jd54nkdgp4xp.png" alt="Nintendo Pokemon Fire Red LT Surge Battle" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Badge 3: Thunder Badge: fast is a trap
&lt;/h2&gt;

&lt;p&gt;Here's what nobody warns you about: agents are &lt;em&gt;fast.&lt;/em&gt; Stupid fast. Faster than you. Faster than me. Faster than anything likely. Issues that would take me a week to solve an agent can find a probable cause in minutes. And speed multiplies whatever you give it, your galaxy-brain ideas and your dumbest ones, at the exact same voltage.&lt;/p&gt;

&lt;p&gt;I've ranted about this in open-source land: opening a PR now costs basically nothing, but &lt;em&gt;reviewing&lt;/em&gt; one still costs a human their actual time and sanity. That gap is a denial-of-service attack wearing a trenchcoat. You tell the agent "do this for every file!!" and now there are 100 changes, some great, some radioactive, and you have to read all 100 because the agent will not tell you which is which. Congrats, you DoS'd yourself.&lt;/p&gt;

&lt;p&gt;The badge here is learning to &lt;em&gt;not grab the lightning with both hands.&lt;/em&gt; Small tasks. Bounded scope. One thing at a time. A fast wrong answer isn't a head start, it just got to being wrong sooner. :(&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%2Fj333vj5pfhqhhb6jx8ce.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%2Fj333vj5pfhqhhb6jx8ce.png" alt="Nintendo Pokemon Fire Red Erika Battle" width="756" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Badge 4: Rainbow Badge: it's gardening, not a vending machine
&lt;/h2&gt;

&lt;p&gt;People treat agents like a vending machine: insert prompt, slot opens, finished feature falls out. Nope. It's &lt;em&gt;gardening.&lt;/em&gt; You plant a thing, you look at the weird mutant that grew, you prune the cursed branches, you re-prompt, you prune again. Repeat until it's a plant and not a crime scene.&lt;/p&gt;

&lt;p&gt;The first output is never the deliverable. It's a sprout. "Good, keep this shape, but the data layer is wrong, redo that part" is the actual loop. The people who look like wizards with agents aren't great prompters, they're patient gardeners who aren't precious about yeeting a bad draft into the sun.&lt;/p&gt;

&lt;p&gt;Plant small, prune often, be responsible for what your agent produces cause that's your personal image too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Halfway to the League
&lt;/h2&gt;

&lt;p&gt;Four badges down. If you actually have these: bedrock, context, scoped speed, and the patience to garden instead of treating the agent like a vending machine, you're already ahead of most people loudly pretending to be good at this.&lt;/p&gt;

&lt;p&gt;Learning is a journey. Enjoy it. Don't let agents &amp;amp; AI remove from you the better part of programming: you getting better at it.&lt;/p&gt;

&lt;p&gt;Obviously, life is not Pokemon. You could perfectly bypass all of this and go straight into your terminal right now to get a "product". That's acceptable in some cases.&lt;/p&gt;

&lt;p&gt;But... where's the fun in that?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>programming</category>
      <category>career</category>
    </item>
    <item>
      <title>You got selected for GSoC 2026, now what?</title>
      <dc:creator>Kevin Alemán</dc:creator>
      <pubDate>Mon, 04 May 2026 04:35:06 +0000</pubDate>
      <link>https://dev.to/kaleman15/you-got-selected-for-gsoc-2026-now-what-1bdc</link>
      <guid>https://dev.to/kaleman15/you-got-selected-for-gsoc-2026-now-what-1bdc</guid>
      <description>&lt;p&gt;So your inbox lit up yesterday with the email. The proposal worked, the interviews worked, the late-night drafts worked. Take a moment, breathe, tell your family, post the screenshot. You earned it 🎉&lt;br&gt;
Now, the actual fun part begins.&lt;/p&gt;

&lt;p&gt;GSoC is, at its core, a few months of getting paid to learn from people who have spent years figuring out how to build software that thousands (sometimes millions) of strangers depend on. Think of it as an internship, but instead of a single company, your "office" is the entire open source world, and your "coworkers" are engineers who chose to spend their free time making things better for everyone. That's a rare seat at the table. Don't waste it.&lt;/p&gt;

&lt;p&gt;Here are a few things to keep in mind so you make the most of it.&lt;/p&gt;
&lt;h2&gt;
  
  
  What a mentor looks for from you
&lt;/h2&gt;
&lt;h3&gt;
  
  
  They want to mentor, not babysit.
&lt;/h3&gt;

&lt;p&gt;Mentors signed up to guide you, answer the hard questions, and unblock you when the codebase fights back. What they did not sign up for is reading the README on your behalf. The heavy lifting, exploring the codebase, running it locally, breaking it, fixing it, writing code that smells like the rest of the repo, that's on you. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A good rule: if you can find the answer in 30 minutes of digging, dig. If you've dug for two hours and you're more confused than when you started, ping them.&lt;/p&gt;

&lt;p&gt;Note 2: at Rocket.Chat, we have an internal meme called &lt;code&gt;:call-the-police:&lt;/code&gt; that would fit perfectly above. Sadly, due to GDPR and other international laws, I cannot share above. End of the note.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Honesty is everything.
&lt;/h3&gt;

&lt;p&gt;LLMs are great at giving you &lt;em&gt;an answer&lt;/em&gt;. They're not great at giving you the answer for this specific repo, with this specific history, with that one weird workaround that's there because of a bug from 2019 nobody wants to revisit. When you step into that kind of fog, just say so. &lt;strong&gt;Mentors respect "I don't get why this is here" way more than a confident wrong guess&lt;/strong&gt;. That said, don't ask for permission to breathe. There's a middle ground between "I'm stuck on every line" and "I haven't said anything in two weeks", and that's where you want to live.&lt;/p&gt;
&lt;h3&gt;
  
  
  Let git do some of the talking.
&lt;/h3&gt;

&lt;p&gt;In a lot of open source repos, the git history is the real diary of the project. Match the style: if they squash, you squash; if they write essays in commit messages, you do too. &lt;strong&gt;Use commits as a steady drumbeat of progress, and save your mentor's inbox for the moments that actually need a human&lt;/strong&gt;. Adding a translation? That's a commit. Untangling a nasty bug and finding a creative fix? That's worth a "hey, look at this" message.&lt;/p&gt;
&lt;h2&gt;
  
  
  What you can ask from your mentor
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Treat them like human documentation.
&lt;/h3&gt;

&lt;p&gt;Mentors are walking archives. They know why a function is named weirdly, which refactor everyone is afraid to touch, and that one PR from 2021 that explains everything. Tap into that, but don't drain the well. Try to find the answer yourself first, give it a responsible amount of time, and if you're still spinning, ask. &lt;strong&gt;The deadline is fixed&lt;/strong&gt;, and running in circles is the most expensive thing you can do with your summer.&lt;/p&gt;
&lt;h3&gt;
  
  
  Ask about the politics the proposal couldn't see.
&lt;/h3&gt;

&lt;p&gt;When you wrote the proposal, you were looking at the project from the outside. Now you're inside, and you'll start spotting things: tech debt, weird coupling, decisions that look wrong until someone explains they're load-bearing. Bring those up. Sometimes the answer will be "yes, let's fix it as part of your work." Other times it'll be "leave it, that rabbit hole eats summers." &lt;em&gt;Both are useful answers, and only your mentor can give them to you.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How to deliver on the proposal you already submitted
&lt;/h2&gt;
&lt;h3&gt;
  
  
  The proposal is the map, not the territory.
&lt;/h3&gt;

&lt;p&gt;You can't redraw it: the timeline, the deliverables, the headline goals are pretty much locked. But there's plenty of room inside the lines: code style, data shapes, security choices, edge cases, testing strategy. &lt;strong&gt;Talk those out with your mentor early&lt;/strong&gt;. The earlier the better, because rework in week 10 hurts a lot more than rework in week 2.&lt;/p&gt;
&lt;h3&gt;
  
  
  Once you've aligned, write a plan.
&lt;/h3&gt;

&lt;p&gt;Break the proposal into weekly chunks, with a rough idea of what "done" looks like for each one. Then, and this is the important part, don't die by the plan. &lt;strong&gt;Plans that are too tight have no room to absorb the inevitable&lt;/strong&gt;: a flu, a flaky test, a rabbit hole, that one dependency that decides to deprecate itself the week you need it. &lt;em&gt;If something can go wrong, it will go wrong&lt;/em&gt;. Plan for it.&lt;/p&gt;


&lt;div class="ltag__wikipedia--container"&gt;
  &lt;div class="ltag__wikipedia--header"&gt;
    &lt;img src="https://assets.dev.to/assets/wikipedia-logo-0a3e76624c7b1c3ccdeb9493ea4add6ef5bd82d7e88d102d5ddfd7c981efa2e7.svg" class="ltag__wikipedia--logo" alt="Wikipedia Logo" width="128" height="128"&gt;
    &lt;a href="https://en.wikipedia.org/wiki/Murphy%27s_law" rel="noopener noreferrer"&gt;Murphy's law&lt;/a&gt;
  &lt;/div&gt;
  &lt;div class="ltag__wikipedia--extract"&gt;&lt;p&gt;&lt;b&gt;Murphy's law&lt;/b&gt; is an adage or epigram that is typically stated as: "Anything that can go wrong &lt;i&gt;will&lt;/i&gt; go wrong."&lt;/p&gt;&lt;/div&gt;
  &lt;div class="ltag__wikipedia--btn--container"&gt;
      &lt;a class="ltag__wikipedia--btn" href="https://en.wikipedia.org/wiki/Murphy%27s_law" rel="noopener noreferrer"&gt;View on Wikipedia&lt;/a&gt;&amp;gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  When to use AI (and when to put your hands on the keyboard)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use AI to plan, not to know.
&lt;/h3&gt;

&lt;p&gt;AI is genuinely great for getting your bearings in a new codebase: "what does this module do", "where is X handled", "give me a tour of this folder". The trap is that it'll happily give you confident answers that feel like understanding without actually being understanding. Always review the plan it gives you. Always question its assumptions. &lt;strong&gt;At the end of the summer, nobody is evaluating the LLM. They're evaluating you&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't let AI eat your learning.
&lt;/h3&gt;

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

&lt;p&gt;This is the part I want you to take most seriously. GSoC is one of the safest spaces you'll ever get to make mistakes: you have a mentor, a stipend, and explicit permission to be a beginner. If you outsource the thinking to an LLM, you're trading the most valuable thing about the program for some saved keystrokes. Especially when it comes to understanding issues: sit with the problem first. Read the code. Form your own theory. Then maybe ask the AI for a second opinion. &lt;strong&gt;AI already "knows" a lot of stuff. The whole point of the summer is: what do you know?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Balance check: we don't want you to feel we (or I) hate AI. AI is really cool and I'm very happy on using it. But as prof. Oak liked to say: "There's a place and time for everything". AI is cool, but the human using it is cooler.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Maintainers can smell it.
&lt;/h3&gt;

&lt;p&gt;I've reviewed enough PRs to tell you this isn't a cute claim: it's true. Code that's 100% AI and 0% human reads differently. The variable names are too generic, the comments explain things nobody would explain, the solution is technically correct but doesn't fit the shape of the codebase, the PR title and/or the code make no sense. Mentors will spot it. And we, the mentors, want you to learn, that's the whole point of GSoC. We want more maintainers for the future. You can be one of them if you use this opportunity.&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%2Fw2n0h7w190dphxhl9pv6.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%2Fw2n0h7w190dphxhl9pv6.png" alt="bro think he slick meme" width="360" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;You'll quickly realize getting selected was the easiest part. &lt;strong&gt;This summer is the real thing&lt;/strong&gt;. Drive your own work, ask the smart questions, ship the small stuff, keep AI as a tool and not as a crutch and you'll come out the other side a much better engineer than the one who opened that email yesterday.&lt;/p&gt;

&lt;p&gt;See you at the final eval 👋&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>gsoc</category>
      <category>software</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Got featured :noice:</title>
      <dc:creator>Kevin Alemán</dc:creator>
      <pubDate>Tue, 10 Mar 2026 16:45:59 +0000</pubDate>
      <link>https://dev.to/kaleman15/-i0</link>
      <guid>https://dev.to/kaleman15/-i0</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/devteam/top-7-featured-dev-posts-of-the-week-1889" class="crayons-story__hidden-navigation-link"&gt;Top 7 Featured DEV Posts of the Week&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/devteam"&gt;
            &lt;img alt="The DEV Team logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1%2Fd908a186-5651-4a5a-9f76-15200bc6801f.jpg" class="crayons-logo__image"&gt;
          &lt;/a&gt;

          &lt;a href="/jess" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F264%2Fb75f6edf-df7b-406e-a56b-43facafb352c.jpg" alt="jess profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/jess" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Jess Lee
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Jess Lee
                &lt;a href="/++"&gt;&lt;img alt="Subscriber" class="subscription-icon" src="https://assets.dev.to/assets/subscription-icon-805dfa7ac7dd660f07ed8d654877270825b07a92a03841aa99a1093bd00431b2.png"&gt;&lt;/a&gt;
              
              &lt;div id="story-author-preview-content-3331226" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/jess" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F264%2Fb75f6edf-df7b-406e-a56b-43facafb352c.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Jess Lee&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/devteam" class="crayons-story__secondary fw-medium"&gt;The DEV Team&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/devteam/top-7-featured-dev-posts-of-the-week-1889" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 10&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/devteam/top-7-featured-dev-posts-of-the-week-1889" id="article-link-3331226"&gt;
          Top 7 Featured DEV Posts of the Week
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/discuss"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;discuss&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/top7"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;top7&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/devteam/top-7-featured-dev-posts-of-the-week-1889" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;47&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/devteam/top-7-featured-dev-posts-of-the-week-1889#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              18&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>top7</category>
      <category>discuss</category>
    </item>
    <item>
      <title>🙌🏽</title>
      <dc:creator>Kevin Alemán</dc:creator>
      <pubDate>Sun, 08 Mar 2026 18:51:54 +0000</pubDate>
      <link>https://dev.to/kaleman15/-j59</link>
      <guid>https://dev.to/kaleman15/-j59</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/kaleman15/in-the-ai-era-code-is-cheap-reputation-isnt-3482" class="crayons-story__hidden-navigation-link"&gt;In the AI Era, Code Is Cheap. Reputation Isn’t.&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/kaleman15" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F255126%2F6bdaeb84-6c1e-4e76-9d45-54c59eaac908.jpeg" alt="kaleman15 profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/kaleman15" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Kevin Alemán
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Kevin Alemán
                
              
              &lt;div id="story-author-preview-content-3309486" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/kaleman15" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F255126%2F6bdaeb84-6c1e-4e76-9d45-54c59eaac908.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Kevin Alemán&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/kaleman15/in-the-ai-era-code-is-cheap-reputation-isnt-3482" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 4&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/kaleman15/in-the-ai-era-code-is-cheap-reputation-isnt-3482" id="article-link-3309486"&gt;
          In the AI Era, Code Is Cheap. Reputation Isn’t.
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/software"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;software&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/kaleman15/in-the-ai-era-code-is-cheap-reputation-isnt-3482" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;33&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/kaleman15/in-the-ai-era-code-is-cheap-reputation-isnt-3482#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              17&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            6 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>opensource</category>
      <category>programming</category>
      <category>software</category>
    </item>
    <item>
      <title>In the AI Era, Code Is Cheap. Reputation Isn’t.</title>
      <dc:creator>Kevin Alemán</dc:creator>
      <pubDate>Wed, 04 Mar 2026 21:01:29 +0000</pubDate>
      <link>https://dev.to/kaleman15/in-the-ai-era-code-is-cheap-reputation-isnt-3482</link>
      <guid>https://dev.to/kaleman15/in-the-ai-era-code-is-cheap-reputation-isnt-3482</guid>
      <description>&lt;p&gt;In the era of AI it's easier than ever to be an Open Source contributor!&lt;/p&gt;

&lt;p&gt;But, at the same time, and quite paradoxically, it's harder than ever.&lt;/p&gt;

&lt;p&gt;Why? Because it's now &lt;em&gt;mechanically easier, but reputationally harder&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Previously, you competed against other incredibly smart volunteers, or maybe against employed developers that contributed their expertise and free time to open source, or against newcomers. Now, you compete against all of that and an army of AI agents generating pull requests, issues, refactors and vulnerability reports faster than what any human can do.&lt;/p&gt;

&lt;p&gt;It's pretty tempting. Using an LLM can reduce significantly the cognitive work you have to do to understand a codebase, and even to produce a valuable change request. Things that were previously "very hard" to do are now a few prompts away, and that lowered the entry barrier for contributions, which is great! But also created a massive increase in volume, which is flooding repositories.&lt;/p&gt;

&lt;p&gt;What's the problem? &lt;br&gt;
&lt;em&gt;Maintainer capacity did not increase&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Review cost did not decrease&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;These two truths have already led maintainer to resort to drastic measures, like what happened with &lt;code&gt;curl&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://daniel.haxx.se/blog/2025/07/14/death-by-a-thousand-slops/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdaniel.haxx.se%2Fblog%2Fwp-content%2Fuploads%2F2017%2F09%2Fbug-insect-1200x803.jpg" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://daniel.haxx.se/blog/2025/07/14/death-by-a-thousand-slops/" rel="noopener noreferrer" class="c-link"&gt;
            Death by a thousand slops | daniel.haxx.se
          &lt;/a&gt;
        &lt;/h2&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdaniel.haxx.se%2Fblog%2Fwp-content%2Fuploads%2F2024%2F07%2Fdaniel-greenbg-blackandwhite-413x413-1.jpg"&gt;
          daniel.haxx.se
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;




&lt;p&gt;So, how do you become a valuable Open Source contributor in the era of infinite code generation? Here are a few tips learned from dealing with a large volume of contributions:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Think. Then think again
&lt;/h2&gt;

&lt;p&gt;AI can produce great code, but it can also produce the worst code ever seen by the humanity. This depends a lot on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;em&gt;prompt&lt;/em&gt; that you use&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;quality&lt;/em&gt; of the LLM&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;context&lt;/em&gt; being shared&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the most important one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your own coding abilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why do you need to know how to code before using LLMs to contribute to open source?&lt;/p&gt;

&lt;p&gt;Well, &lt;em&gt;because an LLM cannot know everything.&lt;/em&gt;&lt;br&gt;
For example, we had a PR that attempted to change this:&lt;/p&gt;

&lt;p&gt;Previous:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Some error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Some error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You would say: that is a valid change, we want to use &lt;code&gt;logger&lt;/code&gt; instead of &lt;code&gt;console&lt;/code&gt;! What's the problem?&lt;/p&gt;

&lt;p&gt;The problem was that the LLM didn't know (and didn't check, cause it wasn't asked to) that we recently changed the typings on our &lt;code&gt;logger&lt;/code&gt; instances, rendering the change invalid.&lt;/p&gt;

&lt;p&gt;What a valid change would have looked like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Some error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But, the LLM didn't know this, and it would have required quite some context for it to know. Good LLMs (Claude, Codex, etc) would have caught, but others would not, unless you asked them. How would you ask something that you didn't know? There's where your coding abilities enter into play.&lt;/p&gt;

&lt;p&gt;Here's the key point: &lt;em&gt;You cannot prompt what you don't know exists&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Someone that wants to be a contributor doesn't trust blindly on what the LLM produces. Knows how to use the tooling (typecheck, in this case) to catch those issues, reads the code to understand current conventions, caveats, etc.&lt;br&gt;
For this programmers, &lt;em&gt;LLMs become a powerful tool&lt;/em&gt;, cause it helps you with the mechanical task of coding and gives you enough time to think.&lt;/p&gt;

&lt;p&gt;This also protects your reputation. If maintainers see a pattern of low-signal PRs from you, they’ll eventually stop reviewing them. Or worse.&lt;/p&gt;

&lt;p&gt;LLMs make contribution faster, but they don’t replace your brain unless you let them.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Respect volume. Review is not free.
&lt;/h2&gt;

&lt;p&gt;You are happy. We're also happy that you want to contribute to open source. It's a noble endeavor and it's something that helps the repository to be safer &amp;amp; you to be better. It's a win-win!&lt;/p&gt;

&lt;p&gt;But, maintainers have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Limited capacity. &lt;/li&gt;
&lt;li&gt;Limited time. &lt;/li&gt;
&lt;li&gt;&lt;em&gt;Limited patience.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We understand, you are happy you created your new PR, and we understand the joy in you of doing that. We've all being there. You want, for sure, your PR to be merged so you can say with honor: "I contributed to X!"&lt;/p&gt;

&lt;p&gt;But, be reasonable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The cost of opening a PR is now near zero.&lt;/li&gt;
&lt;li&gt;The cost of &lt;em&gt;reviewing&lt;/em&gt; it is not.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This asymmetry is the real tension of the AI era.&lt;/p&gt;

&lt;p&gt;If you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;comment “please review” repeatedly,&lt;/li&gt;
&lt;li&gt;ping maintainers aggressively,&lt;/li&gt;
&lt;li&gt;demand merging timelines,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You’re increasing the cognitive cost of your contribution. Even if your PR is valid.&lt;/p&gt;

&lt;p&gt;And here’s the harsh truth:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Maintainers are human.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If interacting with you feels expensive, they may subconsciously deprioritize your work. That means fewer reviews, fewer merges, fewer release notes mentions.&lt;/p&gt;

&lt;p&gt;This is specially important when you use LLMs or Agents as they are fast, way faster than humans, so you could end up doing 100 PRs that you think are valid, and maybe they are! But if the maintainers don't have the capacity to review them all, they just won't.&lt;/p&gt;

&lt;p&gt;That's the definition of a DoS (Denial of Service): you send more requests than what the server (maintainers) can process.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Quality that doesn't cut corners (pls don't sue me Wendy's)
&lt;/h2&gt;

&lt;p&gt;Maintainer capacity is low. We closed around 700 issues (stale, invalid, fixed) in the past month, but at the same time, we received 300 new issues. Some of those issues were valid, some of them were not. The problem is we don't know beforehand, &lt;em&gt;we have to check them all&lt;/em&gt;. You cannot trust an LLM to confirm if something is slop... cause the check may be slop too!&lt;/p&gt;

&lt;p&gt;Related link, &lt;code&gt;curl&lt;/code&gt; fighting against AI slop vulnerability reports:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hackerone.com/reports/3516186" rel="noopener noreferrer"&gt;HackerOne Curl report&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you see, maintainers won't be happy if you waste their time, cause they have stuff to do. The link above, as well as this beautiful list&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





&lt;p&gt;have something in common: they look legit, until they don't. However, for realising something is slop you have to check manually, and that is time/effort wasted.&lt;/p&gt;

&lt;p&gt;So you have to be human, respect the times maintainers have and respect their work. How you do that? &lt;em&gt;Helping the maintainers reduce the cost of reviewing your code&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;Before submitting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did you reproduce the issue yourself?&lt;/li&gt;
&lt;li&gt;Did you run CI locally?&lt;/li&gt;
&lt;li&gt;Did you include screenshots for UI changes?&lt;/li&gt;
&lt;li&gt;Did you provide benchmarks for performance claims?&lt;/li&gt;
&lt;li&gt;Did you include a PoC for security reports?&lt;/li&gt;
&lt;li&gt;Did you check if a feature request already exists?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you claim a performance improvement, &lt;em&gt;show numbers&lt;/em&gt;.&lt;br&gt;
If you fix a bug, &lt;em&gt;explain the root cause&lt;/em&gt;.&lt;br&gt;
If you propose a feature, &lt;em&gt;ask first&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;High quality contributions get reviewed faster.&lt;br&gt;
Low signal contributions accumulate.&lt;/p&gt;

&lt;p&gt;In the AI era, &lt;em&gt;reputation compounds&lt;/em&gt;. If maintainers can trust you, your PRs will be reviewed faster, and you will feel happier. Win-win!&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Bundle trivial changes.
&lt;/h2&gt;

&lt;p&gt;Typos happen. Smol mistakes happen. For example &lt;/p&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subsciption not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;subscription not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Do you spot the bug? Yep, a missing &lt;code&gt;r&lt;/code&gt; on &lt;code&gt;subscription&lt;/code&gt;. The contribution is valid, yes, we want to write correct words in english.&lt;/p&gt;

&lt;p&gt;Does it deserve a PR? Not by itself, maybe if you combine a few more. Think if you find 10 of those misspellings. What's easier for maintainers? 1 PR with 10 changes or 10 PRs with 1 change? Hehe.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you were the maintainer, what would you prefer?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Every PR has overhead: CI runs, notifications, review time, merge time, mental context switch, etc. Reduce the overhead by batching trivial work.&lt;/p&gt;

&lt;p&gt;AI can find an enormous list of fixes like this in a codebase, and if you use an agent like Claude or Clawd you can tell "Hey for each issue create a PR" and then become the most hated contributor on the project :(&lt;/p&gt;

&lt;p&gt;Don't do that. Please. Be mindful. &lt;em&gt;Be human&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  LLMs are fun, but human work is better.
&lt;/h2&gt;

&lt;p&gt;We're on the AI era, we cannot fight AIs anymore, they're here to stay. What we can fight is how we use them.&lt;/p&gt;

&lt;p&gt;For GSoC for example, we value human contributions. That's the point of the program: more humans converting to open source contributors!&lt;/p&gt;

&lt;p&gt;We need new generations of maintainers, of smart people that will use LLMs wisely. You can do amazing stuff with them if you use them properly, but nothing will replace your ability to do amazing stuff as a human. You have to remember that.&lt;/p&gt;

&lt;p&gt;It's easier to contribute, but harder to stand out from the crowd.&lt;br&gt;
Reputation matters.&lt;br&gt;
Trust is earned.&lt;br&gt;
You build it by doing good work.&lt;/p&gt;

&lt;p&gt;As a final note, this is pretty much personal experience. Some projects may have different rules. Some may like to receive 1000 PRs a day (?) idk.&lt;/p&gt;

&lt;p&gt;But, the main point is: AI is not human, but maintainers and contributors are. So remember that.&lt;/p&gt;

&lt;p&gt;Welcome to Open Source!&lt;/p&gt;

&lt;p&gt;If u want to read more:&lt;br&gt;


&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.jeffgeerling.com/blog/2026/ai-is-destroying-open-source/" rel="noopener noreferrer" class="c-link"&gt;
            AI is destroying Open Source, and it's not even good yet - Jeff Geerling
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Over the weekend Ars Technica retracted an article because the AI a writer used hallucinated quotes from an open source library maintainer.
The irony here is the maintainer in question, Scott Shambaugh, was harassed by someone's AI agent over not merging its AI slop code.
It's likely the bot was running through someone's local 'agentic AI' instance (likely using OpenClaw). The guy who built OpenClaw was just hired by OpenAI to "work on bringing agents to everyone." You'll have to forgive me if I'm not enthusastic about that.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          jeffgeerling.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;





</description>
      <category>ai</category>
      <category>opensource</category>
      <category>programming</category>
      <category>software</category>
    </item>
    <item>
      <title>You're doing great, and you need to hear that :)</title>
      <dc:creator>Kevin Alemán</dc:creator>
      <pubDate>Wed, 15 Sep 2021 16:09:03 +0000</pubDate>
      <link>https://dev.to/kaleman15/you-re-doing-great-and-you-need-to-hear-that-12ba</link>
      <guid>https://dev.to/kaleman15/you-re-doing-great-and-you-need-to-hear-that-12ba</guid>
      <description>&lt;p&gt;I'm not the kind of person that likes to be "thanked" for something. I like to do the things, and that's it. And later I realized it was not only me who felt this way. But, is receiving recognition something reserved for super special situations?&lt;/p&gt;

&lt;h2&gt;
  
  
  Everyone needs to be "praised" for doing a great work
&lt;/h2&gt;

&lt;p&gt;Being praised releases dopamine, that's why you feel happy when someone recognizes your work and says that it's good. Everyone likes that feeling of "doing something amazing" by receiving a simple "thanks for helping me". But, it doesn't stop there.&lt;/p&gt;

&lt;p&gt;Your motivation is also increased. It's important to note that everyone has a different set of motivators, so what may work for someone probably won't have the same effect for others. But there are some common motivators in a workplace, like the compensation. Receiving a considerable wage and a good compensation plan on your company may motivate you to work better. Same as having a clean workstation, or having a good team composed of capable people. Recognition is also a &lt;a href="https://www.thesuccessfactory.co.uk/blog/motivators-in-the-workplace-that-improve-employee-experience" rel="noopener noreferrer"&gt;key motivator&lt;/a&gt;, that means, surprisingly, that &lt;a href="https://www.trainingjournal.com/articles/feature/power-praise-and-recognition" rel="noopener noreferrer"&gt;people feel good&lt;/a&gt; when they're recognized :)&lt;/p&gt;

&lt;p&gt;However, as any other dopamine-releaser, the effect of recognition is transient, and, it may decrese the effect over time when it's done &lt;em&gt;too much&lt;/em&gt;. So, recognition should be given timely.&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%2Fk423mpsup0nb13ycv8l8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk423mpsup0nb13ycv8l8.gif" alt="Syndrome's line" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Timely recognition
&lt;/h2&gt;

&lt;p&gt;So, how do we achieve a recognition scheme that's not sporadic but is not rare at the same time? Balance, as always, is the key.&lt;/p&gt;

&lt;p&gt;This is more an HR topic, probably at your company there's a lot of people trying to fix this same issue, because recognition is not as easy as it may look. Fairness plays a &lt;em&gt;really&lt;/em&gt; important role. What if another employee who does the same thing I do receives recognition every week, but I receive it every year? Then, recognition becomes a problem and a demotivator, so it's important to watch out how recognition will be conducted.&lt;/p&gt;

&lt;p&gt;But, let's return to the frequency. From this &lt;a href="https://www.businessinsider.com/how-often-do-employees-need-recognition-2012-8" rel="noopener noreferrer"&gt;BI Article&lt;/a&gt;, a weekly recognition scheme is good. Probably you don't need it to be too frequent. Think for example, on sprints. If your sprints are 2 weeks long, why not dedicating some time at the end to thank your colleagues for their work?&lt;/p&gt;

&lt;p&gt;The same article says that this type of recognition helps the employee to be engaged, and trying to get that recognition again, because people like that. Try to avoid recognizing your employees just with the normal performance review cycle, because that may be too late.&lt;/p&gt;

&lt;p&gt;Again, if your colleague did something &lt;em&gt;really&lt;/em&gt; good for you or the team, don't wait to say thanks. Recognition has a "shelf life", that means, it can expire if not used at the right moment!&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%2Fthumbs.gfycat.com%2FEnchantingSafeArizonaalligatorlizard-max-1mb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthumbs.gfycat.com%2FEnchantingSafeArizonaalligatorlizard-max-1mb.gif" alt="Apu getting expired item from the shelves" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, key points for timely recognition:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do it before it expires :)&lt;/li&gt;
&lt;li&gt;Don't wait to normal performance review cycles to recognize people&lt;/li&gt;
&lt;li&gt;Be fair&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to create a recognition culture?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Make it easy&lt;br&gt;
Your team should feel that it's easy to give recognition. If people find a lot of requirements or an extremely formal process for doing so, they won't do it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Be specific&lt;br&gt;
Saying "thanks" is good, but it's even better when you know &lt;em&gt;the reason&lt;/em&gt; for that. So saying "thanks for helping me with the last presentation" would be much more valuable than just saying thanks, because that means you're recognizing &lt;em&gt;a specific effort&lt;/em&gt;, and not just saying a canned response.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Connect the dots :)&lt;br&gt;
Relate the recognition with your company's values. This makes easier for your team to know how they're contributing to the company's objectives and culture, and that creates a strong culture :)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make it for everyone&lt;br&gt;
Avoid having only managers giving recognition. Foster p2p recognition, since that'll create bounds between your team.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(Key points taken from &lt;a href="https://www.greatgame.com/blog/creating-a-recognition-culture-best-practices" rel="noopener noreferrer"&gt;this article&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, as conclusion, thanks for what you're doing to improve the community :) and thanks for sharing your knowledge with the rest of the people using this platform.&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%2Furw26vjcobmnds2984jb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Furw26vjcobmnds2984jb.jpg" alt="Simpsons' Monstromart: we love you" width="720" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, go there and recognize people for what they're doing :)&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>mentalhealth</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The beauty of Streams in Node</title>
      <dc:creator>Kevin Alemán</dc:creator>
      <pubDate>Fri, 02 Oct 2020 21:06:17 +0000</pubDate>
      <link>https://dev.to/kaleman15/the-beauty-of-streams-in-node-28d</link>
      <guid>https://dev.to/kaleman15/the-beauty-of-streams-in-node-28d</guid>
      <description>&lt;p&gt;Probably you have heard of them, probably you don't. But they have been around for a while. We're talking about &lt;code&gt;streams&lt;/code&gt;, an interesting and often ignored functionality of Node.JS.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are streams?
&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%2Fextension.unh.edu%2Fsites%2Fdefault%2Ffiles%2Fstyles%2F2x_blog_main%2Fpublic%2F2MountainStream_MCarp.jpg%3Fitok%3DDW1-tkGH%26timestamp%3D1516995141" 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%2Fextension.unh.edu%2Fsites%2Fdefault%2Ffiles%2Fstyles%2F2x_blog_main%2Fpublic%2F2MountainStream_MCarp.jpg%3Fitok%3DDW1-tkGH%26timestamp%3D1516995141" alt="a river, or stream?" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make things easier, we will define a stream as a &lt;code&gt;sequence of data that flows freely&lt;/code&gt;. Think of streams like rivers. Rivers flow from one point to another in a constant way. The receiver doesn't know when the river will stop flowing but it's always there for receiving more water.&lt;/p&gt;

&lt;p&gt;In Node, streams are very similar. They are a constant sequence of data. They flow from one point (emitter) to another (receiver). &lt;/p&gt;

&lt;p&gt;The receiver can decide if it wants to receive data or not. Also it decides what to do with the data received. It can &lt;code&gt;ignore&lt;/code&gt; the data, &lt;code&gt;pipe&lt;/code&gt; it to another receiver, &lt;code&gt;parse&lt;/code&gt; it before receiving... &lt;/p&gt;

&lt;h2&gt;
  
  
  Why are streams useful?
&lt;/h2&gt;

&lt;p&gt;This is a really good question. If you have lived without streams your whole life, you will think that you don't need them. And, depending on your use case, this could be true.&lt;/p&gt;

&lt;p&gt;But the reality is that we need to use streams for some operations that otherwise will kill us. Let's put an example&lt;/p&gt;

&lt;h3&gt;
  
  
  Dealing with files
&lt;/h3&gt;

&lt;p&gt;Let's say we want to create a compressed copy of a file on our disk with a Node application. Usually, we will end up with something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;zlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gzip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.gz&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Done!!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Imports removed for brevity&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here, we're doing 4 things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We're reading the &lt;em&gt;entire&lt;/em&gt; file and saving the data to a variable called &lt;code&gt;buffer&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;We're using the &lt;code&gt;zlib.gzip&lt;/code&gt; to compress the file into a &lt;code&gt;gzip&lt;/code&gt;. We're passing the buffer to the function call. This will return a new compressed buffer&lt;/li&gt;
&lt;li&gt;We write the compressed buffer to a new location&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;console.log&lt;/code&gt; indicating that the operation finished&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Well, this works. What's the problem with this approach? You may be wondering. Well, look again at the first 2 steps. In this approach, we're reading the &lt;em&gt;whole file&lt;/em&gt; before starting to process it. Additionally, we're storing the contents of that file in memory. This is not a problem if the file size is in MB. But, if the file size is in the order of GB? Hundreds of GB? Will your computer have all that RAM available to hold the file in it? Probably no. &lt;/p&gt;

&lt;p&gt;So, this approach, even when enough for more simple tasks, represents a problem when we're looking for performance and scalability, or simply we want to support larger files.&lt;/p&gt;

&lt;p&gt;The problem can be solved by using &lt;code&gt;streams&lt;/code&gt;. Let's see how:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createReadStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;zlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createGzip&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createWriteStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.gz&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;finish&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wooh!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're doing some things different here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We're creating a &lt;code&gt;read stream&lt;/code&gt;. This will return us &lt;code&gt;chunks&lt;/code&gt; of the file until it reaches the end.&lt;/li&gt;
&lt;li&gt;We're &lt;code&gt;piping&lt;/code&gt; the chunks to &lt;code&gt;zlib&lt;/code&gt; for compression. What's important here is that we are not waiting for the whole file to be read before starting the compression.&lt;/li&gt;
&lt;li&gt;We're creating a &lt;code&gt;write stream&lt;/code&gt; in which we're passing &lt;code&gt;chunks&lt;/code&gt; of data so Node can write them to the file.&lt;/li&gt;
&lt;li&gt;After all, we listen for the &lt;code&gt;finish&lt;/code&gt; event, which will be triggered when there's nothing more to do.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There's a vast set of details &amp;amp; quirks &amp;amp; functions related to streams which will be covered in other blog posts.&lt;/p&gt;

&lt;p&gt;Hope you liked it!&lt;/p&gt;

</description>
      <category>node</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Building a new feature: talks preview</title>
      <dc:creator>Kevin Alemán</dc:creator>
      <pubDate>Fri, 11 Sep 2020 06:59:14 +0000</pubDate>
      <link>https://dev.to/kaleman15/building-a-new-feature-talks-preview-4mp0</link>
      <guid>https://dev.to/kaleman15/building-a-new-feature-talks-preview-4mp0</guid>
      <description>&lt;p&gt;I'm a backend developer, so most of the time I'm doing backend things. I feel stressed most of the time when I need to do something at the front. &lt;/p&gt;

&lt;p&gt;Then, I started to build my own personal site. And it was great! It's a blog site located temporarily at &lt;a href="https://kaleman.netlify.app" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt; where you can contact me, read what I wrote, share my content with a suggested tweet, and &lt;em&gt;now&lt;/em&gt; you can see the talks I've given in my career. &lt;/p&gt;

&lt;p&gt;The talks are mostly about basic topics, one of them is in progress yet, but I wanted to showcase that I made them. And this was when the trouble begins&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%2F3vlfi3z52kggntvvn83l.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3vlfi3z52kggntvvn83l.gif" alt="prepare for the problems, and make it double" width="500" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How?
&lt;/h3&gt;

&lt;p&gt;The first thing was to define what I wanted: I wanted to showcase my presentations. This was easy (in my mind), but, it wasn't easy in real life.&lt;/p&gt;

&lt;p&gt;To give you more context, I store all my presentations in Google Drive, so I can work on them wherever I go. This makes things easier for working on them, but a little bit hard if you want to show them offline.&lt;/p&gt;

&lt;p&gt;Why? Because first, you have to download the file. This is a no-brain task with a UI, just right-click and download. GG. The task gets more complex when you want &lt;em&gt;your code&lt;/em&gt; to perform that process. So I walked a lonely road, the only one that I have ever known: looking for someone who tried the same and succeeds. &lt;/p&gt;

&lt;p&gt;I found multiple &lt;a href="https://www.gatsbyjs.com/plugins" rel="noopener noreferrer"&gt;Gatsby plugins&lt;/a&gt; by just typing &lt;code&gt;drive&lt;/code&gt; or &lt;code&gt;google drive&lt;/code&gt; into the search box. I tried every single one, with the hope of finding what I wanted. Here's a list of the highlighted ones if you are trying to do something similar:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/cedricdelpoux/gatsby-source-google-docs" rel="noopener noreferrer"&gt;gatsby-source-google-docs&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The problem: the use case I had in mind was very different from what the library did&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/fabe/gatsby-plugin-drive" rel="noopener noreferrer"&gt;gatsby-plugin-drive&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The problem: it only allowed me to download DOC files (not presentations, which was what I wanted)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/jpalmieri/gatsby-source-drive" rel="noopener noreferrer"&gt;gatsby-source-drive&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The problem: it didn't work. Maybe I misconfigured something or so.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/maxsteenbergen/gatsby-plugin-drive" rel="noopener noreferrer"&gt;gatsby-plugin-docs-sheets&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The problem: it only allowed me to download Sheets. I'm pretty sure this was based on &lt;code&gt;gatsby-plugin-drive&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, since no plugin was able to fulfill my needs, I had to make a difficult decision:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give up on my feature&lt;/li&gt;
&lt;li&gt;Create my own plugin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I took the second, and this plugin was the result: &lt;a href="https://github.com/KevLehman/gatsby-plugin-googledrive" rel="noopener noreferrer"&gt;Gatsby-plugin-googledrive&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The entire plugin was based on a single idea: given a Google Drive's &lt;code&gt;folderID&lt;/code&gt;, download all files from the folder, and traverse the subfolders recursively to create the same structure on your selected &lt;code&gt;destination&lt;/code&gt;. And download the files for each folder.&lt;/p&gt;

&lt;p&gt;The technical details can be found at the GitHub of the project and, it's open-source, so if you want to build something around it feel free to do so.&lt;/p&gt;

&lt;h3&gt;
  
  
  How? Part 2
&lt;/h3&gt;

&lt;p&gt;After creating my plugin, I "plugged" it and the download started. I finally had the files on my local, and this was one step closer to my goal.&lt;/p&gt;

&lt;p&gt;I had the PDFs on my local, now, I wanted to do 3 things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get the URL from the PDF in my filesystem (and application!)&lt;/li&gt;
&lt;li&gt;Get the first page of the PDF (the "cover page")&lt;/li&gt;
&lt;li&gt;Convert that page to an image, and show it on a nice grid&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Soo, I needed 3 things: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One way to get the PDF from my filesystem&lt;/li&gt;
&lt;li&gt;One way to read the PDF&lt;/li&gt;
&lt;li&gt;One way to convert the read PDF into images&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the first item, since I'm using Gatsby, I used the &lt;a href="https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-source-filesystem" rel="noopener noreferrer"&gt;gatsby-source-filesystem&lt;/a&gt; to read my folder and get the actual asset URL pointing to my file. It was really easy, just added this to my &lt;code&gt;gatsby-config.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gatsby-source-filesystem&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;talks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${__dirname}/src/talks/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it! Then, to query my filesystem and get the &lt;code&gt;nodes&lt;/code&gt; with data, some &lt;code&gt;graphql&lt;/code&gt; was needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;allFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sourceInstanceName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"talks"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;publicURL&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;  
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That query will do 2 things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get all the files under the &lt;code&gt;path&lt;/code&gt; of the &lt;code&gt;instance name&lt;/code&gt; called &lt;code&gt;talks&lt;/code&gt; (which is the &lt;code&gt;name&lt;/code&gt; property you pass to the plugin definition)&lt;/li&gt;
&lt;li&gt;For each &lt;code&gt;node&lt;/code&gt; aka &lt;code&gt;file&lt;/code&gt;, get its &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;publicURL&lt;/code&gt; (which is the URL that the asset will have after the building)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the second item, I had to do some research. After some looking, I finally found &lt;a href="https://github.com/mozilla/pdfjs-dist" rel="noopener noreferrer"&gt;PDF.JS&lt;/a&gt; which is like the standard for managing PDFs in JavaScript. It was written by Mozilla and has a ton of useful functions. I just used the basic API to get my feature working in a few LoC.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;PDFJS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;talk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publicURL&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// some code goes here&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The introduction to the library in its GitHub page was simple, maybe too small for my taste, but it worked. With this, the only thing left was to find a way to convert the PDF page's data into an actual image.&lt;/p&gt;

&lt;p&gt;I found a pretty nice approach to accomplish that. It worked like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read the PDF page&lt;/li&gt;
&lt;li&gt;Scale the page's width and height (by using the viewport of the page)&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; element&lt;/li&gt;
&lt;li&gt;Set the canvas context to &lt;code&gt;2d&lt;/code&gt; (since we'll draw an image)&lt;/li&gt;
&lt;li&gt;Set the scaled page as the new data context for the &lt;code&gt;canvas&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full code was linked in this &lt;a href="https://stackoverflow.com/a/12921304" rel="noopener noreferrer"&gt;StackOverflow's answer&lt;/a&gt; which even had an example of how it worked. Nice.&lt;/p&gt;

&lt;p&gt;With all of that in place, the final result: &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%2Fi%2Fs0f8n6jf00jerp5mu57f.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%2Fi%2Fs0f8n6jf00jerp5mu57f.png" alt="My site, with the talks page populated" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hope you liked the article, feel free to also visit this post on my &lt;a href="https://kaleman.netlify.app/" rel="noopener noreferrer"&gt;own website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>javascript</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Algos in real life: binary search</title>
      <dc:creator>Kevin Alemán</dc:creator>
      <pubDate>Fri, 04 Sep 2020 20:14:12 +0000</pubDate>
      <link>https://dev.to/kaleman15/algos-in-real-life-binary-search-18jf</link>
      <guid>https://dev.to/kaleman15/algos-in-real-life-binary-search-18jf</guid>
      <description>&lt;p&gt;You probably know about algorithms. You probably don't. So here's a basic definition: an algorithm is a chain of steps for moving from A to B.&lt;/p&gt;

&lt;p&gt;If you want to make a sandwich, you probably have an algorithm for that. Mine is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get the ingredients&lt;/li&gt;
&lt;li&gt;Separate bread and put it on a plate&lt;/li&gt;
&lt;li&gt;Put some dressing on both halves&lt;/li&gt;
&lt;li&gt;Put lettuce, tomatoes, pickles (if any) on one half&lt;/li&gt;
&lt;li&gt;Put ham, cheese, ham again on one half&lt;/li&gt;
&lt;li&gt;Add extra things (this is, probably whatever I can find that fits my sandwich)&lt;/li&gt;
&lt;li&gt;Put the empty half over the other ingredients&lt;/li&gt;
&lt;li&gt;Eat&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whatever your process is, the point is you use an algorithm for that.&lt;/p&gt;

&lt;p&gt;Algos are really useful, in programming and real life. Here, I'll show you an example of how I used one of those algos to make my life (and work) easier.&lt;/p&gt;

&lt;h3&gt;
  
  
  The task
&lt;/h3&gt;

&lt;p&gt;Suppose that you were assigned to solve an issue at work. Depending on the kind of issue this may be easy peasy lemon squeezy or you can end stressed depressed lemon zest. &lt;br&gt;
The issue in this example is a simple one: a function was working at some time in the past, but now it's not. Easy.&lt;/p&gt;

&lt;p&gt;You fix the function, upload your changes, and create a merge request. Everything fine at this point.&lt;/p&gt;

&lt;p&gt;Then, someone from above asks the hard question: "Hey, this worked in the past, could you tell me &lt;em&gt;when&lt;/em&gt; it stopped working?". If like mine, your project has a ton of commits, then you'll have fun, more if your commit history looks like this:&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%2Flqskzvhh87ix4p3mmhru.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%2Flqskzvhh87ix4p3mmhru.png" alt="xkcd commit history" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The solution
&lt;/h3&gt;

&lt;p&gt;You have 3 options here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Cry in a corner&lt;/li&gt;
&lt;li&gt;Traverse &lt;em&gt;all&lt;/em&gt; your commits until you find one where it was working&lt;/li&gt;
&lt;li&gt;Do something good with the knowledge you have&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ok, after doing the first we can start thinking on a real solution. And here's where algorithms come handy. Let's remember one of them!&lt;/p&gt;

&lt;h4&gt;
  
  
  The binary search algo, or the principle of divide and conquer.
&lt;/h4&gt;

&lt;p&gt;You may remember that algorithm from a class, a course, some reading, or any other place. In case you haven't, I'll leave a brief explanation here: &lt;/p&gt;

&lt;p&gt;The main idea of this algorithm is to, given a sorted list and a value to find as inputs, traverse the list to find the value you're looking for.&lt;/p&gt;

&lt;p&gt;The main point of difference between this and other search algos is &lt;em&gt;how&lt;/em&gt; the list is traversed. &lt;/p&gt;

&lt;p&gt;In traditional searching, you go from the start until the end (in the worst case) to find what you're looking for. If you reach the end and you haven't found the value, then it's not there. Something like this:&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%2F7iuxzyifcqe9ge9xt4d9.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7iuxzyifcqe9ge9xt4d9.gif" alt="Linearsearch" width="438" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a binary search, however, you "divide" the list in halves, then compare the middle value with what you're looking for. If the value is greater, then you repeat the process in the left half, otherwise you use the right half. You repeat this until you cannot divide your input list anymore. Something like this:&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%2Fdaic2okdulcwwggm1wdz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdaic2okdulcwwggm1wdz.gif" alt="Binary search" width="773" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To use a binary search, you just have to follow some rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your list must be sorted&lt;/li&gt;
&lt;li&gt;Your list must be sorted&lt;/li&gt;
&lt;li&gt;Your list &lt;em&gt;must&lt;/em&gt; be sorted&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ok. You got this, the list must be sorted. Let's continue with the solution!&lt;/p&gt;

&lt;h3&gt;
  
  
  The solution (part 2)
&lt;/h3&gt;

&lt;p&gt;Since our commit history is sorted (by the date of the commit) we can perform a binary search on the commit history!&lt;/p&gt;

&lt;p&gt;I selected some old commit (like 20 days before) as my start point and my current commit as the last item. &lt;br&gt;
I, then, selected the middle one (this was made visually) and &lt;code&gt;checkout&lt;/code&gt;ed to that commit.&lt;/p&gt;

&lt;p&gt;Was functionality working? Yes? Select a more recent one! Else, use an older one.&lt;/p&gt;

&lt;p&gt;You know how the story ends. I was able to verify the whole commit history in like 20 minutes, when it may have taken 2 hours due to the number of commits in the pool.&lt;/p&gt;

&lt;p&gt;Moral: if you know how to do something fast, do it! And, algos are also useful in real life!&lt;/p&gt;

&lt;p&gt;Hope you liked this history, and let me know if it helped you! Thanks for reading 🎉&lt;/p&gt;

</description>
      <category>git</category>
      <category>productivity</category>
      <category>beginners</category>
      <category>development</category>
    </item>
    <item>
      <title>Developing JS/TS with VIM</title>
      <dc:creator>Kevin Alemán</dc:creator>
      <pubDate>Thu, 18 Jun 2020 06:48:58 +0000</pubDate>
      <link>https://dev.to/kaleman15/developing-js-ts-with-vim-49ke</link>
      <guid>https://dev.to/kaleman15/developing-js-ts-with-vim-49ke</guid>
      <description>&lt;p&gt;In the beginning, there were editors. And VIM was an editor. And VIM was &lt;em&gt;the&lt;/em&gt; editor.&lt;/p&gt;

&lt;p&gt;I started to code 3 years ago. When I started to code, I remember having one coworker that was using Emacs. He just stared at its screen without using the mouse, and all he was doing was using the keyboard to do what he needed. He tried to convince me to use Emacs as well, but something didn't feel so good when using it.&lt;/p&gt;

&lt;p&gt;I, then, started to use VSCode. The good VSCode. I don't have anything to say against him. VSCode is an excellent editor. The only thing that stressed me out was its insane memory usage! After all, it's built in the top of Chromium, so it will use the RAM accordingly. VSCode is a perfect editor for almost anything you want to do. Do you want to write Java? There's a plugin. Do you want to test your API? There's a plugin. Do you want to manage your database? There. Is. A. Plugin. It's not an IDE because they haven't given the title to it!&lt;/p&gt;

&lt;p&gt;Even when that rich ecosystem is something beautiful by itself, it can led to some issues. The memory usage may go insane as you install more extensions. And disabling them based on the workspace (which you have to configure manually) instead of filetype stressed me more. &lt;/p&gt;

&lt;p&gt;So, there was a time, when I was working in a project that used a lot of docker containers, they used a lot of RAM by themselves, and I was using VSCode too. The RAM cake was starting to finish. Also, I had Chrome and another applications that I use to do my work (like Slack, which is also on top of Chromium) trying to get a piece of cake too... My computer didn't like that, so it crashed. This happened consistently for one month. I tried to change browser, to use Slack in my phone, to do some kind of black magic to get the most of my PC, even I tried to &lt;a href="https://downloadmoreram.com/" rel="noopener noreferrer"&gt;download&lt;/a&gt; more RAM (I really expected this one to work... :( ). But nothing happened. &lt;/p&gt;

&lt;p&gt;Then, the illumination came to me.&lt;/p&gt;

&lt;p&gt;I took a course, and one of the instructors was using VIM, but it was like an IDE. It was perfect. He moved so quickly between tabs (buffers) and commands were intuitive. The color scheme was great, the speed was really impressive. He had autocompletion and listing... everything was perfect. &lt;/p&gt;

&lt;p&gt;Motivated by this, I went to my laptop and installed VIM. But... &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%2Fi%2Fw4ehqeleysrz2ubtxo2j.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%2Fi%2Fw4ehqeleysrz2ubtxo2j.png" alt="first vim opening" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;IT WAS NOT LIKE THE VIDEO. WHY? I didn't have the autocomplete, neither the status bar nor the file explorer... it was just an empty console. Like Emacs was. And also I wasn't able to get out of it.&lt;/p&gt;

&lt;p&gt;I realized that Vim was not pretty out-of-the-box. You have to work on it before using it to write code. So I spent a few days reading VIM tutorials and contents. I looked for online resources, and found these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.openvim.com/" rel="noopener noreferrer"&gt;Try VIM online&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vim-adventures.com/" rel="noopener noreferrer"&gt;Learn VIM while playing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learnvimscriptthehardway.stevelosh.com/" rel="noopener noreferrer"&gt;Learn VimScript the hard way&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After finishing 2 of those (obviously the first 2...) I was ready to start to use VIM.&lt;/p&gt;
&lt;h2&gt;
  
  
  The shorcuts
&lt;/h2&gt;

&lt;p&gt;This is a list of the basic shortcuts I learnt before using VIM. These ones allowed me to at least know how to use it. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To exit vim:
&lt;code&gt;:q&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;To enter in edit mode:
&lt;code&gt;i&lt;/code&gt; (yeah, just type &lt;code&gt;i&lt;/code&gt; and you will get into edit mode)&lt;/li&gt;
&lt;li&gt;To exit edit mode (and all other modes):
&lt;code&gt;esc&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;To "save a file":
&lt;code&gt;:w&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;To close without "saving":
&lt;code&gt;:q!&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;To split "tabs" vertically:
&lt;code&gt;Ctrl + wv&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;To split "tabs" horizontally:
&lt;code&gt;Ctrl + ws&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;To change between "tabs":
&lt;code&gt;Ctrl + ww&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The plugins
&lt;/h2&gt;

&lt;p&gt;First of all, like every person looking for knowledge, I typed &lt;code&gt;How to add plugins to vim&lt;/code&gt; in Google. I followed some links and one of them took me to &lt;a href="https://github.com/tpope/vim-pathogen" rel="noopener noreferrer"&gt;Pathogen&lt;/a&gt;, which is a package manager that uses Git (just Git) to get the plugins. I also read about &lt;a href="https://github.com/junegunn/vim-plug" rel="noopener noreferrer"&gt;VimPlug&lt;/a&gt;, but Pathogen was my choice.&lt;/p&gt;

&lt;p&gt;Why? Well, I liked the way it should be enabled:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;execute pathogen#infect()
syntax on
filetype plugin indent on
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do you see? Pathogen "infects" VIM. Isn't it nice? Well, I probably lol'ed so hard when reading that, more than I should. That convinced me to use it instead of VimPlug.&lt;/p&gt;

&lt;p&gt;Later, I discovered VIM 8 had native plugin support... &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%2Fi.kym-cdn.com%2Fentries%2Ficons%2Foriginal%2F000%2F006%2F306%2FFlipTable.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.kym-cdn.com%2Fentries%2Ficons%2Foriginal%2F000%2F006%2F306%2FFlipTable.jpg" alt="flipping the table" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The plugin list
&lt;/h3&gt;

&lt;p&gt;Now that I had a plugin manager, I needed plugins. Where did I find them? I used &lt;a href="https://vimawesome.com/" rel="noopener noreferrer"&gt;Vim Awesome&lt;/a&gt; to get a list of most used plugins and filter the ones that were related to JS/TS/Go. Then, I installed them. Here's the list of the modules I have downloaded for my current development:&lt;/p&gt;

&lt;p&gt;(Images taken from Vimawesome)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://vimawesome.com/plugin/nerdtree-red" rel="noopener noreferrer"&gt;The NERDTree&lt;/a&gt; (to interact with the filesystem)&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%2Ftjlt55ffojt6rqolv68v.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%2Ftjlt55ffojt6rqolv68v.png" alt="nerdtree look and feel" width="800" height="543"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://vimawesome.com/plugin/vim-airline-superman" rel="noopener noreferrer"&gt;Vim Airline&lt;/a&gt; (to get nice look and feel)&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%2Fs04cczhszzoqplev6qfa.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs04cczhszzoqplev6qfa.gif" alt="vim airline look and feel" width="641" height="72"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://vimawesome.com/plugin/fugitive-vim" rel="noopener noreferrer"&gt;Vim Fugitive&lt;/a&gt; (this plugin is so awesome that it should be illegal)&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%2Fi%2Ftropsiz4uvt87h9uz7bu.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%2Fi%2Ftropsiz4uvt87h9uz7bu.png" alt="example git log ran from fugitive.vim" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://vimawesome.com/plugin/vim-polyglot" rel="noopener noreferrer"&gt;Vim Polyglot&lt;/a&gt; (for really good syntax highlight) &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%2Fi%2Fqzirhss8oiiea53zi9oj.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%2Fi%2Fqzirhss8oiiea53zi9oj.png" alt="Typescript syntax highlight with Polyglot" width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://vimawesome.com/plugin/ale" rel="noopener noreferrer"&gt;ALE&lt;/a&gt; (An asynchronous linting engine. This is very useful to configure &lt;code&gt;ESLint&lt;/code&gt; and &lt;code&gt;Prettier&lt;/code&gt; in Vim)&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%2Ftsrzkb974btf6fm77buh.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftsrzkb974btf6fm77buh.gif" alt="example ale linting js code" width="600" height="330"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://vimawesome.com/plugin/coc-nvim" rel="noopener noreferrer"&gt;COC.vim&lt;/a&gt; (the ultimate code completion plugin)&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%2Fs1o4waospzry2hd0xm6h.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1o4waospzry2hd0xm6h.gif" alt="example coc.vim suggesting code" width="1504" height="784"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't all the plugins I use. I just wrote there the most important ones. The ones without its help I wouldn't be able to write code in VIM. &lt;/p&gt;

&lt;p&gt;The final product, using the plugins and one theme that I found (it's called &lt;code&gt;onehalfdark&lt;/code&gt;) was this: &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%2Fi%2Fmnpha41bz41n3sjhxrlq.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%2Fi%2Fmnpha41bz41n3sjhxrlq.png" alt="my vim after the time investment on it" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hope you liked my intro to the Vim world, and maybe this motivates you to start getting into Vim! &lt;/p&gt;

</description>
      <category>vim</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Fuzzy Searching with PostgreSQL</title>
      <dc:creator>Kevin Alemán</dc:creator>
      <pubDate>Mon, 11 May 2020 17:12:11 +0000</pubDate>
      <link>https://dev.to/kaleman15/fuzzy-searching-with-postgresql-97o</link>
      <guid>https://dev.to/kaleman15/fuzzy-searching-with-postgresql-97o</guid>
      <description>&lt;h1&gt;
  
  
  What's fuzzy search?
&lt;/h1&gt;

&lt;p&gt;A fuzzy search is a type of search where the items are returned even when they are not an exact match. A fuzzy search is performed by a &lt;code&gt;fuzzy&lt;/code&gt; algorithm that evaluates the likeliness between the search query and the values, even when the search query is misspelled or the order of the words changed.&lt;/p&gt;

&lt;p&gt;For example, let's assume that we're using Google to find information about &lt;code&gt;washin machines&lt;/code&gt;. As you can see, the word &lt;code&gt;washing&lt;/code&gt; is misspelled. But even when Google knows that it'll return results that are somewhat similar to what you typed. Sometimes it even tries to correct you!&lt;/p&gt;

&lt;p&gt;Well, that's a &lt;code&gt;fuzzy search&lt;/code&gt;. Returning elements that are just &lt;code&gt;similar&lt;/code&gt; one to another. &lt;/p&gt;

&lt;h1&gt;
  
  
  How's searching occasionally implemented?
&lt;/h1&gt;

&lt;p&gt;Let's take a typical requirement: allow a user to search other users by its name. To accomplish that, you may end up building a query like this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;full_name&lt;/span&gt; &lt;span class="k"&gt;ilike&lt;/span&gt; &lt;span class="s1"&gt;'%query_param%'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assuming you have a user named &lt;code&gt;Jonh Doe&lt;/code&gt; in your database, looking for &lt;code&gt;Jonh&lt;/code&gt;, &lt;code&gt;JonH&lt;/code&gt;, &lt;code&gt;jOnh&lt;/code&gt;, &lt;code&gt;jonh doe&lt;/code&gt;, &lt;code&gt;Jonh Doe&lt;/code&gt; and so on will return the value you're looking for. But, what if the user types &lt;code&gt;Doe Jonh&lt;/code&gt;? &lt;/p&gt;

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

&lt;p&gt;Well, for sure your app won't crash with that input. But I'm pretty sure it won't return anything! Why? Because the order of the words is different than what's stored on the database, and &lt;code&gt;ilike&lt;/code&gt; won't do that rearrange of the words to match. One way to overcome this is to query also for the words in a different order, but that's not elegant.&lt;/p&gt;

&lt;p&gt;Apart from that, what happens if now the user (yes, always the user, ugh) types &lt;code&gt;john doe&lt;/code&gt;? There are some ways to handle this with &lt;code&gt;ilikes&lt;/code&gt; but, why doing that amount of work when you can let PostgreSQL do that for you?&lt;/p&gt;

&lt;p&gt;Let's introduce &lt;code&gt;pg_trgm&lt;/code&gt;. A PostgreSQL extension based on something called a &lt;code&gt;trigram&lt;/code&gt; that will be very useful for this! But, first of all, what's a &lt;code&gt;trigram&lt;/code&gt;?&lt;/p&gt;

&lt;h1&gt;
  
  
  PostgreSQL trigrams. What are they?
&lt;/h1&gt;

&lt;p&gt;The basic definition of trigram is: &lt;em&gt;"A group of 3 consecutive written units, such as words, letters, etc"&lt;/em&gt;. The &lt;code&gt;pg_trgm&lt;/code&gt; extension allows us to divide a word in such.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does a trigram look like?
&lt;/h2&gt;

&lt;p&gt;To see how a trigram look like, let's enable the PostgreSQL extension first!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;pg_trgm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;show_trgm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'abcdefghijk'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                        &lt;span class="n"&gt;show_trgm&lt;/span&gt;                        
&lt;span class="c1"&gt;---------------------------------------------------------&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;"  a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;" ab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;abc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;bcd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;cde&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;efg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;fgh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;ghi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;hij&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;ijk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;"jk "&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;As you see, it'll divide the word into groups of 3 characters. Why there are spaces in the first and last trigrams? Well, that's because PostgreSQL assumes that every word to be converted into a trigram has 2 spaces before and one space after. Why? This allows PostgreSQL to create trigrams for words with less than 3 characters (&lt;code&gt;we&lt;/code&gt;, for example). Also, this makes the similarity to take into account the first and last characters, which otherwise would have less weight when the trigrams are generated.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use them to find similar words?
&lt;/h2&gt;

&lt;p&gt;If we select the trigrams for 2 words, we should be able to find how similar those strings are. How? By counting the number of trigrams they share!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;show_trgm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Friend'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
              &lt;span class="n"&gt;show_trgm&lt;/span&gt;              
&lt;span class="c1"&gt;-------------------------------------&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;"  f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;" fr"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;fri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;ien&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;"nd "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;rie&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;show_trgm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Friendship'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                      &lt;span class="n"&gt;show_trgm&lt;/span&gt;                      
&lt;span class="c1"&gt;-----------------------------------------------------&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;"  f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;" fr"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;dsh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;fri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;hip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;ien&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;"ip "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;nds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;rie&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;shi&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How we find those similar trigrams between the 2 sets? Correct, an intersection!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;                                                 
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;unnest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;show_trgm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'friends'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;intersect&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;unnest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;show_trgm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'friendship'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;as&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;as&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;a&lt;/span&gt;  
&lt;span class="c1"&gt;-----&lt;/span&gt;
 &lt;span class="n"&gt;rie&lt;/span&gt;
 &lt;span class="n"&gt;fri&lt;/span&gt;
  &lt;span class="n"&gt;fr&lt;/span&gt;
   &lt;span class="n"&gt;f&lt;/span&gt;
 &lt;span class="k"&gt;end&lt;/span&gt;
 &lt;span class="n"&gt;ien&lt;/span&gt;
 &lt;span class="n"&gt;nds&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, there are 7 trigrams common between the 2 sets. Now, how do we know how similar they are? We can do that by calculating a similarity coefficient between the 2 words. How?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;word_similarity = common_trigrams / first_word_total_trigrams
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why we use the first word? Well, because we're comparing the first against the second word. We don't care about the excedent trigrams from the second word because we know they won't correlate to the first one.&lt;/p&gt;

&lt;p&gt;Now, let's apply the formula. We have &lt;code&gt;7.00&lt;/code&gt; common trigrams, and we have &lt;code&gt;8.00&lt;/code&gt; total trigrams in the first word. Let's use PostgreSQL to determine the coefficient:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;        
&lt;span class="c1"&gt;------------------------&lt;/span&gt;
 &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;87500000000000000000&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Here, we use decimals because otherwise, PostgreSQL will ignore the decimal part of the operation, thus returning us 0.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now, we know that our words have a similarity of &lt;code&gt;0.875&lt;/code&gt;. That means they are very similar! But, having to do all of this manually may take time... there should be a better way. &lt;/p&gt;

&lt;p&gt;Well, there's a better way! Alongside the trigram extension, we enabled a set of functions that came in the same packages. For example, the whole process we've done for calculating the similarity is abstracted away into a single function: &lt;code&gt;word_similarity&lt;/code&gt;. By using the function, we can get all of this process into a single line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;word_similarity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'friends'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'friendship'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="n"&gt;word_similarity&lt;/span&gt; 
&lt;span class="c1"&gt;-----------------&lt;/span&gt;
           &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;875&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And even better, there's a set of &lt;a href="https://www.postgresql.org/docs/9.6/pgtrgm.html" rel="noopener noreferrer"&gt;useful operators&lt;/a&gt; that are built into the same package we're using! For example, we may let PostgreSQL decide if two words are similar or not by using the &lt;code&gt;&amp;lt;%&lt;/code&gt; operator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="s1"&gt;'friends'&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="s1"&gt;'friendship'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; 
&lt;span class="c1"&gt;----------&lt;/span&gt;
 &lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That operator returns if 2 words are similar or not by using a &lt;code&gt;word_similarity_threshold&lt;/code&gt;, which we can query too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;show_limit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="n"&gt;show_limit&lt;/span&gt; 
&lt;span class="c1"&gt;------------&lt;/span&gt;
        &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note that &lt;code&gt;show_limit()&lt;/code&gt; function is deprecated, but still works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That limit is, the minimum coefficient a pair of words can have before marking them as different. You can modify that threshold using the &lt;code&gt;set_limit()&lt;/code&gt; function and provide new value, but for most use cases, the default one should work!&lt;/p&gt;

&lt;p&gt;Using trigrams, we can also query for the "distance" between 2 words, which is calculated by taking the &lt;code&gt;similarity&lt;/code&gt; of the words from &lt;code&gt;1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;distance = 1 - similarity(word_1, word_2);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the &lt;code&gt;&amp;lt;-&amp;gt;&lt;/code&gt; operator. The lower the number the more similar (or less distance) they have.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="s1"&gt;'friends'&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'friendship'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; 
&lt;span class="c1"&gt;----------&lt;/span&gt;
 &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;416667&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use this operator to build something like Google's &lt;code&gt;did you mean&lt;/code&gt; functionality, which is probably done with n-grams.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building a &lt;code&gt;Did you mean&lt;/code&gt; engine
&lt;/h3&gt;

&lt;p&gt;First, let's create a table and populate it with data. For this example, I'll be using the departments of my country, El Salvador.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;t_departments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now, some data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;t_departments&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="k"&gt;values&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'San Salvador'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Chalatenango'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Ahuachapan'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Cabanas'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Sonsonate'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'La Libertad'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Santa Ana'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'La Union'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Cuscatlan'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'San Vicente'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'La Paz'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Usulutan'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Morazan'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'San Miguel'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;t_departments&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="n"&gt;name&lt;/span&gt;     
&lt;span class="c1"&gt;--------------&lt;/span&gt;
 &lt;span class="n"&gt;San&lt;/span&gt; &lt;span class="n"&gt;Salvador&lt;/span&gt;
 &lt;span class="n"&gt;Chalatenango&lt;/span&gt;
 &lt;span class="n"&gt;Ahuachapan&lt;/span&gt;
 &lt;span class="n"&gt;Cabanas&lt;/span&gt;
 &lt;span class="n"&gt;Sonsonate&lt;/span&gt;
 &lt;span class="n"&gt;La&lt;/span&gt; &lt;span class="n"&gt;Libertad&lt;/span&gt;
 &lt;span class="n"&gt;Santa&lt;/span&gt; &lt;span class="n"&gt;Ana&lt;/span&gt;
 &lt;span class="n"&gt;La&lt;/span&gt; &lt;span class="k"&gt;Union&lt;/span&gt;
 &lt;span class="n"&gt;Cuscatlan&lt;/span&gt;
 &lt;span class="n"&gt;San&lt;/span&gt; &lt;span class="n"&gt;Vicente&lt;/span&gt;
 &lt;span class="n"&gt;La&lt;/span&gt; &lt;span class="n"&gt;Paz&lt;/span&gt;
 &lt;span class="n"&gt;Usulutan&lt;/span&gt;
 &lt;span class="n"&gt;Morazan&lt;/span&gt;
 &lt;span class="n"&gt;San&lt;/span&gt; &lt;span class="n"&gt;Miguel&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt; &lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, what happens if the user is looking for &lt;code&gt;San Salvador&lt;/code&gt; but it misspells it and write &lt;code&gt;sn salvador&lt;/code&gt;? Our system should recommend the user to write it properly! How? Let's see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;t_departments&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="s1"&gt;'sn salvador'&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;limit&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="n"&gt;name&lt;/span&gt;     
&lt;span class="c1"&gt;--------------&lt;/span&gt;
 &lt;span class="n"&gt;San&lt;/span&gt; &lt;span class="n"&gt;Salvador&lt;/span&gt;
 &lt;span class="n"&gt;Santa&lt;/span&gt; &lt;span class="n"&gt;Ana&lt;/span&gt;
 &lt;span class="n"&gt;San&lt;/span&gt; &lt;span class="n"&gt;Miguel&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;And 🎉. By returning the first result, we can tell the user that we know what he was trying to write, and still, return results related to its search, as Google does!&lt;/p&gt;

&lt;h3&gt;
  
  
  Solving our initial problem
&lt;/h3&gt;

&lt;p&gt;Well, our initial problem was the user, right? Jk, our initial problem was to handle misspellings when users type a name, but they still want a result. &lt;br&gt;
It's now trivial to do this with our new knowledge, by querying either the &lt;code&gt;word similarity&lt;/code&gt; or the &lt;code&gt;distance&lt;/code&gt; between the words.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;unnest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'jonh doe'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'jane doe'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'mark twain'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'some user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'a person'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'tommy shelby'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;names&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="s1"&gt;'doe jonh'&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;names&lt;/span&gt; &lt;span class="k"&gt;limit&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;names&lt;/span&gt;    
&lt;span class="c1"&gt;------------&lt;/span&gt;
 &lt;span class="n"&gt;jonh&lt;/span&gt; &lt;span class="n"&gt;doe&lt;/span&gt;
 &lt;span class="n"&gt;jane&lt;/span&gt; &lt;span class="n"&gt;doe&lt;/span&gt;
 &lt;span class="n"&gt;mark&lt;/span&gt; &lt;span class="n"&gt;twain&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="k"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Ignore Mark Twain...&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I hope you liked the article, and if you are curious and want to delve more, you can read the &lt;a href="https://www.postgresql.org/docs/9.6/pgtrgm.html" rel="noopener noreferrer"&gt;whole documentation&lt;/a&gt; for trigrams and all the operators you can. In my next blog post, I'll share how to index this kind of data so the queries are faster!&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>database</category>
      <category>sql</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
