<?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: Joy Biswas</title>
    <description>The latest articles on Forem by Joy Biswas (@joybtw).</description>
    <link>https://forem.com/joybtw</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%2F2192152%2F9a3e8268-129a-4185-bc83-1f840f89d58a.png</url>
      <title>Forem: Joy Biswas</title>
      <link>https://forem.com/joybtw</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/joybtw"/>
    <language>en</language>
    <item>
      <title>Why You Should Use panic Instead of log.Fatal for Cleanup</title>
      <dc:creator>Joy Biswas</dc:creator>
      <pubDate>Wed, 26 Nov 2025 04:51:14 +0000</pubDate>
      <link>https://forem.com/joybtw/why-you-should-use-panic-instead-of-fatal-for-cleanup-4ph4</link>
      <guid>https://forem.com/joybtw/why-you-should-use-panic-instead-of-fatal-for-cleanup-4ph4</guid>
      <description>&lt;p&gt;When writing code in Go we often run into errors that are critical. These are errors that mean our application cannot continue running. To handle these we usually look at two options. We can use &lt;code&gt;panic&lt;/code&gt; or we can use &lt;code&gt;log.Fatal&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;They both stop the application but they do it in very different ways. The main difference is how they treat the &lt;code&gt;defer&lt;/code&gt; function.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem with Fatal
&lt;/h3&gt;

&lt;p&gt;When you use &lt;code&gt;log.Fatal&lt;/code&gt; the application stops immediately. It calls a system function called &lt;code&gt;os.Exit(1)&lt;/code&gt;. This is a hard stop. The program does not look back and it does not run any cleanup code.&lt;/p&gt;

&lt;p&gt;Let us look at a standard example. Imagine we are connecting to a database in our &lt;code&gt;main&lt;/code&gt; function. We want to make sure the database connection closes when the app stops.&lt;br&gt;
&lt;/p&gt;

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

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

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;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;"1. Opening Database Connection..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// We schedule this to run when the function exits&lt;/span&gt;
    &lt;span class="k"&gt;defer&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;"Clean up: Closing Database Connection."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Something bad happens here&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CRITICAL ERROR: System failure!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&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;1. Opening Database Connection...
2025/11/26 10:00:00 CRITICAL ERROR: System failure!
exit status 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what is missing? The line "Clean up: Closing Database Connection" never printed. The &lt;code&gt;defer&lt;/code&gt; function was ignored. If this was a real application the database connection might remain open on the server side until it times out because we never sent the close signal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Panic is Different
&lt;/h3&gt;

&lt;p&gt;Now let us look at &lt;code&gt;panic&lt;/code&gt;. When a program panics it begins to shut down but it does not stop immediately. It starts "unwinding" the stack. This means it goes back up through the functions you called.&lt;/p&gt;

&lt;p&gt;Crucially, &lt;strong&gt;panic executes any deferred functions&lt;/strong&gt; it finds along the way.&lt;/p&gt;

&lt;p&gt;Here is the same example using &lt;code&gt;panic&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

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

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

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;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;"1. Opening Database Connection..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// We schedule this to run when the function exits&lt;/span&gt;
    &lt;span class="k"&gt;defer&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;"Clean up: Closing Database Connection."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Something bad happens here&lt;/span&gt;
    &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CRITICAL ERROR: System failure!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&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;1. Opening Database Connection...
Clean up: Closing Database Connection.
panic: CRITICAL ERROR: System failure!

