<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: LinceMathew</title>
    <description>The latest articles on Forem by LinceMathew (@lincemathew).</description>
    <link>https://forem.com/lincemathew</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1138237%2F84b2cb1c-8fe3-4f02-bbea-4edd8de7c7b7.jpeg</url>
      <title>Forem: LinceMathew</title>
      <link>https://forem.com/lincemathew</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/lincemathew"/>
    <language>en</language>
    <item>
      <title>Searching Billions in Seconds: How HNSW Solved the Scale Problem</title>
      <dc:creator>LinceMathew</dc:creator>
      <pubDate>Mon, 27 Apr 2026 08:10:56 +0000</pubDate>
      <link>https://forem.com/lincemathew/searching-billions-in-seconds-how-hnsw-solved-the-scale-problem-b64</link>
      <guid>https://forem.com/lincemathew/searching-billions-in-seconds-how-hnsw-solved-the-scale-problem-b64</guid>
      <description>&lt;p&gt;We have a massive problem with how computers find things. If you have a few hundred photos on your phone, you can find one instantly, but trying to find one specific item out of a billion creates a massive technical strain. &lt;/p&gt;

&lt;p&gt;Most systems rely on "&lt;a href="https://en.wikipedia.org/wiki/Linear_search" rel="noopener noreferrer"&gt;Linear Search&lt;/a&gt;", which is like looking through every single page of a ten-million-page book to find one word. &lt;/p&gt;

&lt;p&gt;This "one-by-one" approach makes real-time tools like chatbots or movie recommendations grind to a halt as the data grows. Furthermore, modern data like images or text is "high-dimensional," which breaks traditional filing systems and makes them no faster than checking every item manually.&lt;/p&gt;

&lt;p&gt;To fix this, researchers Yu. A. Malkov and D. A. Yashunin changed the rules of the game. They realized that we don't always need a "perfect" match if it takes an hour to find; we often just need a "good enough" match found in a millisecond. &lt;/p&gt;

&lt;p&gt;In this article, we are diving into their research paper: "&lt;a href="https://arxiv.org/pdf/1603.09320" rel="noopener noreferrer"&gt;Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs.&lt;/a&gt;" &lt;/p&gt;

&lt;p&gt;We will explore how they used a multi-layered "highway system" to make searching a billion items feel as fast as searching a hundred.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Methods for Fast Searching
&lt;/h2&gt;

&lt;p&gt;To solve the slowness problem, the researchers combined two concepts from computer science. The first is the "Small World" phenomenon. &lt;/p&gt;

&lt;p&gt;You’ve likely heard of "&lt;a href="https://en.wikipedia.org/wiki/Six_degrees_of_separation" rel="noopener noreferrer"&gt;six degrees of separation"&lt;/a&gt;, the idea that you are connected to anyone on Earth through a short chain of acquaintances. &lt;/p&gt;

&lt;p&gt;HNSW treats data the same way. It builds a map where every data point is a "node," and similar points are connected like friends. By jumping from "friend to friend" toward your target, you can navigate a massive dataset in just a few steps.&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%2F64clswedr85x18nw3hw6.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%2F64clswedr85x18nw3hw6.png" alt="six-degrees-of-separation" width="500" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second concept is Hierachy, which is inspired by a structure called a &lt;a href="https://en.wikipedia.org/wiki/Skip_list" rel="noopener noreferrer"&gt;Skip List&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Imagine a high-rise building where the elevators only stop at every 10th floor. To get to floor 42, you take the express elevator to floor 40 and then walk down to 42. HNSW creates "express layers" at the top with only a few data points and long-range connections. &lt;/p&gt;

&lt;p&gt;These top layers allow the search to "skip" across the entire database to the right neighborhood instantly, before dropping down to the ground floor to find the exact 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%2Fuploads%2Farticles%2Fof891215etd7iqf9226w.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%2Fof891215etd7iqf9226w.png" alt="skip-list" width="500" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Multi-Layer Highway System
&lt;/h2&gt;

&lt;p&gt;To bridge the gap between speed and accuracy, the researchers introduced a multi-layer structure called a &lt;strong&gt;Hierarchical Navigable Small World (HNSW)&lt;/strong&gt; graph. &lt;/p&gt;

&lt;p&gt;You can think of this as a "highway system" for data. Instead of one giant, flat network where everything is connected, HNSW organizes data into layers.&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%2F3o6urkbeolnm361cfuvz.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%2F3o6urkbeolnm361cfuvz.png" alt="hnsw" width="282" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Top Layers (Express Lanes)
&lt;/h3&gt;

&lt;p&gt;These layers contain only a few data points with long-distance connections. Much like an express highway between major cities, they allow the search to "skip" across the entire dataset to reach the right neighborhood in just a few jumps.&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%2F005ew1o82gz2dernz0ov.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%2F005ew1o82gz2dernz0ov.png" alt="express-highway" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Bottom Layers (Local Streets)
&lt;/h3&gt;

&lt;p&gt;As the search moves down through the hierarchy, the layers become denser with shorter connections. Once the search reaches the ground layer—which contains every single piece of data—it uses these "local streets" to fine-tune the results and find the exact match.&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%2Fd3ny07jzj5ml5cry7emm.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%2Fd3ny07jzj5ml5cry7emm.png" alt="local-streets" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This hierarchy is inspired by a data structure called a &lt;a href="https://en.wikipedia.org/wiki/Skip_list" rel="noopener noreferrer"&gt;Skip List&lt;/a&gt;, but instead of simple linked lists, it uses complex proximity graphs. &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%2Fetxmb327cglhyvi1mg9s.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%2Fetxmb327cglhyvi1mg9s.png" alt="proximity-graph" width="395" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By separating links by their "distance scales," the algorithm ensures that the search time scales logarithmically. This means that even if the dataset grows from thousands to billions, the number of steps required to find an answer stays manageable and fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Balancing Speed and Accuracy
&lt;/h2&gt;

&lt;p&gt;To make this system work, there are a few settings that determine how the graph is built and searched.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Connections per point (M)&lt;/strong&gt;: This is the number of "links" each piece of data creates with its neighbors. If you give each point more connections, the map becomes more detailed and accurate, but it also takes up more memory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Build Effort (efConstruction)&lt;/strong&gt;: This determines how much work the system does when first creating the index. A higher setting means the "highways" and "local streets" are better connected, making future searches much more reliable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Search Depth (ef)&lt;/strong&gt;: This is a setting you use during the actual search. It tells the computer how many neighbors to check before it decides it has found the best match. You can turn this up at any time to get better results without having to rebuild your entire database.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building an HNSW Index
&lt;/h2&gt;

&lt;p&gt;To see how this works, we can use a popular Python library called &lt;code&gt;hnswlib&lt;/code&gt;. This is the same code used in the original research to prove how fast the system is. The following example shows how to set up a database and perform a search in just a few lines.&lt;/p&gt;

&lt;h3&gt;
  
  
  Import the Tools
&lt;/h3&gt;

&lt;p&gt;We start by importing &lt;code&gt;hnswlib&lt;/code&gt; to build the graph and numpy to handle the coordinates of our "meaning map."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hnswlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create the "Meaning Map"
&lt;/h3&gt;

&lt;p&gt;Let's give our items coordinates based on two features: Sweetness and Size. Fruits will have high sweetness and low size, while furniture will have low sweetness and high size.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;data_labels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Apple&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Banana&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cherry&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Chair&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Table&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sofa&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;data_vectors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;# Apple 
&lt;/span&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;# Banana
&lt;/span&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;# Cherry
&lt;/span&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;# Chair
&lt;/span&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;# Table
&lt;/span&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Sofa 
&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;dim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# Only 2 features: Sweetness and Size
&lt;/span&gt;&lt;span class="n"&gt;num_elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_vectors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The data now looks like a list of coordinates. For example, Apple is at [0.9, 0.2].&lt;/p&gt;

&lt;h3&gt;
  
  
  Choose the Measuring Tape
&lt;/h3&gt;

&lt;p&gt;We initialize the index. We use 'l2' (Euclidean distance) to measure similarity. On our map, this is just a straight line between two points; the shorter the line, the more similar the items are.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hnswlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;space&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;l2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Build the Highway System
&lt;/h3&gt;

&lt;p&gt;We set the rules for the HNSW structure. M sets the number of connections for each point, and ef_construction tells the system how hard to work to find the best neighbors when first building the "highways."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_elements&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;num_elements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ef_construction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Index the Data
&lt;/h3&gt;

&lt;p&gt;This step takes our fruits and furniture and organizes them into layers. The "High-Sweetness" items (fruits) will naturally end up in one neighborhood, while the furniture ends up in another.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_vectors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Perform the Search
&lt;/h3&gt;

&lt;p&gt;Now we search for an "Orange". We haven't told the system what an orange is, but we give it the coordinates &lt;a href="https://dev.toHigh%20sweetness,%20small%20size"&gt;0.85, 0.25&lt;/a&gt;. We tell the system to find the 3 closest neighbors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;query_vector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;([[&lt;/span&gt;&lt;span class="mf"&gt;0.85&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_ef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;distances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;knn_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_vector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The system returns the IDs for Apple, Banana, and Cherry. Even though "Orange" wasn't in our database, HNSW used the highway system to skip past the "Furniture" neighborhood and find the items that lived in the same "Sweet and Small" neighborhood.&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%2F4yhun8ovrrqit95fuhqu.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%2F4yhun8ovrrqit95fuhqu.png" alt="hnsw-graph" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;here is the layered flow diagram.&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%2Fzhphbmai0k9w3ol055zn.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%2Fzhphbmai0k9w3ol055zn.png" alt="hnsw-layered-flow" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this diagram you can see there are three layers in the graph. The top layer has only a few nodes and the bottom layer has all the nodes. The search starts from the top layer and moves down to the bottom layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Realworld Applications of HNSW
&lt;/h2&gt;

&lt;p&gt;The reason this research paper is so influential is that it solved the "scale" problem for some of the most popular technology today. Because HNSW can find a "neighborhood" of similar ideas in milliseconds, it is used in:&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Chatbots &amp;amp; RAG
&lt;/h3&gt;

&lt;p&gt;When you ask an AI a question, it uses HNSW to search through millions of documents to find the specific paragraphs that contain the answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recommendation Engines
&lt;/h3&gt;

&lt;p&gt;Apps like Spotify or Netflix use this logic to find songs or movies that are "mathematically close" to what you just finished watching.&lt;/p&gt;

&lt;h3&gt;
  
  
  Image Search
&lt;/h3&gt;

&lt;p&gt;Tools like Google Lens compare the "fingerprint" of your photo against billions of others to find a match instantly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fraud Detection
&lt;/h3&gt;

&lt;p&gt;Banks use it to see if a new transaction looks "similar" to known patterns of theft or if it fits your normal "neighborhood" of spending.&lt;/p&gt;

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

&lt;p&gt;Before this paper, we had a difficult choice: we could have a search that was perfectly accurate but incredibly slow, or a search that was fast but broke down as it grew.&lt;/p&gt;

&lt;p&gt;Malkov and Yashunin’s HNSW changed that by introducing the "highway" system for data. By accepting a tiny bit of approximation, they gave us a way to search through billions of items in the blink of an eye.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>programming</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Automate the Boring Stuff! Check Out This Open-Source Tool</title>
      <dc:creator>LinceMathew</dc:creator>
      <pubDate>Sun, 13 Jul 2025 16:09:50 +0000</pubDate>
      <link>https://forem.com/lincemathew/automate-the-boring-stuff-check-out-this-open-source-tool-5efk</link>
      <guid>https://forem.com/lincemathew/automate-the-boring-stuff-check-out-this-open-source-tool-5efk</guid>
      <description>&lt;p&gt;If you’re tired of doing the same tasks over and over—copying data between apps, checking emails, or updating spreadsheets—there’s a better way. Meet n8n, a tool that helps you automate those repetitive jobs without needing to be a programmer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/n8n-io/n8n" rel="noopener noreferrer"&gt;n8n stands for Node Automation&lt;/a&gt;. It’s an open-source platform that lets you connect different apps, move data between them, and build powerful automations.&lt;/p&gt;

&lt;p&gt;You can think of it like Zapier, but with more flexibility. Plus, you can host it yourself, which means more control and no monthly fees.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set It Up, No Sweat
&lt;/h2&gt;

&lt;p&gt;Getting started with n8n is simple, and there are a few different ways to run it depending on your preference. Whether you're just trying it out or setting it up for daily use, here are your options:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 1: Run n8n with Docker&lt;/strong&gt;&lt;br&gt;
If you have Docker installed, this is one of the easiest and cleanest ways to run n8n. Open your terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 5678:5678 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; ~/.n8n:/home/node/.n8n &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;N8N_BASIC_AUTH_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;user &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;N8N_BASIC_AUTH_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pass &lt;span class="se"&gt;\&lt;/span&gt;
  n8nio/n8n

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

&lt;/div&gt;



&lt;p&gt;This will start n8n on port 5678 with basic username and password protection. Your workflows will be saved in your local .n8n folder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 2: Use npx to Try n8n Instantly&lt;/strong&gt;&lt;br&gt;
If you have Node.js, you can launch it using just one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx n8n
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it—no setup, no extra install. It’s great for quick testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build Your First Workflow
&lt;/h2&gt;

&lt;p&gt;In this example, we’ll create an automation that fetches the &lt;a href="https://github.com/trending" rel="noopener noreferrer"&gt;daily trending&lt;/a&gt; Go (Golang) repositories on GitHub and adds them to a Google Sheets spreadsheet. This shows how n8n can help you collect and organize information automatically.&lt;/p&gt;

&lt;p&gt;In n8n, a &lt;strong&gt;workflow&lt;/strong&gt; is a series of connected tasks that run automatically, and each task is called a &lt;strong&gt;node&lt;/strong&gt;. Nodes perform specific actions like getting data, processing it, or saving results.&lt;/p&gt;

&lt;p&gt;Here’s a quick look at the workflow we’ll build:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cron Node:&lt;/strong&gt; This triggers the workflow to run once every day (or whenever you want).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTTP Request Node&lt;/strong&gt;: It fetches the trending repositories page from GitHub for the Go language.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTML Extract Node:&lt;/strong&gt; This node reads the web page and pulls out the repository names and descriptions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Function Node:&lt;/strong&gt; It organizes the data into a clean format with title, description, and URL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google Sheets Node:&lt;/strong&gt; Finally, this node adds the data into a Google Sheets spreadsheet.&lt;/p&gt;

&lt;p&gt;Next, we’ll walk through each step so you can build this workflow yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before building the workflow, make sure you have a Google Sheet ready. The first row (header) of the sheet should have these three columns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Title | Description | URL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You also need to authorize Google Sheets in n8n. To do this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Go to Credentials → Google Sheets OAuth2 in n8n.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a Google Cloud project and set up an OAuth Client ID.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add these credentials to the Google Sheets node in your workflow.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;h3&gt;
  
  
  1. Cron Node — Trigger Your Workflow