[stack trace...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Logic: Why Use Panic?
&lt;/h3&gt;

&lt;p&gt;You should use &lt;code&gt;panic&lt;/code&gt; instead of &lt;code&gt;log.Fatal&lt;/code&gt; when you have critical resources to manage.&lt;/p&gt;

&lt;p&gt;In our example we initialized our application and opened a main database connection. The connection was successful. But then another error occurred later in the code.&lt;/p&gt;

&lt;p&gt;If we use &lt;code&gt;log.Fatal&lt;/code&gt; the app just dies. The database connection is never explicitly closed.&lt;/p&gt;

&lt;p&gt;If we use &lt;code&gt;panic&lt;/code&gt; the application understands that it needs to crash but it is polite about it. It pauses to run the &lt;code&gt;defer&lt;/code&gt; function. This allows us to strictly close the database connection. Once the cleanup is done the application finally shuts down and prints the error message.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;log.Fatal:&lt;/strong&gt; Stops the app instantly. It skips &lt;code&gt;defer&lt;/code&gt; functions. Use this only if you have no cleanup to do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;panic:&lt;/strong&gt; Stops the normal flow but runs &lt;code&gt;defer&lt;/code&gt; functions first. Use this when you need to ensure connections, files, or resources are closed properly before the program exits.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Go's New WaitGroup.Go</title>
      <dc:creator>Joy Biswas</dc:creator>
      <pubDate>Sun, 02 Nov 2025 05:44:52 +0000</pubDate>
      <link>https://forem.com/joybtw/gos-new-waitgroupgo-ed8</link>
      <guid>https://forem.com/joybtw/gos-new-waitgroupgo-ed8</guid>
      <description>&lt;p&gt;Go 1.25+ added a new method to the &lt;code&gt;sync&lt;/code&gt; package that removes common boilerplate: the &lt;code&gt;WaitGroup.Go()&lt;/code&gt; method. If you've used &lt;code&gt;wg.Add(1)&lt;/code&gt;, &lt;code&gt;go func()&lt;/code&gt;, and &lt;code&gt;defer wg.Done()&lt;/code&gt; hundreds of times, this one's for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The old way
&lt;/h2&gt;

&lt;p&gt;Here's how we launch concurrent goroutines:&lt;br&gt;
&lt;/p&gt;

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

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

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;
    &lt;span class="n"&gt;list1&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&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;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;list2&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&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="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;l1&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;l2&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&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;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;6&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="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list1&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;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="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l1&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&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;uniqueIdx&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num1&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;uniqueIdx&lt;/span&gt; &lt;span class="o"&gt;^=&lt;/span&gt; &lt;span class="n"&gt;num1&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num2&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;uniqueIdx&lt;/span&gt; &lt;span class="o"&gt;^=&lt;/span&gt; &lt;span class="n"&gt;num2&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;uniqueIdx&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;This works fine. But look at the steps: increment the counter manually, wrap everything in an anonymous function, remember to defer the done call. For every single goroutine.&lt;/p&gt;

&lt;h2&gt;
  
  
  The new way
&lt;/h2&gt;

&lt;p&gt;Now we can write:&lt;br&gt;
&lt;/p&gt;

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

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

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;
    &lt;span class="n"&gt;list1&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&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;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;list2&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&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="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;l1&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;l2&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;[]&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;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;6&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;Go&lt;/span&gt;&lt;span class="p"&gt;(&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;solution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list2&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;Go&lt;/span&gt;&lt;span class="p"&gt;(&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;solution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l1&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&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;uniqueIdx&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num1&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;uniqueIdx&lt;/span&gt; &lt;span class="o"&gt;^=&lt;/span&gt; &lt;span class="n"&gt;num1&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num2&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;uniqueIdx&lt;/span&gt; &lt;span class="o"&gt;^=&lt;/span&gt; &lt;span class="n"&gt;num2&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;uniqueIdx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Go()&lt;/code&gt; method handles the counter increment and the &lt;code&gt;Done()&lt;/code&gt; call automatically. Three steps become one clean method call.&lt;/p&gt;

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

&lt;p&gt;The implementation is simple:&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="c"&gt;// https://github.com/golang/go/blob/master/src/sync/waitgroup.go&lt;/span&gt;
&lt;span class="k"&gt;func&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;WaitGroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Go&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&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;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="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's exactly what we've been writing manually, just packaged properly.&lt;/p&gt;

&lt;p&gt;If you're on Go 1.25 or later, start using &lt;code&gt;wg.Go()&lt;/code&gt; where it makes sense.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Thanks to &lt;a href="https://antonz.org/" rel="noopener noreferrer"&gt;Anton Zhiyanov&lt;/a&gt; for his excellent &lt;a href="https://antonz.org/go-concurrency/goroutines/#go-routine" rel="noopener noreferrer"&gt;Gist of Go: Concurrency&lt;/a&gt; guide&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
    </item>
    <item>
      <title>Email Validation and SMTP Handshake With Go</title>
      <dc:creator>Joy Biswas</dc:creator>
      <pubDate>Fri, 24 Oct 2025 12:47:29 +0000</pubDate>
      <link>https://forem.com/joybtw/email-validation-and-smtp-handshake-with-go-39gp</link>
      <guid>https://forem.com/joybtw/email-validation-and-smtp-handshake-with-go-39gp</guid>
      <description>&lt;p&gt;I was implementing a signup endpoint for an API where users can register via email. There are many ways to verify an email address. You could use a popular library like &lt;code&gt;go-playground/validator&lt;/code&gt; to check if the input is in an email format. However, this doesn't confirm if the email address actually exists or if its domain can receive mail.&lt;/p&gt;

&lt;p&gt;If you prefer not to use regex or an external package, Go's standard library offers the &lt;code&gt;net/mail&lt;/code&gt; package to validate an email address format.&lt;/p&gt;

&lt;p&gt;This approach is generally better than a simple regex validation because &lt;code&gt;mail.ParseAddress&lt;/code&gt; parses an address according to the official &lt;strong&gt;RFC 5322 specification&lt;/strong&gt;, which defines the standard for email format.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Basic Format Validation&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Let's start by checking if a string has a valid email format.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1: A Well-Formatted but Non-Existent Email&lt;/strong&gt;&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;email&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"example-user@exampledomain.com"&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code will run without an error. It passes the test because the string contains a local part (&lt;code&gt;example-user&lt;/code&gt;), an &lt;code&gt;@&lt;/code&gt; symbol, and a domain (&lt;code&gt;exampledomain.com&lt;/code&gt;). The &lt;code&gt;ParseAddress&lt;/code&gt; function only cares about the format, not whether the address is real.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 2: An Incorrect Format&lt;/strong&gt;&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;email&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"example-user"&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, the program will panic and show the error: &lt;code&gt;mail: missing '@' in address&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Validating the Domain&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Format validation is a good first step, but it doesn't prevent users from signing up with an address like &lt;code&gt;test@nonexistent-domain.com&lt;/code&gt;. Our next thought might be to check the domain's DNS records.&lt;/p&gt;

&lt;p&gt;A common but flawed approach is to look up the host directly.&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;"net"&lt;/span&gt;

&lt;span class="n"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"exampledomain.com"&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LookupHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This check for an &lt;code&gt;A&lt;/code&gt; or &lt;code&gt;AAAA&lt;/code&gt; record is not what we need for email validation. Many people purchase domains exclusively for email services and never set up a website, so they may not have an &lt;code&gt;A&lt;/code&gt; record pointing to a web server. Letting users pass verification based on this check is a bad idea.&lt;/p&gt;

&lt;p&gt;The correct approach is to check for &lt;strong&gt;&lt;code&gt;MX&lt;/code&gt; (Mail Exchanger)&lt;/strong&gt; records. These DNS records specify the mail servers responsible for accepting email on behalf of a domain. If a domain has &lt;code&gt;MX&lt;/code&gt; records, it's configured to receive email.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Looking Up MX Records&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;First, let's get the domain name from the email address and use &lt;code&gt;net.LookupMX&lt;/code&gt; to find the &lt;code&gt;MX&lt;/code&gt; records for that domain.&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;email&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"contact@gmail.com"&lt;/span&gt;
&lt;span class="n"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"@"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;parts&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="c"&gt;// "gmail.com"&lt;/span&gt;

&lt;span class="n"&gt;mxRecords&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LookupMX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Panicf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to look up MX records for %s: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mxRecords&lt;/span&gt;&lt;span class="p"&gt;)&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;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No MX records found for %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MX Records for %s:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mx&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;mxRecords&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;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"  Host: %s, Preference: %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pref&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;For a valid address like &lt;code&gt;contact@gmail.com&lt;/code&gt;, you'll see a result similar to this, confirming the domain is set up to receive mail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;MX Records &lt;span class="k"&gt;for &lt;/span&gt;gmail.com:
  Host: gmail-smtp-in.l.google.com., Preference: 5
  Host: alt1.gmail-smtp-in.l.google.com., Preference: 10
  Host: alt2.gmail-smtp-in.l.google.com., Preference: 20
  Host: alt3.gmail-smtp-in.l.google.com., Preference: 30
  Host: alt4.gmail-smtp-in.l.google.com., Preference: 40
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run the same code on a domain with no &lt;code&gt;MX&lt;/code&gt; records, &lt;code&gt;net.LookupMX&lt;/code&gt; will return an error, such as &lt;code&gt;lookup joybtw.com: no such host&lt;/code&gt;. This tells us the domain is not configured to receive email, and we should reject the address.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;The SMTP Handshake to Verify the Mailbox&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Now that we know the domain is configured to receive mail, we can go one step further by asking the server if the specific mailbox (e.g., &lt;code&gt;contact@gmail.com&lt;/code&gt;) actually exists. We can do this by performing a partial &lt;strong&gt;SMTP handshake&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This process involves connecting to the mail server and simulating the first few steps of sending an email, stopping just before transmitting any actual content. The key is the &lt;code&gt;RCPT TO&lt;/code&gt; command, where we ask the server if it will accept a message for our target email address. The server's response tells us whether the user likely exists.&lt;/p&gt;

&lt;p&gt;Here’s how it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Connect to the Mail Server:&lt;/strong&gt; We connect to the mail server with the highest priority (lowest preference number) on port 25.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Start the Conversation (&lt;code&gt;EHLO&lt;/code&gt;):&lt;/strong&gt; We greet the server to start the conversation.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Specify the Sender (&lt;code&gt;MAIL FROM&lt;/code&gt;):&lt;/strong&gt; We state the sender's address.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Check the Recipient (&lt;code&gt;RCPT TO&lt;/code&gt;):&lt;/strong&gt; We provide the email address to validate.