&lt;/h3&gt;

&lt;p&gt;The Cron node triggers your workflow based on time. You can set it to run daily, hourly, or whenever you want. For this example, set it to run once a day.&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%2F5t55vidy0vxo965jo3q2.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%2F5t55vidy0vxo965jo3q2.png" alt=" " width="800" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. HTTP Request Node — Fetch GitHub Trending Repos
&lt;/h3&gt;

&lt;p&gt;This node sends a GET request to GitHub’s trending page for Go repositories. The URL is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;https://github.com/trending/go?since&lt;span class="o"&gt;=&lt;/span&gt;daily
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can replace go with any language you want to track. The response will be the page’s HTML in text format.&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%2Fkc80vzdgoac5p4dk6dm9.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%2Fkc80vzdgoac5p4dk6dm9.png" alt=" " width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. HTML Extract Node — Get Repo Names and Descriptions
&lt;/h3&gt;

&lt;p&gt;The HTML Extract node reads the page’s HTML and extracts the repository names and descriptions using CSS selectors.&lt;/p&gt;

&lt;p&gt;For repo names:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="nc"&gt;.Box-row&lt;/span&gt; &lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="nt"&gt;a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For descriptions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="nc"&gt;.Box-row&lt;/span&gt; &lt;span class="nt"&gt;p&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The node uses the HTML body from the HTTP Request node as input.&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%2Ffi69jg7su6gg80j1u8tf.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%2Ffi69jg7su6gg80j1u8tf.png" alt=" " width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Function Node — Format Data for Google Sheets
&lt;/h3&gt;

&lt;p&gt;This node takes the extracted data and cleans it up. It trims extra spaces and creates a neat JSON object with three fields: Title, Description, and URL. The URL is built by adding &lt;a href="https://github.com" rel="noopener noreferrer"&gt;https://github.com&lt;/a&gt; in front of the repo name.&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%2F4lxd0mx8msk2zy0g7tji.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%2F4lxd0mx8msk2zy0g7tji.png" alt=" " width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Google Sheets Node — Save Data to Your Sheet
&lt;/h3&gt;

&lt;p&gt;Finally, this node adds the formatted data to your Google Sheet. Use the Append operation and specify your sheet’s ID and the range (for example, Sheet1!A:C). Map the fields Title, Description, and URL to the corresponding columns in your sheet.&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%2Fzoo3dmtwwnoxj6icfga9.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%2Fzoo3dmtwwnoxj6icfga9.png" alt=" " width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is how our final workflow looks.&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%2F6a6wenc95enj7dy511c4.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%2F6a6wenc95enj7dy511c4.png" alt=" " width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s trigger the workflow manually.&lt;br&gt;
Boom! All the trending Go repositories from GitHub are added to our Google Sheet!&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%2Fd21i2l23oworqkrcpwd3.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%2Fd21i2l23oworqkrcpwd3.png" alt=" " width="800" height="491"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Else Can You Automate with n8n?
&lt;/h2&gt;

&lt;p&gt;n8n is very flexible and can help automate many everyday tasks. Here are some common ways people use it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notifications&lt;/strong&gt;&lt;br&gt;
For example, when a new order comes in, n8n can automatically send a message to your team on Slack and send an email alert. This keeps everyone updated without manual effort.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reporting&lt;/strong&gt;&lt;br&gt;
You can gather important data or metrics every week, create a report, and have n8n email it to your team before meetings. This saves time and ensures everyone has the latest information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Web Scraping&lt;/strong&gt;&lt;br&gt;
Want to track competitor prices? n8n can scrape product prices from websites and log the data into a Google Sheet for easy comparison.&lt;/p&gt;

&lt;p&gt;These examples show just a few of the many ways n8n can simplify your work by automating repetitive tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line: Is n8n for You?
&lt;/h2&gt;

&lt;p&gt;If you find yourself doing the same tasks over and over—copying data, sending emails, checking updates—n8n can save you a lot of time. It’s powerful, flexible, and doesn’t require you to be a developer.&lt;/p&gt;

&lt;p&gt;Whether you're automating small personal tasks or building complex workflows for your team, n8n makes it easier. And the best part? You’re in full control, especially if you choose to self-host it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PRO TIP: Struggling to locate API endpoints across your codebase?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hexmos.com/landing/liveapi" rel="noopener noreferrer"&gt;LiveAPI&lt;/a&gt; lets you instantly find and explore every endpoint across all your repositories — give it a try and see how much easier navigation can be!&lt;/p&gt;

</description>
      <category>automation</category>
      <category>opensource</category>
      <category>n8n</category>
    </item>
    <item>
      <title>Getting the Best Out of GitHub Copilot</title>
      <dc:creator>LinceMathew</dc:creator>
      <pubDate>Sun, 01 Jun 2025 16:20:14 +0000</pubDate>
      <link>https://forem.com/lincemathew/getting-the-best-out-of-github-copilot-ejc</link>
      <guid>https://forem.com/lincemathew/getting-the-best-out-of-github-copilot-ejc</guid>
      <description>&lt;p&gt;As my first in-editor AI coding partner, I started with &lt;a href="https://www.cursor.com/" rel="noopener noreferrer"&gt;Cursor&lt;/a&gt;. However, four months ago, I decided to switch to &lt;a href="https://github.com/features/copilot" rel="noopener noreferrer"&gt;GitHub Copilot&lt;/a&gt;. While using Cursor, I was aware of Copilot and its features, but at the time, it felt unstable and not as polished as Cursor. Recently, I noticed that GitHub Copilot has been improving significantly, becoming a strong competitor to Cursor. This encouraged me to give Copilot a try, especially since it offers a larger quota for expensive LLM calls and has proven to be stable even in its preview version.&lt;/p&gt;

&lt;p&gt;Another reason for the switch was my existing GitHub Pro subscription, which meant I could save $22 per month by not needing Cursor’s subscription if Copilot proved to be a good alternative.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore some of unique Copilot’s features i found and best practices we can use to make the best out of copilot.&lt;br&gt;
FYI:My primary focus is on Github copilot extension on &lt;a href="https://visualstudio.microsoft.com/github-copilot/" rel="noopener noreferrer"&gt;VScode insider&lt;/a&gt;, even you can access copilot from web version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Personalizing GitHub Copilot Responses
&lt;/h2&gt;

&lt;p&gt;GitHub Copilot allows you to customize its responses to better suit your needs.Its difficult and irritating to mention stick to functional programming, use early return etc in every chat completion. These custom instructions help Copilot understand your preferences, project requirements, or even organization-wide standards. There are three types of custom instructions you can use:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Personal Custom Instructions&lt;/strong&gt;: Copilot’s responses to your individual preferences across all conversations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository Custom Instructions&lt;/strong&gt;: Define project-specific guidelines, frameworks, or coding standards for a particular repository.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Organization Custom Instructions&lt;/strong&gt;: Apply organization-wide preferences, managed by organization owners, to ensure consistency across all repositories.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s start with personal custom instructions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Personal Custom Instructions
&lt;/h3&gt;

&lt;p&gt;Personal custom instructions let you customize how GitHub Copilot responds to you, making it more aligned with your preferences. Setting them up is straightforward and can be done either in the Copilot Chat panel or immersive mode.&lt;/p&gt;

&lt;h4&gt;
  
  
  How to Add Personal Instructions
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Open the Copilot Chat panel or immersive mode:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Click the Copilot Chat icon in the top-right corner of any GitHub page to open the panel.&lt;/li&gt;
&lt;li&gt;If you prefer a full-page view, click the dropdown next to the Copilot Chat icon and select "Immersive." You can also go directly to &lt;a href="https://github.com/copilot" rel="noopener noreferrer"&gt;https://github.com/copilot&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Access Personal Instructions:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;In the Chat panel or immersive page, click the dropdown menu at the top-right corner and select "Personal instructions."&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Add Your Preferences:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Write your preferences in the text box using natural language. You can format them however you like—either as a single block of text, line by line, or separated by blank lines.&lt;/li&gt;
&lt;li&gt;If you’re unsure where to start, click the templates button to see examples of common instructions. For instance, selecting "Communication" will add placeholders like &lt;code&gt;{format}&lt;/code&gt; that you can customize.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Save Your Instructions:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Click "Save" to activate your instructions. They’ll stay active until you decide to change or remove them.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Example
&lt;/h4&gt;

&lt;p&gt;Let’s say you want Copilot to respond in Portuguese and keep explanations short and simple. Here’s how you can set it up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the Copilot Chat panel.&lt;/li&gt;
&lt;li&gt;In the "Personal instructions" section, add the following:
Always respond in Portuguese. Keep explanations concise and break them down step by step.&lt;/li&gt;
&lt;li&gt;Save your instructions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, whenever you interact with Copilot, it will respond in Portuguese and provide clear, concise explanations tailored to your preferences.&lt;/p&gt;

&lt;p&gt;continue reading the &lt;a href="https://journal.hexmos.com/getting-the-best-out-of-github-copilot/" rel="noopener noreferrer"&gt;full article here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Data Races in Go: What They Are and Why You Should Care</title>
      <dc:creator>LinceMathew</dc:creator>
      <pubDate>Sun, 13 Apr 2025 16:04:16 +0000</pubDate>
      <link>https://forem.com/lincemathew/data-races-in-go-what-they-are-and-why-you-should-care-14fa</link>
      <guid>https://forem.com/lincemathew/data-races-in-go-what-they-are-and-why-you-should-care-14fa</guid>
      <description>&lt;p&gt;A data race happens when two or more goroutines access the same memory location at the same time, and at least one of them writes to it — without proper synchronization.&lt;/p&gt;

&lt;p&gt;This can lead to unpredictable behavior. Your program might sometimes work just fine, and other times crash or return wrong results. That’s because the order in which goroutines run isn’t guaranteed, so without coordination, one goroutine might read a value while another is in the middle of changing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Are Data Races a Problem?
&lt;/h2&gt;

&lt;p&gt;Data races aren’t just theoretical—they can cause real, unpredictable problems that are difficult to catch and fix. Here’s a simple example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;race&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="c"&gt;// read, increment, write&lt;/span&gt;
        &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="c"&gt;// conflicting access&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, both the main goroutine and the anonymous goroutine are updating the same variable &lt;code&gt;n&lt;/code&gt;. Since there’s no coordination between them—no locks, no channels protecting the access—we don’t know which &lt;code&gt;n++&lt;/code&gt; happens first. The output might be 1, 2, or something even weirder depending on how the Go runtime schedules the goroutines.&lt;/p&gt;

&lt;p&gt;This is the essence of a data race: multiple goroutines accessing shared memory without synchronization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So what’s the big deal?&lt;/strong&gt;&lt;br&gt;
The biggest problem with data races is that they don’t fail consistently. Your code might run fine 100 times and crash on the 101st. That makes them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Hard to reproduce&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hard to debug&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Easy to miss in tests&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the impact can be serious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You might get incorrect results or corrupted state&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Goroutines might get stuck in deadlocks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your program might even crash if memory is accessed in unsafe ways&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your app  "sometimes fails for no reason," a data race could be the hidden culprit.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to Spot Data Races
&lt;/h2&gt;

&lt;p&gt;The good news? Go makes it easy to spot data races using a built-in tool: the &lt;a href="https://go.dev/doc/articles/race_detector" rel="noopener noreferrer"&gt;race detector&lt;/a&gt;.&lt;br&gt;
Let's try it out with our example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;
    &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="c"&gt;// race condition&lt;/span&gt;
            &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter&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;Each goroutine tries to increment counter. But since there's no synchronization—no mutex, no channel—they can interfere with each other. The result is unpredictable, and chances are the final output won’t be 10.&lt;/p&gt;

&lt;p&gt;To catch this, run the program with Go’s race detector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run &lt;span class="nt"&gt;-race&lt;/span&gt; main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The -race flag enables Go’s runtime race detector. If there’s a data race, you’ll see a warning 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%2Fh780elxiph8876qjy4s0.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%2Fh780elxiph8876qjy4s0.png" alt="Iription" width="711" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This output shows exactly where the race occurred, what variable was involved, and which goroutines were part of the conflict. It’s a powerful way to catch concurrency issues early—ideally before they make it into production.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Solve Data Races
&lt;/h2&gt;

&lt;p&gt;Once you’ve spotted a data race, the next step is fixing it. Go gives you three main tools for this: mutexes, atomic operations, and channels. Each has its place, depending on what you're doing and how you want to coordinate access to shared data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using a Mutex
&lt;/h3&gt;

&lt;p&gt;A sync.Mutex ensures that only one goroutine can access a piece of code at a time. You lock before accessing the shared variable and unlock after you're done.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mu&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;

&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
    &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;

&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
    &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;

&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Counter:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the mutex (&lt;code&gt;mu&lt;/code&gt;) protects access to counter. Only one goroutine can increment it at a time. It’s simple and effective—great for most shared state scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using sync/atomic
&lt;/h3&gt;

&lt;p&gt;For basic numeric operations (like counters or flags), the sync/atomic package provides a faster, lock-free alternative.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"sync/atomic"&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;

&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddInt64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;

&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddInt64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;

&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Counter:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Atomic operations are lightweight and efficient—but they only work for specific use cases, like updating integers or booleans. You can't use them for complex updates or data structures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Channels
&lt;/h3&gt;

&lt;p&gt;Channels are a Go-native way to synchronize access to data. Instead of locking, you "own" the value by passing it through a channel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="c"&gt;// initialize&lt;/span&gt;

&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;
    &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
    &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;

&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;
    &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
    &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;

&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// wait for goroutines&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Counter:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Here, the value lives inside the channel, and only one goroutine can access it at a time. It’s a safe and idiomatic way to coordinate shared state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which One Should You Use?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use Mutex: when you need simple locking for shared resources.&lt;/li&gt;
&lt;li&gt;Use Atomic: for fast, low-level operations on numbers.&lt;/li&gt;
&lt;li&gt;Use Channels: when goroutines need to communicate, not just protect data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Data races can quietly break your code in unpredictable ways. The good news? Go gives you simple tools to catch and fix them—like the -race flag, mutexes, channels, and atomic operations.&lt;/p&gt;

&lt;p&gt;Just remember: when goroutines share data, coordinate access. Pick the right tool for the job, and you’ll avoid a whole class of sneaky bugs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;"Don’t communicate by sharing memory; share memory by communicating."&lt;br&gt;
— Rob Pike&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;PRO TIP: Are you looking for an efficient way to create API documents for your projects?&lt;/p&gt;