&lt;ul&gt;
&lt;li&gt;  A response code starting with &lt;strong&gt;&lt;code&gt;250&lt;/code&gt;&lt;/strong&gt; means "OK," and the address is likely valid.&lt;/li&gt;
&lt;li&gt;  A response code like &lt;strong&gt;&lt;code&gt;550&lt;/code&gt;&lt;/strong&gt; means the address does not exist.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;End the Conversation (&lt;code&gt;QUIT&lt;/code&gt;):&lt;/strong&gt; We properly close the connection without sending an email.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Important Considerations&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;While powerful, this method isn't foolproof:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Catch-All Addresses:&lt;/strong&gt; Some servers are configured with a "catch-all" policy, meaning they accept emails for &lt;em&gt;any&lt;/em&gt; address at that domain to prevent spammers from guessing valid addresses. In this case, the &lt;code&gt;RCPT TO&lt;/code&gt; check will always succeed, even for non-existent mailboxes.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Security Measures:&lt;/strong&gt; Mail servers may use security features like greylisting or block automated checks altogether. This can lead to false negatives, where a valid address appears invalid.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Here is the complete code:&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Here is a simple, runnable Go program that combines these validation steps.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"bufio"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net"&lt;/span&gt;
    &lt;span class="s"&gt;"net/mail"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"contact@gmail.com"&lt;/span&gt; &lt;span class="c"&gt;// Change this to test other emails&lt;/span&gt;

    &lt;span class="c"&gt;// Validate Email Format&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"'%s' is not a valid email format: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Extract Domain and Find MX Records&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastIndexByte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'@'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;email&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="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;mxRecords&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LookupMX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Could not look up MX records for '%s': %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mxRecords&lt;/span&gt;&lt;span class="p"&gt;)&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;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No MX records found for '%s'."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Perform SMTP Handshake&lt;/span&gt;
    &lt;span class="n"&gt;mxServer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mxRecords&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Host&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mxServer&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;":25"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Could not connect to SMTP server: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bufio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Could not read from connection: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"S: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// EHLO command&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;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"EHLO mydomain.com&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'\n'&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;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"S: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// MAIL FROM command&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;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"MAIL FROM:&amp;lt;test@mydomain.com&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'\n'&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;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"S: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// RCPT TO command (The actual check)&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;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"RCPT TO:&amp;lt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'\n'&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;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"S: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Check the response for the recipient&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"250"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Result: Email address is likely valid."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;"Result: Email address is likely invalid."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// QUIT&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;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"QUIT&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'\n'&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;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"S: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;This code is for educational purposes to demonstrate the concepts of email validation. It is not production-level code. For a real-world application, you would need more robust error handling, connection timeouts, and logic to iterate through multiple MX records if the primary one fails.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>security</category>
    </item>
    <item>
      <title>Makefile is Awesome, and I Love It</title>
      <dc:creator>Joy Biswas</dc:creator>
      <pubDate>Sun, 19 Oct 2025 13:23:28 +0000</pubDate>
      <link>https://forem.com/joybtw/makefile-is-awesome-and-i-love-it-48aj</link>
      <guid>https://forem.com/joybtw/makefile-is-awesome-and-i-love-it-48aj</guid>
      <description>&lt;p&gt;Makefile is my go-to tool for every project now. Instead of running long commands inside the repo, I use Makefile. Makefile is super awesome!&lt;/p&gt;

&lt;p&gt;For my &lt;a href="https://github.com/joybiswas007/blog" rel="noopener noreferrer"&gt;blog&lt;/a&gt;, while building, there were lots of commands I needed to run, like building the binary, running the binary, building the docker image, and re-building the docker image every time I made changes in my code. I had to run many commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go build -o blog ./cmd/api/main.go
sudo docker compose up -d
sudo docker compose up --build -d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sometimes I became so lazy that I pressed the up arrow key lots of times because there were many other commands I had executed.&lt;/p&gt;

&lt;p&gt;That’s why I thought I should use Makefile. You just set up the Makefile and run the command &lt;code&gt;make build&lt;/code&gt;. Once you set it up, you can see the generated binary. You can easily remember what to run; you don’t have to type the full &lt;code&gt;go build -o blog ./cmd/api/main.go&lt;/code&gt; or other project-related commands all the time. It’s just easy and cool.&lt;/p&gt;

&lt;p&gt;Example Makefile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;BINARY_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; blog
&lt;span class="nv"&gt;CLI_BINARY_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; blog_cli
&lt;span class="nv"&gt;API_ENTRY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; cmd/api/main.go
&lt;span class="nv"&gt;CLI_ENTRY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; cmd/cli/main.go

&lt;span class="c"&gt;# Build the main API binary.
&lt;/span&gt;&lt;span class="nl"&gt;build&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"==&amp;gt; Building API binary: &lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;&lt;span class="s2"&gt;BINARY_NAME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;go build &lt;span class="nt"&gt;-ldflags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-s -w"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;BINARY_NAME&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;API_ENTRY&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Build the command-line interface (CLI) binary.
&lt;/span&gt;&lt;span class="nl"&gt;build-cli&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"==&amp;gt; Building CLI binary: &lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;&lt;span class="s2"&gt;CLI_BINARY_NAME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;go build &lt;span class="nt"&gt;-ldflags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-s -w"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;CLI_BINARY_NAME&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;CLI_ENTRY&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Run the API application directly.
&lt;/span&gt;&lt;span class="nl"&gt;run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"==&amp;gt; Running API from &lt;/span&gt;&lt;span class="p"&gt;$(&lt;/span&gt;&lt;span class="s2"&gt;API_ENTRY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;go run &lt;span class="p"&gt;$(&lt;/span&gt;API_ENTRY&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Build and run the docker containers.
&lt;/span&gt;&lt;span class="nl"&gt;build-docker&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;docker-setup&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"==&amp;gt; Starting Docker containers..."&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;COMPOSE_CMD&lt;span class="p"&gt;)&lt;/span&gt; up &lt;span class="nt"&gt;-d&lt;/span&gt;

&lt;span class="c"&gt;# Rebuild and run the docker containers.
&lt;/span&gt;&lt;span class="nl"&gt;re-build-docker&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;docker-setup&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"==&amp;gt; Rebuilding and starting Docker containers..."&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;COMPOSE_CMD&lt;span class="p"&gt;)&lt;/span&gt; up &lt;span class="nt"&gt;--build&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;

&lt;span class="c"&gt;# Shut down and remove the docker containers.
&lt;/span&gt;&lt;span class="nl"&gt;docker-down&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"==&amp;gt; Shutting down Docker containers..."&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;COMPOSE_CMD&lt;span class="p"&gt;)&lt;/span&gt; down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you just have to run &lt;code&gt;make build&lt;/code&gt; or any other command you like. If you don’t know what command to run, simply run &lt;code&gt;make help&lt;/code&gt;, it will list all the available commands in the Makefile.&lt;/p&gt;

&lt;p&gt;Once I was working on a project where I used Air for live reloading, TailwindCSS for generating CSS, and Templ for generating user interfaces.&lt;/p&gt;

&lt;p&gt;While building, I had to run these three commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tailwindcss -i ./styles/input.css -o ./assets/css/output.css --watch --minify
templ generate -path ./cmd/web/templates --watch --open-browser=false
air
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can easily remember &lt;code&gt;air&lt;/code&gt;, but the other two commands are a bit long, and I had to press the up arrow key countless times.&lt;/p&gt;

&lt;p&gt;Again, Makefile came to the rescue.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nv"&gt;TEMPLATES_DIR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; cmd/web/templates
&lt;span class="nv"&gt;TAILWIND_INPUT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; cmd/web/styles/input.css
&lt;span class="nv"&gt;TAILWIND_OUTPUT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; cmd/web/assets/css/output.css

&lt;span class="nl"&gt;watch-air&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"==&amp;gt; Starting Air for live reload..."&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;air

&lt;span class="nl"&gt;watch-templ&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"==&amp;gt; Watching templ files..."&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;templ generate &lt;span class="nt"&gt;-path&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;TEMPLATES_DIR&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;--watch&lt;/span&gt; &lt;span class="nt"&gt;--open-browser&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;

&lt;span class="nl"&gt;watch-css&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"==&amp;gt; Watching CSS files..."&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;tailwindcss &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;TAILWIND_INPUT&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="p"&gt;$(&lt;/span&gt;TAILWIND_OUTPUT&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;--minify&lt;/span&gt; &lt;span class="nt"&gt;--watch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, if you try to run the commands like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;@$(&lt;/span&gt;MAKE&lt;span class="p"&gt;)&lt;/span&gt; watch-templ
    &lt;span class="p"&gt;@$(&lt;/span&gt;MAKE&lt;span class="p"&gt;)&lt;/span&gt; watch-air
    &lt;span class="p"&gt;@$(&lt;/span&gt;MAKE&lt;span class="p"&gt;)&lt;/span&gt; watch-css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method won’t work because here we are executing three commands sequentially, so the second command waits for the first to finish.&lt;/p&gt;

&lt;p&gt;Now we have to run these commands in parallel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;watch&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"==&amp;gt; Starting live reload with Air, Templ, and Tailwind CSS..."&lt;/span&gt;
    &lt;span class="p"&gt;@$(&lt;/span&gt;MAKE&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-j3&lt;/span&gt; watch-air watch-templ watch-css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;make -jN&lt;/code&gt; option specifies the maximum number of commands that &lt;code&gt;make&lt;/code&gt; can run in parallel.&lt;/p&gt;

&lt;p&gt;Read more about &lt;code&gt;$(MAKE)&lt;/code&gt; here: &lt;a href="https://stackoverflow.com/questions/38978627/what-is-the-variable-make-in-a-makefile" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/38978627/what-is-the-variable-make-in-a-makefile&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just run &lt;code&gt;make watch&lt;/code&gt; and you’re good to go. Makefile just makes your development process much easier and more efficient. I hope you use Makefile in your project!&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>programming</category>
      <category>performance</category>
      <category>automation</category>
    </item>
    <item>
      <title>A Docker Trick I Wish I Knew Sooner</title>
      <dc:creator>Joy Biswas</dc:creator>
      <pubDate>Thu, 16 Oct 2025 05:04:06 +0000</pubDate>
      <link>https://forem.com/joybtw/a-docker-trick-i-wish-i-knew-sooner-23of</link>
      <guid>https://forem.com/joybtw/a-docker-trick-i-wish-i-knew-sooner-23of</guid>
      <description>&lt;p&gt;While building a Docker image recently, I needed to download a file using &lt;code&gt;curl&lt;/code&gt;. My first instinct was to install &lt;code&gt;curl&lt;/code&gt; in the container, make the request, and move on. But then I discovered Docker has a built-in way to handle this, and it's cleaner.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Old Way: Installing curl
&lt;/h2&gt;

&lt;p&gt;Here's what I was doing initially:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; alpine:latest&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apk add &lt;span class="nt"&gt;--no-cache&lt;/span&gt; curl
&lt;span class="k"&gt;RUN &lt;/span&gt;curl &lt;span class="nt"&gt;-sS&lt;/span&gt; https://example.com/somefile.txt &lt;span class="nt"&gt;-o&lt;/span&gt; /app/somefile.txt

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works, but it adds unnecessary bloat. You're installing &lt;code&gt;curl&lt;/code&gt; just to download a file, increasing your image size and adding an extra dependency you don't really need at runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Better Way: Using Docker's ADD Instruction
&lt;/h2&gt;

&lt;p&gt;Docker's &lt;code&gt;ADD&lt;/code&gt; instruction can fetch remote files directly without requiring &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;wget&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; alpine:latest&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="s"&gt; https://example.com/anotherfile.json /app/anotherfile.json&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Much simpler. No extra packages, no additional layers, and the intent is clearer. &lt;code&gt;ADD&lt;/code&gt; pulls the file at build time and places it exactly where you need it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Smaller Image Size
&lt;/h3&gt;

&lt;p&gt;Every package you install adds megabytes to your final image. Skipping &lt;code&gt;curl&lt;/code&gt; keeps things lean, especially important when you're optimizing for production or working with constrained environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fewer Dependencies
&lt;/h3&gt;

&lt;p&gt;Less tooling means fewer potential security vulnerabilities and a simpler dependency tree. Your container only contains what it actually needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cleaner Dockerfiles
&lt;/h3&gt;

&lt;p&gt;Using built-in instructions makes your Dockerfile more readable and idiomatic. Other developers (or future you) will immediately understand what's happening.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use Each Approach
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;ADD&lt;/code&gt;&lt;/strong&gt; when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're downloading a single file from a URL&lt;/li&gt;
&lt;li&gt;The file doesn't require authentication&lt;/li&gt;
&lt;li&gt;You want to keep your image minimal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Stick with &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;wget&lt;/code&gt;&lt;/strong&gt; when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need more control over the download (headers, authentication, retries)&lt;/li&gt;
&lt;li&gt;You're fetching multiple files in a complex workflow&lt;/li&gt;
&lt;li&gt;You need to process or validate the downloaded content before using it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Have you used &lt;code&gt;ADD&lt;/code&gt; for remote files before, or do you have other Docker tricks worth sharing?&lt;/strong&gt; Let me know in the comments! 😊&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>productivity</category>
    </item>
    <item>
      <title>My personal blog built with Go and React</title>
      <dc:creator>Joy Biswas</dc:creator>
      <pubDate>Thu, 16 Oct 2025 04:44:47 +0000</pubDate>
      <link>https://forem.com/joybtw/my-personal-blog-built-with-go-and-react-1pg7</link>
      <guid>https://forem.com/joybtw/my-personal-blog-built-with-go-and-react-1pg7</guid>
      <description>&lt;p&gt;For quite some time I wanted to change the look of my blog a bit.&lt;br&gt;
Changed a lot in this version. Made the Footer which is now StatusBar like Vim/Neovim style. Also changed the Header and instead of a typical header made a sidebar. Feels good man! 😊 &lt;br&gt;
Your feedback is appreciated!&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%2Fesj5g7n11n2iwqetpkwm.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%2Fesj5g7n11n2iwqetpkwm.png" alt="blog image" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Techstack:&lt;br&gt;
Backend: Go, Gin, Redis, PostgreSQL, Viper&lt;br&gt;
Frontend: React, TailwindCSS&lt;/p&gt;

&lt;p&gt;For Markdown rendering used: react-markdown and for syntax highlighting used: highlight.js.&lt;br&gt;
For Markdown editor used: react-md-editor&lt;/p&gt;

&lt;p&gt;Here's the &lt;a href="https://github.com/joybiswas007/blog" rel="noopener noreferrer"&gt;source code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>react</category>
      <category>programming</category>
      <category>docker</category>
    </item>
    <item>
      <title>Real-Time Server Monitoring with Go and WebSockets</title>
      <dc:creator>Joy Biswas</dc:creator>
      <pubDate>Mon, 06 Oct 2025 16:41:02 +0000</pubDate>
      <link>https://forem.com/joybtw/real-time-server-monitoring-with-go-and-websockets-23bj</link>
      <guid>https://forem.com/joybtw/real-time-server-monitoring-with-go-and-websockets-23bj</guid>
      <description>&lt;p&gt;For a long time I wanted to create a project with WebSocket but wasn't getting a good idea. One day I was checking my VPS's resources from htop. Then suddenly an idea popped in my mind: why not use WebSocket and do that remotely in real-time?&lt;/p&gt;

&lt;h3&gt;
  
  
  The Idea
&lt;/h3&gt;

&lt;p&gt;The concept is simple. Instead of SSHing into my server every time I want to check CPU usage, memory, or disk space, I could build a web dashboard that streams this information live. WebSockets make this perfect because they keep a persistent connection open, pushing updates to the browser without constant polling.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tech Stack
&lt;/h3&gt;

&lt;p&gt;As usual, I'm gonna use Go. For such a simple project, I used Go's standard &lt;code&gt;net/http&lt;/code&gt; library for the web server, &lt;code&gt;github.com/gorilla/websocket&lt;/code&gt; for WebSocket connections, and &lt;code&gt;github.com/shirou/gopsutil&lt;/code&gt; to fetch system metrics.&lt;/p&gt;

&lt;p&gt;The beauty of this stack is how lightweight it is. No heavy frameworks, no complex setup. Just three dependencies and you're good to go.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick note:&lt;/strong&gt; Yes, tools like Prometheus and Grafana already do this (and better). But where's the fun in that? This project is all about learning how these things work under the hood.&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;p&gt;The server does two main things. First, it serves a simple HTML page with CSS and JavaScript that connects to the WebSocket endpoint. Second, it collects system stats using gopsutil and pushes them through the WebSocket connection every second or so.&lt;/p&gt;

&lt;p&gt;On the backend, gopsutil makes it dead simple to grab CPU percentages, memory usage, disk space, and even network stats. The gorilla/websocket package handles the upgrade from HTTP to WebSocket and manages the connection lifecycle.&lt;/p&gt;

&lt;p&gt;The frontend is basic HTML, CSS and JavaScript. When the page loads, it establishes a WebSocket connection and listens for messages. Each message contains JSON data with the current system stats, which gets displayed in real-time on the page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why This Project Matters
&lt;/h3&gt;

&lt;p&gt;This might seem like a toy project, but it taught me some valuable concepts. I learned how WebSockets maintain stateful connections, how to handle concurrent clients in Go, and how to gather system metrics programmatically.&lt;/p&gt;

&lt;p&gt;Plus, it's actually useful. I can now check my server's health from any browser without needing SSH access. You could extend this to monitor multiple servers, add alerts when resources hit certain thresholds, or even create graphs showing resource usage over time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Themes
&lt;/h3&gt;

&lt;p&gt;The dashboard comes with five different visual styles to match your preference. Here's what each theme looks like:&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%2Fc8fumgcjwjt6c1k9u0pk.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%2Fc8fumgcjwjt6c1k9u0pk.png" alt="image" width="800" height="371"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm924z2sl9b6ifnb3ytdq.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%2Fm924z2sl9b6ifnb3ytdq.png" alt="image" width="800" height="373"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fotc2gx4wx174h14b3twx.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%2Fotc2gx4wx174h14b3twx.png" alt="image" width="800" height="364"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvjx0sht4teqysdefx6x9.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%2Fvjx0sht4teqysdefx6x9.png" alt="image" width="800" height="314"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy67gr602lexhk1fbqj11.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%2Fy67gr602lexhk1fbqj11.png" alt="image" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm not very good at designing UI, so it needs to be fixed a lot. If you're into frontend, feel free to contribute and make it look better.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;If you want to try it yourself, here's how:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repository:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git clone https://github.com/joybiswas007/res_mon.git
   &lt;span class="nb"&gt;cd &lt;/span&gt;res_mon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Install the dependencies:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   go mod tidy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Run the server:
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Open your browser and go to &lt;code&gt;http://localhost:8080&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The code is straightforward, so you can easily modify it to track different metrics or change how often updates are sent.&lt;/p&gt;

&lt;h3&gt;
  
  
  One More Thing...
&lt;/h3&gt;

&lt;p&gt;Oh, and I took the liberty to write a Dockerfile and docker-compose.yaml file. Was it necessary? Absolutely not. Could you just run &lt;code&gt;go run main.go&lt;/code&gt; and call it a day? Yes. Did I spend extra time containerizing a project that literally runs on a single command? Also yes.&lt;/p&gt;

</description>
      <category>go</category>
      <category>backend</category>
      <category>javascript</category>
      <category>api</category>
    </item>
    <item>
      <title>Beware of Bots Everywhere</title>
      <dc:creator>Joy Biswas</dc:creator>
      <pubDate>Sat, 04 Oct 2025 07:16:47 +0000</pubDate>
      <link>https://forem.com/joybtw/beware-of-bots-everywhere-g2a</link>
      <guid>https://forem.com/joybtw/beware-of-bots-everywhere-g2a</guid>
      <description>&lt;h3&gt;
  
  
  Beware of Bots Everywhere
&lt;/h3&gt;

&lt;p&gt;Everyone, watch out for bots. Writing code is important, but it's not enough. When you deploy an app, you must make sure it's secure. For example, secrets like &lt;strong&gt;API&lt;/strong&gt; keys should not leak. There are many stories about the high cost of leaked secret keys on Github.&lt;/p&gt;

&lt;p&gt;I check my blog logs every day. From the start, I noticed strange IP addresses. They tried to visit pages that do not exist. Some tried to grab environment variables. Others attempted to run weird commands. This shows why we need to think about security during every deployment. &lt;/p&gt;

&lt;p&gt;I host my blog on a VPS. I closed all ports except the ones I need. I also run the blog inside a Docker container for extra safety. These steps help block most threats.  Use firewall like &lt;strong&gt;UFW&lt;/strong&gt; to enforce port rules and keep everything updated.&lt;/p&gt;

&lt;p&gt;Here are some recent log images I captured. My server handles this kind of activity every 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%2F4voevt6wg63vyrkegto4.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%2F4voevt6wg63vyrkegto4.png" alt="image" width="800" height="541"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbkq7algyklhdss7p1gpx.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%2Fbkq7algyklhdss7p1gpx.png" alt="image" width="800" height="409"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkc319nzx5pjmim2eajl9.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%2Fkc319nzx5pjmim2eajl9.png" alt="image" width="800" height="540"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd76jr96f57uk7c66ntj8.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%2Fd76jr96f57uk7c66ntj8.png" alt="image" width="800" height="564"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stay vigilant with your setups. Simple habits like log checks and port controls can save you from big problems. Check your own logs today.&lt;/p&gt;

&lt;p&gt;Check out my blog's source code &lt;a href="https://github.com/joybiswas007/blog" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>containers</category>
      <category>go</category>
    </item>
    <item>
      <title>How I Stopped Worrying About RAM and Learned to Love Vim</title>
      <dc:creator>Joy Biswas</dc:creator>
      <pubDate>Mon, 29 Sep 2025 07:03:56 +0000</pubDate>
      <link>https://forem.com/joybtw/how-i-stopped-worrying-about-ram-and-learned-to-love-vim-2c07</link>
      <guid>https://forem.com/joybtw/how-i-stopped-worrying-about-ram-and-learned-to-love-vim-2c07</guid>
      <description>&lt;p&gt;That's right, both Vim and Neovim are now a part of my life. I love them both. Today's topic isn't about Vim vs. Neovim, I just wanted to share my experience with you all. I use Vim for all kinds of text editing and Neovim for coding&lt;/p&gt;

&lt;h2&gt;
  
  
  When It Started
&lt;/h2&gt;

&lt;p&gt;At the end of December 2024 and into early January 2025, I started learning Vim. Before that, Zed had just been released for Linux, so I installed it on my Manjaro device. After trying Zed for a few days, I found it really cool, it used less RAM than VSCode.&lt;/p&gt;

&lt;p&gt;Like everyone else, I began my development journey with VSCode. I saw people bragging about Vim and Neovim, and I noticed some developers typing incredibly fast. Seriously, just using the keyboard without ever touching the mouse, they were moving really fast! I was like, I have to learn this, and here I am.&lt;/p&gt;

&lt;h2&gt;
  
  
  RAM Usage
&lt;/h2&gt;

&lt;p&gt;This is how much RAM gets used when I open VSCode, Postman, and Chromium at the same time. The best part is, this is just when I write Go code. If I write JavaScript, the RAM usage in VSCode goes up even more.&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%2Fj1kycaa26dnqtxet0sa1.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%2Fj1kycaa26dnqtxet0sa1.png" alt="RAM usage screenshot" width="606" height="364"&gt;&lt;/a&gt; See VSCode almost uses 1.3 GB of RAM just when you open it, and when the project grows, the memory usage goes even higher. If you work with JavaScript projects, you'll notice RAM usage increases even more because of all the extra features and extensions running in the background. This is one reason I like using Vim and Neovim for coding, they are much lighter. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Learning Curve
&lt;/h2&gt;

&lt;p&gt;My first few days were rough. I kept forgetting how to exit, lost files, and fumbled through basic navigation. The modal editing system was a completely different mindset compared to traditional editors. It took a while to get used to switching between normal, insert, and visual modes. I relied heavily on cheat sheets and spent a lot of time on following tutorials. I'm still learning a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Customizing My Setup
&lt;/h2&gt;

&lt;p&gt;Once I got comfortable with the basics, I started tweaking my setup. If you're curious, you can check out my Neovim config file here: &lt;a href="https://github.com/joybiswas007/kickstart.nvim" rel="noopener noreferrer"&gt;joybiswas007/kickstart.nvim&lt;/a&gt;. I actually used a fork of the popular &lt;code&gt;kickstart.nvim&lt;/code&gt; starter template, which you can find at &lt;a href="https://github.com/nvim-lua/kickstart.nvim" rel="noopener noreferrer"&gt;nvim-lua/kickstart.nvim&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to learn Vim, I highly recommend checking out &lt;a href="https://github.com/iggredible/Learn-Vim" rel="noopener noreferrer"&gt;Learn Vim (the Smart Way)&lt;/a&gt;. It's a free, beginner-friendly guide that covers everything from the basics to advanced topics and is a great resource for both new and experienced users.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Vim and Neovim Changed My Workflow
&lt;/h2&gt;

&lt;p&gt;The biggest change? I barely touch the mouse now. Navigating between files, editing text, and running commands all happen from the keyboard. My workflow feels faster and more focused. Macros and registers are game changers for repetitive tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advice for Beginners
&lt;/h2&gt;

&lt;p&gt;If you’re thinking about trying Vim or Neovim, start small. Learn a few commands at a time and don’t get overwhelmed by all the possibilities. Use cheat sheets and practice regularly. Don’t be afraid to break things, messing up is part of the learning process. And remember, customizing your setup can make the experience a lot more enjoyable.&lt;/p&gt;

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

&lt;p&gt;Looking back, I’m happy I tried Vim and Neovim. They’ve helped me code better and faster. I’m still learning new things, and that keeps it interesting. If you’re unsure about trying them, just go for it, you might end up liking them more than you expect.&lt;/p&gt;

</description>
      <category>vim</category>
      <category>neovim</category>
    </item>
    <item>
      <title>Why I Stopped Using go mod download in My Dockerfile</title>
      <dc:creator>Joy Biswas</dc:creator>
      <pubDate>Mon, 29 Sep 2025 07:01:47 +0000</pubDate>
      <link>https://forem.com/joybtw/why-i-stopped-using-go-mod-download-in-my-dockerfile-59o9</link>
      <guid>https://forem.com/joybtw/why-i-stopped-using-go-mod-download-in-my-dockerfile-59o9</guid>
      <description>&lt;p&gt;Using &lt;code&gt;go mod download&lt;/code&gt; inside your Dockerfile can significantly slow down your image build process. Each time you rebuild the image, all Go modules are downloaded again, making the process inefficient, especially during local development when rebuilds are frequent and can take a long time.&lt;/p&gt;

&lt;p&gt;While working on the Dockerfile for running my blog inside a Docker container, I encountered this issue firsthand. Every time I made changes and rebuilt the image, Go modules were re-downloaded repeatedly. It quickly became time consuming and frustrating.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;So, how did I solve this? The answer was simple: I used &lt;a href="https://docs.docker.com/build/cache/" rel="noopener noreferrer"&gt;Docker's build cache&lt;/a&gt;. After making the changes, the build times were noticeably reduced, and I could clearly see the improvement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dockerfile
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;With caching (fast):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Set Go proxy to direct (optional)&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; GOPROXY=direct&lt;/span&gt;

&lt;span class="c"&gt;# Copy Go mod files and download dependencies&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; go.mod go.sum ./&lt;/span&gt;

&lt;span class="c"&gt;# Set cache directories&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; GOCACHE=/go-cache&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; GOMODCACHE=/gomod-cache&lt;/span&gt;

&lt;span class="c"&gt;# Complete other tasks&lt;/span&gt;
...

# Build statically linked, optimized binary
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nt"&gt;--mount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cache,target&lt;span class="o"&gt;=&lt;/span&gt;/gomod-cache &lt;span class="nt"&gt;--mount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cache,target&lt;span class="o"&gt;=&lt;/span&gt;/go-cache &lt;span class="se"&gt;\
&lt;/span&gt;    go build &lt;span class="nt"&gt;-o&lt;/span&gt; binary main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;&lt;strong&gt;Without caching (slow):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Copy Go mod files and download dependencies&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; go.mod go.sum ./&lt;/span&gt;

&lt;span class="c"&gt;# Download Go modules&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;go mod download

&lt;span class="c"&gt;# Build the Go binary&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;go build &lt;span class="nt"&gt;-o&lt;/span&gt; binary main.go

&lt;span class="c"&gt;# Complete other tasks&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;&lt;code&gt;go mod download&lt;/code&gt; keeps running until it encounters an error or is manually stopped.&lt;/p&gt;

&lt;p&gt;You can check out the final Dockerfile &lt;a href="https://github.com/joybiswas007/blog/blob/main/Dockerfile" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>go</category>
    </item>
    <item>
      <title>Arch Installation Guide</title>
      <dc:creator>Joy Biswas</dc:creator>
      <pubDate>Mon, 29 Sep 2025 07:01:11 +0000</pubDate>
      <link>https://forem.com/joybtw/arch-installation-guide-7bj</link>
      <guid>https://forem.com/joybtw/arch-installation-guide-7bj</guid>
      <description>&lt;h1&gt;
  
  
  Table of Contents
&lt;/h1&gt;

&lt;p&gt;This is a minimal guide to install &lt;strong&gt;Arch Linux&lt;/strong&gt;. I used these steps to install &lt;strong&gt;Arch Linux&lt;/strong&gt; on my device. I hope this guide will help you guys. So, let's begin right away!&lt;/p&gt;

&lt;p&gt;If you are reading this guide, then I assume you are already booted into Arch and following these steps. I've used &lt;code&gt;nano&lt;/code&gt; as a text editor during the installation, but you can use any text editor you like: &lt;code&gt;nano&lt;/code&gt;, &lt;code&gt;vim&lt;/code&gt;, &lt;code&gt;vi&lt;/code&gt; etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  ToC
&lt;/h3&gt;




&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;No.&lt;/th&gt;
&lt;th&gt;Topic&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Pre-installation&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Verify signature&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Connect to the internet&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Update the system clock&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Partition the disks&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Format the partitions&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Mount the file systems&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Install essential packages&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Configure the system&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Chroot&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Time zone&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Localization&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Network configuration&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Initramfs&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Root password&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Post-installation&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Pre-installation
&lt;/h3&gt;

&lt;p&gt;Grab the Arch Linux ISO file from their &lt;a href="https://archlinux.org/download/" rel="noopener noreferrer"&gt;Download&lt;/a&gt; page and boot your USB drive with any bootable software you like. I've used &lt;a href="https://www.balena.io/etcher/" rel="noopener noreferrer"&gt;Balena Etcher&lt;/a&gt; in this tutorial.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verify signature
&lt;/h3&gt;

&lt;p&gt;It is recommended to verify the image signature before use, especially when downloading from an HTTP mirror, where downloads are generally prone to be intercepted to serve malicious images&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gpg &lt;span class="nt"&gt;--keyserver-options&lt;/span&gt; auto-key-retrieve &lt;span class="nt"&gt;--verify&lt;/span&gt; archlinux-version-x86_64.iso.sig
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, from an existing Arch Linux installation run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pacman-key &lt;span class="nt"&gt;-v&lt;/span&gt; archlinux-version-x86_64.iso.sig
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Connect to the internet
&lt;/h3&gt;

&lt;p&gt;Ensure your &lt;a href="https://wiki.archlinux.org/title/Network_interface" rel="noopener noreferrer"&gt;network interface&lt;/a&gt; is listed and enabled, for example with &lt;a href="https://man.archlinux.org/man/ip-link.8" rel="noopener noreferrer"&gt;ip-link(8)&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ip &lt;span class="nb"&gt;link&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the connection with &lt;a href="https://en.wikipedia.org/wiki/ping_(networking_utility)" rel="noopener noreferrer"&gt;ping&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ping archlinux.org
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or make sure your device is connected to the Internet with Ethernet Cable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update the system clock
&lt;/h3&gt;

&lt;p&gt;Use &lt;a href="https://man.archlinux.org/man/timedatectl.1" rel="noopener noreferrer"&gt;timedatectl(1)&lt;/a&gt; to ensure the system clock is accurate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;timedatectl set-ntp &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To check the service status, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;timedatectl status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Partition the disks
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;cfdisk&lt;/code&gt; to partition the disk. We'll be using &lt;code&gt;cfdisk&lt;/code&gt; in this guide. It's super easy to partition the disks with &lt;code&gt;cfdisk&lt;/code&gt;. Seriously! Try it once.&lt;/p&gt;

&lt;h3&gt;
  
  
  Format the partitions
&lt;/h3&gt;

&lt;p&gt;As you are done making partitions, now let's format them to make them usable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mkfs.ext4 /dev/root_partition
mkfs.fat &lt;span class="nt"&gt;-F32&lt;/span&gt; /dev/efi_system_partition
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you created an &lt;a href="https://wiki.archlinux.org/title/EFI_system_partition#Format_the_partition" rel="noopener noreferrer"&gt;EFI system partition&lt;/a&gt;, format it to FAT32 using &lt;a href="https://man.archlinux.org/man/mkfs.fat.8" rel="noopener noreferrer"&gt;mkfs.fat(8)&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mkswap /dev/swap_partition
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mount the file systems
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mount /dev/root_partition /mnt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's create some directory inside the /mnt partition to mount the efi system.&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;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /mnt/boot/efi
&lt;span class="nb"&gt;mkdir&lt;/span&gt; /mnt/home
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now mount the EFI system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mount /dev/sda1 /mnt/boot/efi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you created a &lt;a href="https://wiki.archlinux.org/title/Swap" rel="noopener noreferrer"&gt;swap&lt;/a&gt; volume, enable it with &lt;a href="https://man.archlinux.org/man/swapon.8" rel="noopener noreferrer"&gt;swapon(8)&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;swapon /dev/swap_partition
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Select the mirrors
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Packages to be installed must be downloaded from &lt;a href="https://wiki.archlinux.org/title/Mirrors" rel="noopener noreferrer"&gt;mirror&lt;/a&gt; servers, which are defined in &lt;code&gt;/etc/pacman.d/mirrorlist&lt;/code&gt;. On the live system, after connecting to the internet, reflector updates the mirror list by choosing 20 most recently synchronized HTTPS mirrors and sorting them by download rate.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The higher a mirror is placed in the list, the more priority it is given when downloading a package. You may want to inspect the file to see if it is satisfactory. If it is not, edit the file accordingly, and move the geographically closest mirrors to the top of the list, although other criteria should be taken into account.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;This file will later be copied to the new system by pacstrap, so it is worth getting right.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Install essential packages
&lt;/h3&gt;

&lt;p&gt;Use the &lt;a href="https://man.archlinux.org/man/pacstrap.8" rel="noopener noreferrer"&gt;pacstrap(8)&lt;/a&gt; script to install the &lt;a href="https://archlinux.org/packages/?name=base" rel="noopener noreferrer"&gt;base&lt;/a&gt; package, Linux &lt;a href="https://wiki.archlinux.org/title/Kernel" rel="noopener noreferrer"&gt;kernel&lt;/a&gt; and firmware for common hardware:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pacstrap /mnt base linux linux-firmware vim nano linux-headers base-devel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Tip:&lt;br&gt;
You can substitute linux for a kernel package of your choice, or you could omit it entirely when installing in a container.&lt;/p&gt;

&lt;p&gt;You could omit the installation of the firmware package when installing in a virtual machine or container.&lt;/p&gt;

&lt;p&gt;The base package does not include all tools from the live installation, so installing other packages may be necessary for a fully functional base system. In particular, consider installing:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Configure the system
&lt;/h3&gt;

&lt;p&gt;Generate an &lt;a href="https://wiki.archlinux.org/title/Fstab" rel="noopener noreferrer"&gt;fstab&lt;/a&gt; file (use -U or -L to define by &lt;a href="https://wiki.archlinux.org/title/UUID" rel="noopener noreferrer"&gt;UUID&lt;/a&gt; or labels, respectively):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;genfstab &lt;span class="nt"&gt;-U&lt;/span&gt; /mnt &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /mnt/etc/fstab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the resulting &lt;code&gt;/mnt/etc/fstab file&lt;/code&gt;, and &lt;a href="https://wiki.archlinux.org/title/Textedit" rel="noopener noreferrer"&gt;edit&lt;/a&gt; it in case of errors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chroot
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://wiki.archlinux.org/title/Change_root" rel="noopener noreferrer"&gt;Change root&lt;/a&gt; into the new system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;arch-chroot /mnt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now let's install some necessary packages which we need to complete the install process
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pacman &lt;span class="nt"&gt;-S&lt;/span&gt; grub efibootmgr efivar networkmanager intel-ucode amd-ucode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;if you device is support Intel microcode then install &lt;code&gt;intel-ucode&lt;/code&gt; or if you device support AMD micorcode then install &lt;code&gt;amd-ucode&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Time zone
&lt;/h3&gt;

&lt;p&gt;Set the &lt;a href="https://wiki.archlinux.org/title/System_time#Time_zone" rel="noopener noreferrer"&gt;time zone&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-sf&lt;/span&gt; /usr/share/zoneinfo/Region/City /etc/localtime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change the Region &amp;amp; City according to your location.&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;ln&lt;/span&gt; &lt;span class="nt"&gt;-sf&lt;/span&gt; /usr/share/zoneinfo/Asia/Dhaka /etc/localtime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or check all the available regions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /usr/share/zoneinfo &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Select the one you need.&lt;/p&gt;

&lt;p&gt;Run &lt;a href="https://man.archlinux.org/man/hwclock.8" rel="noopener noreferrer"&gt;hwclock(8)&lt;/a&gt; to generate &lt;code&gt;/etc/adjtime&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hwclock &lt;span class="nt"&gt;--systohc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Localization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create the locale.conf(5) file, and &lt;a href="https://wiki.archlinux.org/title/Locale#Setting_the_system_locale" rel="noopener noreferrer"&gt;set the LANG variable&lt;/a&gt; accordingly:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano /etc/locale.conf 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enter the followings in locale.conf file&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="nv"&gt;LANG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;en_US.UTF-8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit &lt;code&gt;/etc/locale.gen&lt;/code&gt; and uncomment &lt;code&gt;en_US.UTF-8 UTF-8&lt;/code&gt; and other needed locales. Generate the locales by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;locale-gen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Network configuration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create the hostname file:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano /etc/hostname
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit &lt;code&gt;/etc/hostname&lt;/code&gt; and add this line:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Alternatively, Using &lt;a href="https://man.archlinux.org/man/hostnamectl.1" rel="noopener noreferrer"&gt;hostnamectl(1)&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hostnamectl set-hostname myhostname
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Some software may however still read &lt;code&gt;/etc/hosts&lt;/code&gt; directly. To prevent them from potentially breaking or delaying operation, configure the &lt;code&gt;hosts(5)&lt;/code&gt; file:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano /etc/hosts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;127.0.0.1   localhost
::1     localhost
127.0.1.1   myhostname
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Complete the &lt;a href="https://wiki.archlinux.org/title/Network_configuration" rel="noopener noreferrer"&gt;network configuration&lt;/a&gt; for the newly installed environment. That may include installing suitable &lt;a href="https://wiki.archlinux.org/title/Network_management" rel="noopener noreferrer"&gt;network management&lt;/a&gt; software.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initramfs
&lt;/h3&gt;

&lt;p&gt;Creating a new initramfs is usually not required, because &lt;a href="https://wiki.archlinux.org/title/Mkinitcpio" rel="noopener noreferrer"&gt;mkinitcpio&lt;/a&gt; is run automatically during the kernel package installation.&lt;/p&gt;

&lt;p&gt;For &lt;a href="https://wiki.archlinux.org/title/Install_Arch_Linux_on_LVM#Adding_mkinitcpio_hooks" rel="noopener noreferrer"&gt;LVM&lt;/a&gt;, &lt;a href="https://wiki.archlinux.org/title/Dm-crypt" rel="noopener noreferrer"&gt;system encryption&lt;/a&gt;, or &lt;a href="https://wiki.archlinux.org/title/RAID#Configure_mkinitcpio" rel="noopener noreferrer"&gt;RAID&lt;/a&gt;, modify &lt;a href="https://man.archlinux.org/man/mkinitcpio.conf.5" rel="noopener noreferrer"&gt;mkinitcpio.conf(5)&lt;/a&gt; and regenerate the initramfs image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mkinitcpio &lt;span class="nt"&gt;-P&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Root password
&lt;/h3&gt;

&lt;p&gt;Set the root password:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install GRUB bootloader
&lt;/h3&gt;

&lt;p&gt;Install GRUB in the EFI directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;grub-install &lt;span class="nt"&gt;--target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;x86_64-efi &lt;span class="nt"&gt;--efi-directory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/boot/efi &lt;span class="nt"&gt;--bootloader-id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;GRUB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generate the GRUB configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;grub-mkconfig &lt;span class="nt"&gt;-o&lt;/span&gt; /boot/grub/grub.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enable NetworkManager
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;NetworkManager
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Exit chroot
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Unmount
&lt;/h3&gt;

&lt;p&gt;Unmount all partitions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;umount &lt;span class="nt"&gt;-R&lt;/span&gt; /mnt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Optionally, use &lt;code&gt;fuser&lt;/code&gt; to identify any busy partitions before unmounting.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Reboot
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;If you see the login screen, congratulations—you've successfully installed &lt;strong&gt;Arch Linux&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Username:&lt;/strong&gt; &lt;code&gt;root&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Password:&lt;/strong&gt; &lt;code&gt;YourRootPassword&lt;/code&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Post-installation
&lt;/h3&gt;

&lt;p&gt;A new installation only includes the root account. It is best to create an unprivileged user account for daily use.&lt;/p&gt;

&lt;p&gt;Create a new user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;useradd &lt;span class="nt"&gt;--create-home&lt;/span&gt; myuser
passwd myuser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the user to common groups:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; wheel,users,power,storage myuser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable sudo access for your user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano /etc/sudoers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uncomment the following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;%wheel &lt;span class="nv"&gt;ALL&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;ALL&lt;span class="o"&gt;)&lt;/span&gt; ALL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install GUI
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Xorg (Display Server)
&lt;/h4&gt;

&lt;p&gt;Install Xorg:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pacman &lt;span class="nt"&gt;-S&lt;/span&gt; xorg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install some basic fonts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pacman &lt;span class="nt"&gt;-S&lt;/span&gt; ttf-dejavu ttf-droid ttf-font-awesome otf-font-awesome ttf-lato ttf-liberation ttf-opensans ttf-ubuntu-font-family
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit FreeType configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano /etc/profile.d/freetype2.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uncomment this line:&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;export &lt;/span&gt;&lt;span class="nv"&gt;FREETYPE_PROPERTIES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"truetype:interpreter-version=40"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  KDE Desktop Environment
&lt;/h3&gt;

&lt;p&gt;Install KDE and SDDM (Display Manager):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pacman &lt;span class="nt"&gt;-S&lt;/span&gt; sddm plasma
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Optional) Install all KDE applications:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pacman &lt;span class="nt"&gt;-S&lt;/span&gt; kde-applications
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable and start the display manager:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;sddm.service
systemctl start sddm.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;And you're done! Enjoy your &lt;strong&gt;Arch Linux&lt;/strong&gt; setup.&lt;/p&gt;