&lt;p&gt;LiveAPI get all your backend API documented in one shot Try it out and share your feedback!&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%2Fukgim03pm0i8s2hw3c8y.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%2Fukgim03pm0i8s2hw3c8y.png" alt="Imagion" width="700" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Don't Let Your LLM Hallucinate—Check Out These Prompting Rules and Methods!</title>
      <dc:creator>LinceMathew</dc:creator>
      <pubDate>Sun, 23 Feb 2025 16:12:46 +0000</pubDate>
      <link>https://forem.com/lincemathew/dont-let-your-llm-hallucinate-check-out-these-prompting-rules-and-methods-39jb</link>
      <guid>https://forem.com/lincemathew/dont-let-your-llm-hallucinate-check-out-these-prompting-rules-and-methods-39jb</guid>
      <description>&lt;p&gt;From the &lt;a href="https://fullstackdeeplearning.com/llm-bootcamp/" rel="noopener noreferrer"&gt;&lt;strong&gt;LLM Bootcamp lectures&lt;/strong&gt;&lt;/a&gt; by &lt;strong&gt;UC Berkeley PhD alumni&lt;/strong&gt;, I’ve learned key &lt;strong&gt;rules and methods&lt;/strong&gt; that improve prompts. This article covers techniques like &lt;strong&gt;Active Prompting, Meta Prompting, and Few-Shot Prompting&lt;/strong&gt; etc designed to make models think more systematically and produce better results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Essential Rules for Writing Effective Prompts
&lt;/h2&gt;

&lt;p&gt;Here are a few important rules that can make prompts more effective. These techniques improve the accuracy and usefulness of responses.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Structured Text
&lt;/h3&gt;

&lt;p&gt;Language models perform better when given well-organized input. Just like humans find clear instructions easier to follow, models also work better with structured prompts.&lt;/p&gt;

&lt;p&gt;Example: Asking for a Python Function&lt;br&gt;
❌ Without Structure:&lt;br&gt;
"Write a Python function that checks if a number is prime."&lt;/p&gt;

&lt;p&gt;✅ With Structure (Pseudocode):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Define a function is_prime(n):
  If n is less than 2, return False
  For each number i from 2 to sqrt(n):
    If n is divisible by i, return False
  Return True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A structured prompt makes it easier for the model to understand and follow specific steps, reducing mistakes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Break Down Complex Requests (Decomposition)
&lt;/h3&gt;

&lt;p&gt;When asking a model to complete a big task, it’s better to split it into smaller steps. This improves accuracy and keeps responses more focused.&lt;/p&gt;

&lt;p&gt;Example: Writing a Blog Post&lt;br&gt;
❌ All-in-One Prompt:&lt;br&gt;
"Write a blog post about climate change and include recent statistics."&lt;/p&gt;

&lt;p&gt;✅ Step-by-Step Approach:&lt;/p&gt;

&lt;p&gt;Gather facts: "List recent climate change statistics from 2023."&lt;br&gt;
Plan the content: "Create an outline for a climate change blog post."&lt;br&gt;
Write in parts: "Write an engaging introduction for a climate change blog post."&lt;br&gt;
Expand each section separately.&lt;br&gt;
Breaking down the task ensures each part is handled properly before moving to the next.&lt;/p&gt;

&lt;p&gt;✅ With Structure (Pseudocode):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Define a function is_prime(n):
  If n is less than 2, return False
  For each number i from 2 to sqrt(n):
    If n is divisible by i, return False
  Return True

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Guide the Model’s Reasoning (Chain of Thought)
&lt;/h3&gt;

&lt;p&gt;Instead of asking for a direct answer, guiding the model through logical steps leads to better responses.&lt;/p&gt;

&lt;p&gt;Example: Checking for a Prime Number&lt;br&gt;
❌ Simple Prompt:&lt;br&gt;
"Is 2,345 a prime number?"&lt;/p&gt;

&lt;p&gt;✅ Step-by-Step Prompt:&lt;br&gt;
"Let’s determine if 2,345 is a prime number by checking divisibility step by step."&lt;/p&gt;

&lt;p&gt;This approach encourages the model to explain its reasoning, making the response more reliable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Combine Multiple Responses (Ensembling)
&lt;/h3&gt;

&lt;p&gt;No model is perfect. Each has strengths and weaknesses, so combining multiple responses can lead to better accuracy.&lt;/p&gt;

&lt;p&gt;For example, instead of relying on a single model to summarize an article, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ask two different models and compare results.&lt;/li&gt;
&lt;li&gt;Run the same model multiple times and merge the best answers.
This method helps filter out inconsistencies and improves response quality.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Different types of Prompting  Methods
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Active Prompting
&lt;/h3&gt;

&lt;p&gt;Active Prompting is a method that helps language models improve their reasoning by selecting the most useful examples for learning. Instead of relying on a fixed set of pre-written prompts, this approach identifies uncertain or ambiguous questions and refines them through human annotation.&lt;/p&gt;

&lt;h4&gt;
  
  
  How Active Prompting Works
&lt;/h4&gt;

&lt;p&gt;The process involves four key steps:&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%2Fg93nwwsqkko2scdftwz4.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%2Fg93nwwsqkko2scdftwz4.png" alt="image" width="720" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uncertainty Estimation – The model answers a set of training questions multiple times (e.g., five attempts). If the answers vary significantly, the question is marked as uncertain.&lt;/li&gt;
&lt;li&gt;Selection – The most uncertain questions are chosen for human review.&lt;/li&gt;
&lt;li&gt;Annotation – Humans provide step-by-step reasoning for these selected questions.&lt;/li&gt;
&lt;li&gt;Inference – The newly annotated examples are added back into the system, improving the model’s accuracy for similar tasks.
#### Why Active Prompting Matters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Continue reading the complete article here: &lt;a href="https://journal.hexmos.com/dont-let-your-llm-hallucinate-check-out-these-prompting-rules-and-methods/" rel="noopener noreferrer"&gt;https://journal.hexmos.com/dont-let-your-llm-hallucinate-check-out-these-prompting-rules-and-methods/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>llm</category>
      <category>promptengineering</category>
      <category>ai</category>
    </item>
    <item>
      <title>Common API Design Mistakes and How to Avoid Them</title>
      <dc:creator>LinceMathew</dc:creator>
      <pubDate>Tue, 31 Dec 2024 18:15:05 +0000</pubDate>
      <link>https://forem.com/lincemathew/common-api-design-mistakes-and-how-to-avoid-them-46e1</link>
      <guid>https://forem.com/lincemathew/common-api-design-mistakes-and-how-to-avoid-them-46e1</guid>
      <description>&lt;p&gt;Maintaining and designing scalable APIs is a tremendous task, especially once you have more than 100 APIs for your project. In the era of API as a Service, knowledge of API design is unavoidable.&lt;/p&gt;

&lt;p&gt;In this article, we will discuss a few RESTful API design standards you can apply to your projects for building an ideal API ecosystem.&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%2Fsb7f0vztzf7des3iy084.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%2Fsb7f0vztzf7des3iy084.png" alt="Imagription" width="360" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Focus on Resources
&lt;/h3&gt;

&lt;p&gt;The fundamental purpose of APIs is to provide access to particular resources. An API resource represents a piece of data or functionality that the API provides access to. &lt;/p&gt;

&lt;p&gt;For example, in a CRM (Customer Relationship Management) application, typical resources include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contacts&lt;/li&gt;
&lt;li&gt;Leads&lt;/li&gt;
&lt;li&gt;Accounts&lt;/li&gt;
&lt;li&gt;Tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A resource can be in the form of a singleton (a single account) or a collection (a group of tasks).&lt;/p&gt;