&lt;p&gt;Here is the &lt;a href="https://wiki.archlinux.org/title/installation_guide" rel="noopener noreferrer"&gt;Official Arch Linux Install Guide&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>archlinux</category>
      <category>linux</category>
    </item>
    <item>
      <title>The Effect of AI on Me</title>
      <dc:creator>Joy Biswas</dc:creator>
      <pubDate>Mon, 29 Sep 2025 07:00:26 +0000</pubDate>
      <link>https://forem.com/joybtw/the-effect-of-ai-on-me-26b5</link>
      <guid>https://forem.com/joybtw/the-effect-of-ai-on-me-26b5</guid>
      <description>&lt;p&gt;I don't know why, but when I try to learn frontend development, I don't find it as exciting as backend or Linux related topics. I understand React, but my real struggle is UI design, I'm just not good at it. With backend projects, I can read documentation, follow tutorials, and build things. But design? Remember that meme about backend developers who can't center a &lt;code&gt;div&lt;/code&gt;? That's me.&lt;/p&gt;

&lt;h2&gt;
  
  
  My AI Experiment
&lt;/h2&gt;

&lt;p&gt;While building the dashboard with React and TailwindCSS for this blog, I hit a wall with design. So I thought: &lt;em&gt;Let's try AI!&lt;/em&gt; What followed was 2-3 days of frustration.&lt;/p&gt;