&lt;p&gt;We can design an API in the format &lt;code&gt;GET /contacts&lt;/code&gt; to fetch a list of all contacts or &lt;code&gt;PUT /tasks/301&lt;/code&gt; to update a task's details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Proper URL Naming
&lt;/h3&gt;

&lt;p&gt;Naming conventions are important for URLs. It is better to use nouns for RESTful URLs, as RESTful APIs are designed for collecting resources and communication, not for performing actions or operations.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Recommended Approach&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /contacts&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /tasks/:id&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Less Preferred Approach&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /get-contacts&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /get-task-by-id/:id&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Path Parameters
&lt;/h3&gt;

&lt;p&gt;Using path parameters provides a clear and structured way to identify resources and their relationships within the API.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /tasks/:id&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Avoid this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /tasks

{
 id:1
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Maintain API hierarchy
&lt;/h3&gt;

&lt;p&gt;Maintaining a well-defined resource hierarchy helps define relationships between different resources in an API.&lt;/p&gt;

&lt;p&gt;In the case of CRM&lt;br&gt;
&lt;code&gt;GET /user/{userId}/task/{taskId}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here, the API clearly fetches the task based on the task ID under a specific user.&lt;/p&gt;

&lt;h3&gt;
  
  
  API versioning
&lt;/h3&gt;

&lt;p&gt;APIs will get modified as the product grows. So, modifications to the API should not affect older users, older clients, or frontend code. That's when versioning comes in.&lt;/p&gt;

&lt;p&gt;Use API versioning when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Renaming or changing any endpoint or property&lt;/li&gt;
&lt;li&gt;Parameter changes&lt;/li&gt;
&lt;li&gt;Modifying a data format&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Versioning can be done by using URL Path Change or by using a Header.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;URL Path&lt;/em&gt;&lt;br&gt;
Version is defined in the path itself.&lt;br&gt;
Example: &lt;a href="https://example.com/api/v2/user" rel="noopener noreferrer"&gt;https://example.com/api/v2/user&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Header Versioning&lt;/em&gt;&lt;br&gt;
Version defined in the Header of the API&lt;br&gt;
Accept: version=1.0&lt;/p&gt;

&lt;p&gt;Maintaining and designing APIs is a never-ending challenge. It will differ for different products, use cases, and contexts. This article covers a few aspects that will help you to build better API ecosystems.&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%2Fyiwomxcfd7jrkcuhzuf4.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%2Fyiwomxcfd7jrkcuhzuf4.png" alt="Imiption" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My team and I are developing &lt;a href="https://hexmos.com/liveapi/" rel="noopener noreferrer"&gt;LiveAPI&lt;/a&gt;, a super convenient API doc generation tool. Using &lt;a href="https://hexmos.com/liveapi/" rel="noopener noreferrer"&gt;LiveAPI&lt;/a&gt;, you can create API documentation for any web project within minutes, with minimal effort. &lt;br&gt;
Also, once you connect, LiveAPI will keep your API documentation up to date based on code changes. &lt;/p&gt;

&lt;p&gt;Try LiveAPI and share your valuable feedback. Keep connected for more tech tips and articles.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>programming</category>
      <category>api</category>
    </item>
    <item>
      <title>Learn Golang in 2025, You Won't Regret It</title>
      <dc:creator>LinceMathew</dc:creator>
      <pubDate>Sun, 29 Dec 2024 18:34:57 +0000</pubDate>
      <link>https://forem.com/lincemathew/learn-golang-in-2025-you-wont-regret-it-531f</link>
      <guid>https://forem.com/lincemathew/learn-golang-in-2025-you-wont-regret-it-531f</guid>
      <description>&lt;p&gt;As I explained in previous articles, we are working on building &lt;a href="https://hexmos.com/liveapi/" rel="noopener noreferrer"&gt;LiveAPI&lt;/a&gt;, a super-convenient auto-API doc generation tool. LiveAPI's backend is in Golang, and I'm discovering the unique and cool features of Golang.&lt;/p&gt;

&lt;p&gt;For those who don't know, &lt;a href="https://github.com/golang/go" rel="noopener noreferrer"&gt;Golang (Go)&lt;/a&gt; is a programming language designed at Google in 2009. It is syntactically similar to C.&lt;/p&gt;

&lt;p&gt;Before working on Golang projects, I primarily used Node.js and Python web frameworks. For a beginner switching to Golang from another domain, it can be a little difficult initially, but once you practice and gain expertise, you won't leave.&lt;/p&gt;

&lt;p&gt;My first Golang project was to convert a Python CLI tool, &lt;a href="https://github.com/HexmosTech/glee" rel="noopener noreferrer"&gt;Glee&lt;/a&gt;, to Golang. &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%2F2qy4qjgricsi7xogx1r1.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%2F2qy4qjgricsi7xogx1r1.png" alt="Imagcription" width="220" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We found Python to be slower and maintaining a single compiled CLI binary to be very difficult, the binary sometimes not compatible with Mac OS. These and other issues forced us to switch to Golang. &lt;a href="https://www.reddit.com/r/golang/comments/1b0bao1/my_experience_with_go_as_a_python_developer/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button" rel="noopener noreferrer"&gt;Here is a Reddit post on the story&lt;/a&gt; and the issues behind the switch.&lt;/p&gt;

&lt;p&gt;In this article, I will explain the unique features in Golang that attracted me to it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Goroutines - Lightweight Concurrency&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func main() {
    go sayHello("World") // runs concurrently
    time.Sleep(1 * time.Second) 
}

func sayHello(name string) {
    fmt.Printf("Hello, %s!\n", name)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Think of goroutines like tiny workers that can do tasks independently. They're much lighter than traditional threads - you can create thousands of them without a performance hit.&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%2Fzouv8kac79pfv4at7lnc.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%2Fzouv8kac79pfv4at7lnc.png" alt="Imaription" width="300" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Channels - Built-in Communication&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func main() {
    messages := make(chan string)
    go func() { messages &amp;lt;- "ping" }()
    msg := &amp;lt;-messages
    fmt.Println(msg)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Channels are like pipes that let goroutines communicate safely. Imagine two people passing notes through a tube - one writes and puts it in, the other takes it out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Defer - Cleanup Made Simple&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func readFile() {
    file, err := os.Open("test.txt")
    defer file.Close() // Will run when function exits 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Defer is like setting a reminder for cleanup tasks. It's similar to writing a post-it note saying "don't forget to close the file" right when you open it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Interface Implementation - Implicit Contracts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Writer interface {
    Write([]byte) (int, error)
}

type ConsoleWriter struct{}

func (cw ConsoleWriter) Write(data []byte) (int, error) {
    return fmt.Println(string(data))
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go's interfaces are satisfied implicitly - if a type has the right methods, it automatically implements the interface. It's like joining a club: you don't need to formally declare membership; if you can do what the club requires, you're automatically in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Multiple Return Values - Native Error Handling&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("cannot divide by zero")
    }
    return a / b, nil
}

func main() {
    result, err := divide(10, 0)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    fmt.Println("Result:", result)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multiple return values make error handling natural and explicit in Go. It's like getting both a package and a receipt when shopping - you can check if everything is okay before proceeding. This pattern encourages developers to handle errors properly.&lt;/p&gt;

&lt;p&gt;These are just a few features I like in Go. There are also others, like single executable binaries, faster performance, type inference, built-in testing support, and cross-compilation.&lt;/p&gt;

&lt;p&gt;If you're making resolutions for 2025, add Golang to your list. You won't regret it. Thanks for reading! If you want to learn Golang by contributing to an open-source project, check out &lt;a href="https://github.com/HexmosTech/glee" rel="noopener noreferrer"&gt;glee&lt;/a&gt; and &lt;a href="https://github.com/HexmosTech/Lama2" rel="noopener noreferrer"&gt;Lama2&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
      <category>go</category>
    </item>
    <item>
      <title>What is Mutex and How to Use it in Golang?</title>
      <dc:creator>LinceMathew</dc:creator>
      <pubDate>Sat, 28 Dec 2024 20:07:45 +0000</pubDate>
      <link>https://forem.com/lincemathew/what-is-mutex-and-how-to-use-it-in-golang-1m1i</link>
      <guid>https://forem.com/lincemathew/what-is-mutex-and-how-to-use-it-in-golang-1m1i</guid>
      <description>&lt;p&gt;During the development of &lt;a href="https://liveapi.hexmos.com/" rel="noopener noreferrer"&gt;LiveAPI&lt;/a&gt;, an Auto API documentation generation tool, I needed to implement a robust queue mechanism that scaled based on the number of server machine cores. This was crucial to prevent excessive resource usage (memory and CPU) that could lead to resource starvation, crashes, and a poor user experience.&lt;/p&gt;

&lt;p&gt;In this article, I'll explain how I utilized mutexes in Golang to address this challenge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is a Mutex?&lt;/strong&gt;&lt;br&gt;
In concurrent programming, a Mutex (Mutual Exclusion) is a locking mechanism that prevents race conditions by ensuring only one goroutine can access a shared resource at a time.  It's akin to a key to a room – only one person can hold the key and enter at once.&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%2Fvd11vq7kfvmdgc2g551z.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%2Fvd11vq7kfvmdgc2g551z.png" alt="Imagiption" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mutex Usage in Golang&lt;/strong&gt;&lt;br&gt;
Let's illustrate how a Mutex can manage concurrent job execution:&lt;br&gt;
&lt;a href="https://pkg.go.dev/sync" rel="noopener noreferrer"&gt;Go's sync package &lt;/a&gt; provides several primitives for synchronization, with Mutex being one of the most commonly used tools.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var (
    maxConcurrentJobs int
    activeJobs        int
    jobMutex          sync.Mutex
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, the &lt;code&gt;activeJobs&lt;/code&gt; variable tracks the number of currently running jobs. Since multiple goroutines might attempt to modify this variable concurrently, leading to race conditions, we use a Mutex to synchronize access.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Check if we can process more jobs
jobMutex.Lock()
if activeJobs &amp;gt;= maxConcurrentJobs {
    jobMutex.Unlock()
    // Wait before checking again
    time.Sleep(time.Second)
    continue
}
jobMutex.Unlock()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How a Mutex Works&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Locking&lt;/em&gt;: The &lt;code&gt;Lock()&lt;/code&gt; method acquires exclusive access to the critical section.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Unlocking&lt;/em&gt;: The &lt;code&gt;Unlock()&lt;/code&gt; method releases the lock.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Critical Section&lt;/em&gt;: The code between &lt;code&gt;Lock&lt;/code&gt; and &lt;code&gt;Unlock&lt;/code&gt; where the **shared resource is accessed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Types of Mutexes in Golang&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;sync.Mutex&lt;/em&gt;: This is the basic mutual exclusion lock in Go. It allows only one goroutine to access the critical section at a time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type SafeCounter struct {
    mu    sync.Mutex
    count int
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;sync.RWMutex&lt;/em&gt;: This is a reader/writer mutex that allows multiple readers to access the shared resource simultaneously, but only one writer at a time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var rwMutex sync.RWMutex
// Reader methods
rwMutex.RLock()   // Lock for reading
rwMutex.RUnlock() // Unlock for reading

// Writer methods
rwMutex.Lock()    // Lock for writing
rwMutex.Unlock()  // Unlock for writing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mutexes are essential tools for managing shared resources in concurrent Go programs. They prevent race conditions and ensure data integrity by controlling access to critical sections of code.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>go</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Working on Redis streams? Don't forget these commands.</title>
      <dc:creator>LinceMathew</dc:creator>
      <pubDate>Sat, 28 Dec 2024 01:31:13 +0000</pubDate>
      <link>https://forem.com/lincemathew/working-on-redis-streams-dont-forget-these-commands-5dlp</link>
      <guid>https://forem.com/lincemathew/working-on-redis-streams-dont-forget-these-commands-5dlp</guid>
      <description>&lt;p&gt;I’ve been learning and implementing Redis streams for the past few days to set up a real-time communication system and queue management for our product &lt;a href="https://hexmos.com/liveapi/" rel="noopener noreferrer"&gt;LiveAPI&lt;/a&gt;, an auto API doc generation tool.&lt;/p&gt;

&lt;p&gt;In this article, let us discuss a few Redis Stream commands that you need to be aware of while building efficient solutions using Redis Streams.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;XADD: This command helps to add new entries to a stream. 
Example: &lt;code&gt;XADD mystream * sensor-id 1234 temperature 19.8 humidity 43.5&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This command adds a new entry to the stream 'mystream'. The * tells Redis to auto-generate the entry ID. Each entry contains multiple field-value pairs (sensor-id, temperature, humidity).&lt;/p&gt;

&lt;p&gt;2.XREAD: This command reads entries from one or more streams. &lt;br&gt;
Example: &lt;code&gt;XREAD COUNT 2 STREAMS mystream 0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This reads 2 entries from 'mystream' starting from the beginning (ID 0).&lt;/p&gt;

&lt;p&gt;3.XRANGE: This command returns entries within a specific ID range. &lt;br&gt;
Example: &lt;code&gt;XRANGE mystream 1641293000000-0 1641293060000-0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This command is used to get historical data within a specific range.&lt;/p&gt;

&lt;p&gt;4.XGROUP CREATE: Creates a consumer group for stream processing. &lt;br&gt;
Example: &lt;code&gt;XGROUP CREATE mystream mygroup $&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Creates a consumer group named 'mygroup' for 'mystream'. The $ means the group will only read new messages (from the last ID).&lt;/p&gt;

&lt;p&gt;5.XREADGROUP: Reads from a stream as part of a consumer group. &lt;br&gt;
Example: &lt;code&gt;XREADGROUP GROUP mygroup consumer1 COUNT 1 STREAMS mystream &amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This reads one unread message from 'mystream' as consumer1 in mygroup. The &amp;gt; means "give me new messages that haven’t been delivered to other consumers".&lt;/p&gt;

&lt;p&gt;6.XCLAIM: Used to transfer ownership of pending messages. &lt;br&gt;
Example: &lt;code&gt;XCLAIM mystream mygroup consumer2 30000 1692312456878-0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This command will transfer ownership from one consumer to another within the same consumer group. This is particularly useful in handling failed consumers or rebalancing workloads. XCLAIM ensures no messages are lost if a consumer fails, enables work redistribution for better load balancing, and provides message recovery mechanisms.&lt;/p&gt;

&lt;p&gt;I hope these few commands help to give you an idea about Redis streams and their commands. Share your valuable feedback.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>redis</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I Created API Docs for 5 Open-source Projects Within 10 Minutes</title>
      <dc:creator>LinceMathew</dc:creator>
      <pubDate>Wed, 25 Dec 2024 11:40:04 +0000</pubDate>
      <link>https://forem.com/lincemathew/i-created-api-docs-for-5-open-source-projects-within-10-minutes-4fg5</link>
      <guid>https://forem.com/lincemathew/i-created-api-docs-for-5-open-source-projects-within-10-minutes-4fg5</guid>
      <description>&lt;p&gt;Creating and maintaining API documentation for any project is a tremendous task that eats up most of your time. However, we can't ignore this step in web development engineering because API docs play a significant role in collaboration, decision-making, and guidance.&lt;/p&gt;

&lt;p&gt;For the last few months, my team and I have been working on developing &lt;a href="https://hexmos.com/liveapi/" rel="noopener noreferrer"&gt;LiveAPI&lt;/a&gt;, a super convenient tool for creating API Docs with the help of AI. Existing documentation tools, for example, &lt;a href="https://swagger.io/" rel="noopener noreferrer"&gt;Swagger&lt;/a&gt;, take time and effort from developers to set up and maintain. We saw an opportunity here and developed an easy doc generation tool that works within a few clicks.&lt;/p&gt;

&lt;p&gt;Here, I will explain how I created API Docs using &lt;a href="https://hexmos.com/liveapi/" rel="noopener noreferrer"&gt;LiveAPI&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, sign up for &lt;a href="https://liveapi.hexmos.com/" rel="noopener noreferrer"&gt;LiveAPI here&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;Once logged in, find and select the "Create API Docs" option.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;Paste the GitHub/GitLab URL of the open-source or your personal project.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;Click the "Create Docs" button and allow a few minutes for the process to complete.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;Once finished, the documentation will be hosted on LiveAPI, and you can access the link immediately.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Using this method, I created API docs for 5 open-source web projects within 10 minutes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/mongo-express/mongo-express" rel="noopener noreferrer"&gt;Mongo-express&lt;/a&gt;: A web-based MongoDB admin interface written with Node.js, Express, and Bootstrap 5&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/inventree/InvenTree" rel="noopener noreferrer"&gt;InvenTree&lt;/a&gt;: An open-source inventory management system that provides powerful low-level stock control and part tracking.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/freescout-help-desk/freescout" rel="noopener noreferrer"&gt;Freescout&lt;/a&gt;: FreeScout is the super lightweight and powerful free open source help desk and shared inbox built with PHP (Laravel framework).&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/BookStackApp/BookStack" rel="noopener noreferrer"&gt;BookStack&lt;/a&gt;: A platform for storing and organising information and documentation. &lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/raeperd/realworld-springboot-java" rel="noopener noreferrer"&gt;realworld-springboot-java&lt;/a&gt;: ReadWorld.io backend project using spring boot java using spring-security, spring-data-jpa&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Try &lt;a href="https://liveapi.hexmos.com/" rel="noopener noreferrer"&gt;LiveAPI&lt;/a&gt; today to create API docs for your personal or open-source projects in minutes.&lt;/p&gt;

&lt;p&gt;Want to learn more about LiveAPI's features? Check out our landing page here and find other blogs &lt;a href="https://dev.to/lincemathew"&gt;in my bio&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Follow me for more exciting product news and tips!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>liveapi</category>
      <category>ai</category>
    </item>
    <item>
      <title>Redis Pub/Sub vs. Redis Streams: Choosing the Right Solution</title>
      <dc:creator>LinceMathew</dc:creator>
      <pubDate>Mon, 23 Dec 2024 19:40:33 +0000</pubDate>
      <link>https://forem.com/lincemathew/redis-pubsub-vs-redis-streams-choosing-the-right-solution-2oei</link>
      <guid>https://forem.com/lincemathew/redis-pubsub-vs-redis-streams-choosing-the-right-solution-2oei</guid>
      <description>&lt;p&gt;While working on building a &lt;a href="https://dev.to/lincemathew/is-this-a-good-way-to-reduce-operational-costs-4ig2"&gt;Go binary tool ("Runner")&lt;/a&gt; for our product &lt;a href="https://hexmos.com/liveapi/" rel="noopener noreferrer"&gt;LiveAPI&lt;/a&gt; (the super convenient API doc generation tool), we needed to establish communication between LiveAPI's backend and Runner. We initially tried the &lt;a href="https://redis.io/docs/latest/develop/interact/pubsub/" rel="noopener noreferrer"&gt;Redis pub/sub &lt;/a&gt; mechanism but later realized it was insufficient for our use case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problems with Redis Pub/Sub&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Redis Pub/Sub follows a traditional publish-subscribe model: Publishers send messages to channels, and subscribers receive messages from the channels they are subscribed to.&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%2Faoqmvrrcevuwaj9r6zs1.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%2Faoqmvrrcevuwaj9r6zs1.png" alt="pub/sub" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This presented several problems for LiveAPI:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Duplicate Operations and Wasted Resources&lt;/em&gt;: If a user ran the same Runner on multiple devices, the subscription behavior of pub/sub would cause the same operations to run on multiple devices, creating duplication and wasting resources.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Memory and Data Loss&lt;/em&gt;: Pub/sub doesn't retain or persist messages, so if the server crashed or a job failed due to a panic, there was no way to restart the operations.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Lack of Acknowledgement&lt;/em&gt;: The LiveAPI backend had no indication that a job request from the consumer had reached the subscriber.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redis Streams as the Solution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Redis Streams provide a more robust and feature-rich messaging system. They are essentially append-only logs where producers add messages, and consumers read them.&lt;/p&gt;

&lt;p&gt;Redis Streams addresses the issues we encountered with Pub/Sub:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Avoids Duplicate Operations&lt;/em&gt;: Even if the same Runner is running on multiple devices, only one instance can read and acknowledge a message, preventing the duplicate operations that occurred with pub/sub.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Message Persistence&lt;/em&gt;: Redis Streams persist messages. If the server crashes, operations can be restarted with the same message.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Guaranteed Delivery and Acknowledgement&lt;/em&gt;: Redis Streams provides message acknowledgement, assuring the LiveAPI backend that job requests reach the intended subscriber.&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%2F779x8145zjf99e7drynr.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%2F779x8145zjf99e7drynr.png" alt="stream" width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understand Your Usecase&lt;/strong&gt;&lt;br&gt;
Redis Streams was selected as a solution for LiveAPI due to its message persistence, guaranteed delivery, message acknowledgement, and ability to prevent duplicate operations. &lt;/p&gt;

&lt;p&gt;While Pub/Sub is a simpler solution and better suited for real-time messaging, Streams offers more features and guarantees, making it ideal for use cases where data durability and reliability are critical.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>ai</category>
      <category>liveapi</category>
    </item>
    <item>
      <title>Never Give Up on Learning a New Web Framework. This trick will solve a significant part of the problem.</title>
      <dc:creator>LinceMathew</dc:creator>
      <pubDate>Wed, 18 Dec 2024 05:50:28 +0000</pubDate>
      <link>https://forem.com/lincemathew/never-give-up-on-learning-a-new-web-framework-this-trick-will-solve-a-significant-part-of-the-54o8</link>
      <guid>https://forem.com/lincemathew/never-give-up-on-learning-a-new-web-framework-this-trick-will-solve-a-significant-part-of-the-54o8</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/lincemathew" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2F1138237%2F84b2cb1c-8fe3-4f02-bbea-4edd8de7c7b7.jpeg" alt="lincemathew"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/lincemathew/simple-trick-to-create-api-docs-for-any-open-source-web-projects-iil" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Simple Trick to Create API Docs for any Open-source Web Projects&lt;/h2&gt;
      &lt;h3&gt;LinceMathew ・ Dec 18 '24&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#programming&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#opensource&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#ai&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>learning</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