&lt;p&gt;My first prompt: "Create a React login component." The result? A stark white screen with basic inputs, zero creativity. I refined my request, but the AI kept producing similar uninspired designs. And you can also guess what happened with the other components and how many times I had to re-run the prompt to redesign the dashboard. That's when I realized: &lt;strong&gt;AI needs precise prompting&lt;/strong&gt;, and even then, its creativity is limited.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Dependency Trap
&lt;/h2&gt;

&lt;p&gt;What started as a helper became a crutch. I began using AI (ChatGPT, Gemini, Copilot) for everything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple text changes I could make in seconds&lt;/li&gt;
&lt;li&gt;Basic layout fixes&lt;/li&gt;
&lt;li&gt;Errors I could've solved with a quick Google search&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The scary part? &lt;strong&gt;The more I used AI for trivial tasks, the harder it became to think independently&lt;/strong&gt;. Like slow poison, reliance crept in:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Immediate solutions felt convenient&lt;/li&gt;
&lt;li&gt;My problem-solving muscles weakened&lt;/li&gt;
&lt;li&gt;I grew impatient with manual work&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AI is a tool, not a replacement&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
It can't replicate human creativity in design&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The prompt matters&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
"Make a beautiful login page" ≠ effective instruction&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Overuse harms growth&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If you delegate thinking, you stop learning&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Those 2-3 days taught me: &lt;strong&gt;Use AI to enhance skills, not avoid developing them&lt;/strong&gt;. &lt;/p&gt;

</description>
      <category>ai</category>
    </item>
  </channel>
</rss>
