<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Frastyawan Nym</title>
    <description>The latest articles on DEV Community by Frastyawan Nym (@frasnym).</description>
    <link>https://dev.to/frasnym</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%2F576342%2F59e69919-6ff3-4067-9aaf-44eb08901cd9.jpg</url>
      <title>DEV Community: Frastyawan Nym</title>
      <link>https://dev.to/frasnym</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/frasnym"/>
    <language>en</language>
    <item>
      <title>Create Local MySQL using Docker Run</title>
      <dc:creator>Frastyawan Nym</dc:creator>
      <pubDate>Fri, 22 Mar 2024 02:39:19 +0000</pubDate>
      <link>https://dev.to/frasnym/create-local-mysql-using-docker-run-pkp</link>
      <guid>https://dev.to/frasnym/create-local-mysql-using-docker-run-pkp</guid>
      <description>&lt;p&gt;This is just a rant writing. Because how difficult tutorial out there just to setup this kind of thing. So I'm here to summarize for you (reader) how to get it done.&lt;/p&gt;

&lt;p&gt;Simple! Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--name&lt;/span&gt; mysql-local &lt;span class="nt"&gt;-p&lt;/span&gt; 3306:3306 &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;admin &lt;span class="nt"&gt;-d&lt;/span&gt; mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mysql-local&lt;/code&gt;: Your container name, feel free to change it.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-p 3306:3306&lt;/code&gt;: Expose container to localhost, so we can connect with UI (ex: DBeaver).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-e MYSQL_ROOT_PASSWORD=admin&lt;/code&gt;: &lt;code&gt;root&lt;/code&gt; user password, adjust with your preference.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-d&lt;/code&gt;: Detach mode&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mysql&lt;/code&gt;: Image name&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This will automatically pull the image if not pulled yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting into interface (or else)
&lt;/h2&gt;

&lt;p&gt;After this, maybe you need to access via UI. Here is the setting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Host: localhost&lt;/li&gt;
&lt;li&gt;Port: 3306&lt;/li&gt;
&lt;li&gt;User: root&lt;/li&gt;
&lt;li&gt;Password: admin&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Maybe you will need this
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;When connecting, maybe you will get error &lt;code&gt;Public Key Retrieval is not allowed&lt;/code&gt;. If you are using DBeaver, search for driver properties/setting. Change &lt;code&gt;allowPublicKeyRetrieval = true&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;That it and Thank You.&lt;/p&gt;

</description>
      <category>mysql</category>
      <category>docker</category>
    </item>
    <item>
      <title>Boost Your Golang Skills: Writing Large Data Files for Performance</title>
      <dc:creator>Frastyawan Nym</dc:creator>
      <pubDate>Fri, 15 Sep 2023 06:46:47 +0000</pubDate>
      <link>https://dev.to/frasnym/boost-your-golang-skills-writing-large-data-files-for-performance-297m</link>
      <guid>https://dev.to/frasnym/boost-your-golang-skills-writing-large-data-files-for-performance-297m</guid>
      <description>&lt;p&gt;Golang, known for its simplicity and performance, offers various ways to tackle tasks efficiently. As a beginner developer, you might be wondering how to write large data into files effectively. In this beginner-friendly guide, we'll explore three key methods: Sequential, Parallel, and Parallel Chunk. We'll break down the concepts, provide easy-to-understand code samples, and offer practical advice to help you get started. Let's embark on this coding journey! 📝&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction 🎉
&lt;/h2&gt;

&lt;p&gt;Before we dive into these methods, let's start with some basics. File handling in Golang is essential for tasks like saving user data, generating reports, or storing logs. Imagine it as managing a virtual filing cabinet where you can add, retrieve, and organize information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Concepts 🧠
&lt;/h3&gt;

&lt;p&gt;Golang, with its goroutines (lightweight threads), allows you to perform tasks concurrently, making it perfect for efficient file writing. Why does efficient file writing matter? Well, it can significantly impact the performance of your applications, ensuring they run smoothly.&lt;/p&gt;

&lt;p&gt;Now, let's explore the three methods with simplified explanations, easy-to-follow code, and practical examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sequential File Writer 📜
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is Sequential Writing?&lt;/strong&gt;&lt;br&gt;
Sequential file writing is like writing a story from start to finish, one sentence at a time. It's straightforward and easy to understand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to Use it?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use sequential writing when you're just starting, and simplicity is crucial.&lt;/li&gt;
&lt;li&gt;Ideal for smaller datasets that don't require super-fast write speeds.&lt;/li&gt;
&lt;li&gt;Great for scenarios where data order is essential.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simplicity: It's easy to implement, perfect for beginners.&lt;/li&gt;
&lt;li&gt;Data Integrity: Maintains the order of data, making it reliable.&lt;/li&gt;
&lt;li&gt;Low Resource Usage: Doesn't require much memory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slower for large datasets.&lt;/li&gt;
&lt;li&gt;Not the best choice for blazing-fast writes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Code Sample and Explanation:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/frasnym/go-file-writer-example/blob/main/filewriter/sequential/sequential.go"&gt;filewriter/sequential/sequential.go&lt;/a&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;sequential&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;"github.com/frasnym/go-file-writer-example/filewriter"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// SequentialFileWriter represents a writer for sequential file operations.&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;sequentialFileWriter&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fileWriter&lt;/span&gt; &lt;span class="n"&gt;filewriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileWriter&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// NewSequentialFileWriter creates a new instance of SequentialFileWriter.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewSequentialFileWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt; &lt;span class="n"&gt;filewriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileWriter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;filewriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sequentialFileWriter&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Write writes the specified number of lines to the file sequentially.&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;w&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sequentialFileWriter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;totalLines&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Create the output file&lt;/span&gt;
    &lt;span class="n"&gt;file&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;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&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;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileClose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewBufferedWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&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;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;totalLines&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&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;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This is a line of data %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;i&lt;/span&gt;&lt;span class="p"&gt;)&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;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BufferedWriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&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="k"&gt;return&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;// Flush the buffer to ensure all data is written to the file.&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;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BufferedFlush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code sample, we've created a sequential file writer that writes lines of data sequentially to a file. Here's what's happening step by step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We create a new instance of &lt;code&gt;sequentialFileWriter&lt;/code&gt; using &lt;code&gt;NewSequentialFileWriter&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Write&lt;/code&gt; method takes the total number of lines to write and the filename.&lt;/li&gt;
&lt;li&gt;We create the output file using &lt;code&gt;w.fileWriter.CreateFile(filename)&lt;/code&gt; and defer its closure.&lt;/li&gt;
&lt;li&gt;To optimize writing, we use a buffered writer created with &lt;code&gt;w.fileWriter.NewBufferedWriter&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Inside a loop, we generate data for each line and write it using &lt;code&gt;w.fileWriter.BufferedWriteString&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;After writing all the lines, we ensure all data is flushed to the file with &lt;code&gt;w.fileWriter.BufferedFlush&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This code demonstrates how to write data sequentially to a file while maintaining data integrity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parallel File Writer 🚀
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is Parallel Writing?&lt;/strong&gt;&lt;br&gt;
Parallel writing is like having multiple authors working on different parts of a book at the same time. It speeds up the process significantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to Use it?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Utilize parallel writing when dealing with large datasets that need to be written quickly.&lt;/li&gt;
&lt;li&gt;Ideal for scenarios where write speed is a top priority.&lt;/li&gt;
&lt;li&gt;When your system can efficiently manage concurrent writes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speed: Greatly improves write speed, especially for large datasets.&lt;/li&gt;
&lt;li&gt;Efficiency: Efficiently utilizes system resources.&lt;/li&gt;
&lt;li&gt;Scalability: Scales well with the number of cores or goroutines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A bit more complex to implement than sequential writing.&lt;/li&gt;
&lt;li&gt;Data order might not be guaranteed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Code Sample and Explanation:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/frasnym/go-file-writer-example/blob/main/filewriter/parallel/parallel.go"&gt;filewriter/parallel/parallel.go&lt;/a&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;parallel&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;"os"&lt;/span&gt;
    &lt;span class="s"&gt;"runtime"&lt;/span&gt;
    &lt;span class="s"&gt;"sync"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/frasnym/go-file-writer-example/filewriter"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;parallelFileWriter&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fileWriter&lt;/span&gt;    &lt;span class="n"&gt;filewriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileWriter&lt;/span&gt;
    &lt;span class="n"&gt;maxGoRoutines&lt;/span&gt; &lt;span class="kt"&gt;int&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;NewParallelFileWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt; &lt;span class="n"&gt;filewriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileWriter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;filewriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Get the number of available CPU cores&lt;/span&gt;
    &lt;span class="n"&gt;maxGoRoutines&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GOMAXPROCS&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="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;parallelFileWriter&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;maxGoRoutines&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;maxGoRoutines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;parallelFileWriter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;totalLines&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Create the output file&lt;/span&gt;
    &lt;span class="n"&gt;file&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;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&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;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileClose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Calculate the number of lines to be written by each worker&lt;/span&gt;
    &lt;span class="n"&gt;linesPerTask&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;totalLines&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maxGoRoutines&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;errCh&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maxGoRoutines&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;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maxGoRoutines&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;linesPerTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errCh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Close the error channel when all workers are done&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;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="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errCh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="c"&gt;// Collect and handle errors&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;err&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;errCh&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="k"&gt;return&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;return&lt;/span&gt; &lt;span class="no"&gt;nil&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="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;parallelFileWriter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;File&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;sync&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;linesPerTask&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errCh&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;error&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;startLine&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;linesPerTask&lt;/span&gt;
    &lt;span class="n"&gt;endLine&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;startLine&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;linesPerTask&lt;/span&gt;

    &lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewBufferedWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&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;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;startLine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;endLine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&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;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This is a line of data %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;i&lt;/span&gt;&lt;span class="p"&gt;)&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;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BufferedWriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&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;errCh&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BufferedFlush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code sample, we've created a parallel file writer that takes advantage of multiple goroutines to write lines of data concurrently to a file. Here's what's happening step by step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We create a new instance of &lt;code&gt;parallelFileWriter&lt;/code&gt; using &lt;code&gt;NewParallelFileWriter&lt;/code&gt;. It determines the number of CPU cores available to decide how many goroutines to use.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Write&lt;/code&gt; method takes the total number of lines to write and the filename.&lt;/li&gt;
&lt;li&gt;We create the output file using &lt;code&gt;w.fileWriter.CreateFile(filename)&lt;/code&gt; and defer its closure.&lt;/li&gt;
&lt;li&gt;To optimize writing, we calculate the number of lines each worker should write based on the total number of lines and the available CPU cores.&lt;/li&gt;
&lt;li&gt;We use a &lt;code&gt;sync.WaitGroup&lt;/code&gt; to wait for all workers to complete their tasks and an error channel to collect and handle errors.&lt;/li&gt;
&lt;li&gt;Inside a loop, we spawn multiple goroutines, each assigned to a worker function &lt;code&gt;w.worker&lt;/code&gt;. These workers write their respective lines concurrently.&lt;/li&gt;
&lt;li&gt;The worker function calculates the range of lines it's responsible for and writes data to the file using a buffered writer.&lt;/li&gt;
&lt;li&gt;Once all workers are done, we close the error channel and collect and handle any errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This code demonstrates how to harness the power of parallelism to write data concurrently to a file, improving write speed significantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parallel Chunk File Writer 🧩
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is Parallel Chunk Writing?&lt;/strong&gt;&lt;br&gt;
Think of it as writing chapters of a book in parallel while maintaining the order within each chapter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to Use it?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose parallel chunk writing for large datasets when both speed and data order are crucial.&lt;/li&gt;
&lt;li&gt;Especially suitable when dealing with structured data that can be divided into chunks.&lt;/li&gt;
&lt;li&gt;When your system can efficiently manage concurrent writes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speed: Offers a significant speed boost for large datasets.&lt;/li&gt;
&lt;li&gt;Data Order: Maintains data order within each chunk.&lt;/li&gt;
&lt;li&gt;Scalability: Scales well with the number of cores or goroutines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A bit more complex to implement than sequential writing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Code Sample and Explanation:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/frasnym/go-file-writer-example/blob/main/filewriter/parallelchunk/parallelchunk.go"&gt;filewriter/parallelchunk/parallelchunk.go&lt;/a&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;parallelchunk&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;"runtime"&lt;/span&gt;
    &lt;span class="s"&gt;"sync"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/frasnym/go-file-writer-example/filewriter"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;parallelChunkFileWriter&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fileWriter&lt;/span&gt;    &lt;span class="n"&gt;filewriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileWriter&lt;/span&gt;
    &lt;span class="n"&gt;maxGoRoutines&lt;/span&gt; &lt;span class="kt"&gt;int&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;NewParallelChunkFileWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt; &lt;span class="n"&gt;filewriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileWriter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;filewriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Get the number of available CPU cores&lt;/span&gt;
    &lt;span class="n"&gt;maxGoRoutines&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GOMAXPROCS&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="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;parallelChunkFileWriter&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;maxGoRoutines&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;maxGoRoutines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;parallelChunkFileWriter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;totalLines&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;chunkSize&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;totalLines&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maxGoRoutines&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maxGoRoutines&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;startLine&lt;/span&gt; &lt;span class="o"&gt;:=&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;chunkSize&lt;/span&gt;
        &lt;span class="n"&gt;endLine&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;startLine&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;chunkSize&lt;/span&gt;

        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writeChunkToFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startLine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endLine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;wg&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="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&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="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;parallelChunkFileWriter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;writeChunkToFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startLine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endLine&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="kt"&gt;string&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;sync&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;file&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;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateFile&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;Sprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&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;startLine&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&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;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileClose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewBufferedWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&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;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;startLine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;endLine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&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;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This is a line of data %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;i&lt;/span&gt;&lt;span class="p"&gt;)&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;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BufferedWriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&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="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileWriter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BufferedFlush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code sample, we've created a parallel chunk file writer that divides data into smaller chunks and writes them concurrently to a file while maintaining data order within each chunk. Here's what's happening step by step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We create a new instance of &lt;code&gt;parallelChunkFileWriter&lt;/code&gt; using &lt;code&gt;NewParallelChunkFileWriter&lt;/code&gt;. It determines the number of CPU cores available to decide how many goroutines to use.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Write&lt;/code&gt; method takes the total number of lines to write and the filename.&lt;/li&gt;
&lt;li&gt;To optimize writing, we calculate the number of lines each worker should write based on the total number of lines and the available CPU cores.&lt;/li&gt;
&lt;li&gt;We use a &lt;code&gt;sync.WaitGroup&lt;/code&gt; to wait for all workers to complete their tasks.&lt;/li&gt;
&lt;li&gt;Inside a loop, we spawn multiple goroutines, each assigned to a worker function &lt;code&gt;w.writeChunkToFile&lt;/code&gt;. These workers write their respective chunks of lines concurrently while maintaining data order within each chunk.&lt;/li&gt;
&lt;li&gt;The worker create the output file using &lt;code&gt;w.fileWriter.CreateFile(filename)&lt;/code&gt; and defer its closure.&lt;/li&gt;
&lt;li&gt;The worker function calculates the range of lines it's responsible for and writes data to the file using a buffered writer.&lt;/li&gt;
&lt;li&gt;Once all workers are done, we wait for the &lt;code&gt;sync.WaitGroup&lt;/code&gt; to signal that they've completed their&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;tasks.&lt;/p&gt;

&lt;p&gt;This code demonstrates how to achieve both speed and data order within chunks by dividing data and utilizing parallelism effectively.&lt;/p&gt;

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

&lt;p&gt;As a beginner developer, choosing the right method for writing large data into files depends on your specific use case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sequential Writing&lt;/strong&gt; is suitable for simplicity and data integrity but is slower for large datasets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Parallel Writing&lt;/strong&gt; is ideal when write speed is crucial, and you can manage concurrent writes efficiently, even if data order isn't a top priority.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Parallel Chunk Writing&lt;/strong&gt; is the sweet spot, offering both speed and data order within chunks for large datasets, but it comes with a moderate implementation complexity.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consider your project's requirements, system capabilities, and the balance between speed and data integrity when making your choice. Happy coding! 🚀📦&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to connect?
&lt;/h2&gt;

&lt;p&gt;Got questions or just want to chat? Connect with me on &lt;a href="https://twitter.com/intent/follow?screen_name=frasnym"&gt;Twitter/X&lt;/a&gt; anytime. Can't wait to chat with you! 💬&lt;/p&gt;

</description>
      <category>go</category>
      <category>filehandling</category>
      <category>performance</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Secure File Transfer Made Easy: Connect to SFTP Servers with Golang</title>
      <dc:creator>Frastyawan Nym</dc:creator>
      <pubDate>Mon, 28 Aug 2023 08:07:21 +0000</pubDate>
      <link>https://dev.to/frasnym/secure-file-transfer-made-easy-connect-to-sftp-servers-with-golang-53a1</link>
      <guid>https://dev.to/frasnym/secure-file-transfer-made-easy-connect-to-sftp-servers-with-golang-53a1</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Intro&lt;/li&gt;
&lt;li&gt;WHAT and WHY is SFTP?&lt;/li&gt;
&lt;li&gt;How to connect to an SFTP&lt;/li&gt;
&lt;li&gt;Something you can do after&lt;/li&gt;
&lt;li&gt;Conclusions&lt;/li&gt;
&lt;li&gt;Footnote&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;In this article, we'll show you how to connect to an SFTP server using Golang. SFTP is a secure file transfer protocol that allows you to transfer files over the internet securely 🔒. Golang is a programming language that's easy to learn and use, making it an excellent choice for building applications that require secure file transfer 💻.&lt;/p&gt;

&lt;p&gt;We'll start by explaining what SFTP is and why it's important 📡. Next, we'll walk you through the steps to connect to an SFTP server using Golang, including establishing an SSH connection, creating an SFTP client, and performing file transfer operations 🚀.&lt;/p&gt;

&lt;p&gt;By the end of this article, you'll have a good understanding of how to connect to an SFTP server using Golang and be able to apply this knowledge to your own projects 📝.&lt;/p&gt;

&lt;h2&gt;
  
  
  WHAT and WHY is SFTP?
&lt;/h2&gt;

&lt;p&gt;File transfer is an essential aspect of modern digital communication, allowing individuals and organizations to share data across networks and devices. However, with the increasing threat of cyberattacks and data breaches, secure file transfer has become more critical than ever 🔒. &lt;/p&gt;

&lt;p&gt;This is where Secure File Transfer Protocol (SFTP) comes in, providing a secure and reliable way to transfer files over the internet 🌐.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to connect to an SFTP
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;First, you'll need to import the "github.com/pkg/sftp" package in your Go code. This package provides an SFTP client implementation.&lt;/li&gt;
&lt;li&gt;Next, you'll need to establish an SSH connection to the SFTP server. You can use the "golang.org/x/crypto/ssh" package to do this. Here's an example code snippet:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ssh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClientConfig&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Auth&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;ssh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthMethod&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ssh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;HostKeyCallback&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ssh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InsecureIgnoreHostKey&lt;/span&gt;&lt;span class="p"&gt;(),&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ssh&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="s"&gt;"sftp.example.com:22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&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;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to dial: "&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;client&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;sftp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClient&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="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;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to create SFTP client: "&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;client&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we're using a password-based authentication method. You can also use other authentication methods, such as &lt;a href="https://github.com/frasnym/go-sftp-example/tree/main/public-key-auth"&gt;public key authentication&lt;/a&gt; 🔑.&lt;/p&gt;

&lt;h2&gt;
  
  
  Something you can do after
&lt;/h2&gt;

&lt;p&gt;Once you've established the SSH connection and created an SFTP client, you can use the client to perform SFTP operations, such as uploading and downloading files. Here's an example code snippet that uploads a file to the SFTP server:&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;localFile&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;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/path/to/local/file"&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;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to open local file: "&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;localFile&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;remoteFile&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;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/path/to/remote/file"&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;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to create remote file: "&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;remoteFile&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;_&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;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remoteFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;localFile&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;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to upload file: "&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 example, we're opening a local file, creating a remote file on the SFTP server, and then copying the contents of the local file to the remote file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;In this article, we've shown you how to connect to an SFTP server using Golang. By following the steps outlined in this article, you now have the knowledge and skills to automate file transfers, improve efficiency, and enhance security in your data exchange processes 🚀.&lt;/p&gt;

&lt;p&gt;We encourage you to apply what you've learned and explore further on your own. Golang has a vibrant community and a wealth of resources available, so don't hesitate to reach out and learn more 💻.&lt;/p&gt;

&lt;p&gt;Thank you for reading, and we hope this article has been informative and useful to you 📝.&lt;/p&gt;

&lt;h2&gt;
  
  
  Footnote
&lt;/h2&gt;

&lt;p&gt;Full code is available on &lt;a href="https://github.com/frasnym/go-sftp-example/tree/main"&gt;github&lt;/a&gt; 🌐&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to connect?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://twitter.com/intent/follow?screen_name=frasnym"&gt;Twitter/X&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>sftp</category>
      <category>ssh</category>
    </item>
    <item>
      <title>Building a Deep Nested CLI Application with Cobra in Golang</title>
      <dc:creator>Frastyawan Nym</dc:creator>
      <pubDate>Wed, 02 Aug 2023 08:30:01 +0000</pubDate>
      <link>https://dev.to/frasnym/building-a-deep-nested-cli-application-with-cobra-in-golang-55hj</link>
      <guid>https://dev.to/frasnym/building-a-deep-nested-cli-application-with-cobra-in-golang-55hj</guid>
      <description>&lt;p&gt;Continuing my previous &lt;a href="https://dev.to/frasnym/getting-started-with-cobra-creating-multi-level-command-line-interfaces-in-golang-2j3k"&gt;article&lt;/a&gt; about Cobra , the powerful Golang library for building command-line interfaces, we're diving deeper into the world of CLI development. &lt;/p&gt;

&lt;p&gt;In this installment, we'll explore how to take advantage of Cobra's capabilities to create a deeply nested CLI application. By organizing commands and subcommands in a hierarchical structure, we can make our CLI more user-friendly, intuitive, and flexible for handling complex tasks. Join me as we embark on this journey of building a feature-rich CLI tool that showcases the true power of Cobra in Golang. Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Deep Nesting
&lt;/h2&gt;

&lt;p&gt;To achieve deep nesting, we'll add subcommands under the existing config command. Let's create subcommands under &lt;code&gt;subcommand&lt;/code&gt;: &lt;code&gt;deepsubcommand&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// cmd/deepsubcommand.go
package cmd

import (
    "fmt"

    "github.com/spf13/cobra"
)

var deepSubCmd = &amp;amp;cobra.Command{
    Use:   "deepsubcommand",
    Short: "A brief description of the deepsubcommand",
    Long: `A longer description that explains the deepsubcommand
in detail. For example, you can mention how it complements
the main command and what options it supports.`,
    Run: func(cmd *cobra.Command, args []string) {
        // This function will be executed when the "deepsubcommand" is called
        fmt.Println("Running the deepsubcommand!")
    },
}

func init() {
    subCmd.AddCommand(deepSubCmd)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lest try it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ go run main.go subcommand deepsubcommand
&amp;gt; Running the deepsubcommand!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;In this blog post, we explored how to create a deep nested CLI application using the Cobra library in Golang. By organizing commands and subcommands hierarchically, we can build user-friendly CLIs that enhance the overall user experience. Cobra's intuitive API and support for commands, subcommands, and flags make it a powerful choice for building CLI applications in Golang.&lt;/p&gt;

&lt;p&gt;In your own projects, you can extend this deep nested CLI application further and customize it to suit your specific use cases. Have fun experimenting with different configurations and commands to create a versatile and user-friendly CLI tool!&lt;/p&gt;

&lt;h2&gt;
  
  
  Footnote:
&lt;/h2&gt;

&lt;p&gt;Full code is available on &lt;a href="https://github.com/frasnym/basic-cobra-cli/tree/feature/deep-nested-command"&gt;github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>cli</category>
      <category>cobra</category>
    </item>
    <item>
      <title>Getting Started with Cobra: Creating Multi-Level Command Line Interfaces in Golang</title>
      <dc:creator>Frastyawan Nym</dc:creator>
      <pubDate>Mon, 31 Jul 2023 10:29:40 +0000</pubDate>
      <link>https://dev.to/frasnym/getting-started-with-cobra-creating-multi-level-command-line-interfaces-in-golang-2j3k</link>
      <guid>https://dev.to/frasnym/getting-started-with-cobra-creating-multi-level-command-line-interfaces-in-golang-2j3k</guid>
      <description>&lt;h2&gt;
  
  
  Introduction:
&lt;/h2&gt;

&lt;p&gt;Creating a CLI using Cobra in Golang is a great choice, and nesting commands can help organize and structure your CLI effectively. Below, I'll guide you through the process of creating a nested CLI using Cobra.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Cobra?
&lt;/h2&gt;

&lt;p&gt;Cobra is a robust and flexible Golang library for building CLI applications. It provides an elegant and easy-to-use interface to define commands, flags, and arguments, making it a popular choice among Golang developers for creating CLI applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites:
&lt;/h2&gt;

&lt;p&gt;Before we begin, ensure you have Go (Golang) installed and have set up your workspace properly. You can install Cobra by executing the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get &lt;span class="nt"&gt;-u&lt;/span&gt; github.com/spf13/cobra@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Getting Started:
&lt;/h2&gt;

&lt;p&gt;Let's start by creating a new Golang project in your desired workspace. Once your project is set up, we'll initialize a Cobra application by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cobra init &lt;span class="o"&gt;[&lt;/span&gt;your-cli-app-name]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a basic structure for your CLI application, including the necessary files and folders.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining the Root Command:
&lt;/h2&gt;

&lt;p&gt;The root command is the entry point of your CLI application. It is the command executed when users run your application without any subcommands. Open the &lt;code&gt;cmd/root.go&lt;/code&gt; file, and let's define the root command using Cobra:&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;// cmd/root.go&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;cmd&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;"github.com/spf13/cobra"&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;rootCmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cobra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Use&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="s"&gt;"[your-cli-app-name]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Short&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"A brief description of your CLI application"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;`A longer description that explains your CLI application
in detail. For example, you can mention the various commands
available and what they do.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="o"&gt;:&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;cmd&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cobra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// This function will be executed when the root command is called&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;"Welcome to [your-cli-app-name]! Use --help for usage."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Execute&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="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rootCmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execute&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="no"&gt;nil&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;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exit&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can try to run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ go run main.go                                                          
&amp;gt; Welcome to [your-cli-app-name]! Use --help for usage.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding a Nested Command:
&lt;/h2&gt;

&lt;p&gt;Next, let's add a nested command to our CLI application. Nested commands are subcommands that provide additional functionality under the main command. For example, let's create a subcommand called "subcommand" for our application. Open the &lt;code&gt;cmd/subcommand.go&lt;/code&gt; file and define the nested command:&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;// cmd/subcommand.go&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;cmd&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;"github.com/spf13/cobra"&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;subCmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cobra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Use&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="s"&gt;"subcommand"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Short&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"A brief description of the subcommand"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;`A longer description that explains the subcommand
in detail. For example, you can mention how it complements
the main command and what options it supports.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="o"&gt;:&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;cmd&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cobra&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// This function will be executed when the "subcommand" is called&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;"Running the subcommand!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;rootCmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subCmd&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;Lets try it again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ go run main.go subcommand           
&amp;gt; Running the subcommand!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Congratulations! 🎉 You have successfully created a CLI application using Cobra with a nested command. You can continue to expand your application by adding more subcommands, flags, and arguments to meet your specific needs.&lt;/p&gt;

&lt;p&gt;In this blog post, we've only scratched the surface of what you can achieve with Cobra. It's a powerful library that allows you to create professional-grade CLIs with ease. Experiment with various options, customize your commands, and explore more features provided by Cobra.&lt;/p&gt;

&lt;p&gt;Happy coding! 👨‍💻&lt;/p&gt;

&lt;h2&gt;
  
  
  Footnote:
&lt;/h2&gt;

&lt;p&gt;Full code is available on &lt;a href="https://github.com/frasnym/basic-cobra-cli"&gt;github&lt;/a&gt; 🤝&lt;/p&gt;

</description>
      <category>go</category>
      <category>cli</category>
      <category>cobra</category>
    </item>
    <item>
      <title>Access your Golang Private Repository</title>
      <dc:creator>Frastyawan Nym</dc:creator>
      <pubDate>Thu, 20 Jul 2023 05:17:02 +0000</pubDate>
      <link>https://dev.to/frasnym/access-your-golang-private-repository-40ac</link>
      <guid>https://dev.to/frasnym/access-your-golang-private-repository-40ac</guid>
      <description>&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Add your ssh to you git host&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update your GOPRIVATE&lt;br&gt;
&lt;code&gt;go env -w GOPRIVATE="github.com/&amp;lt;OrgNameHere&amp;gt;/*&lt;/code&gt;"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update your gitconfig. This example for bitbucket:&lt;br&gt;
&lt;code&gt;git config --global url."git@bitbucket.org:".insteadOf "https://bitbucket.org/"&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add your ssh key with ssh-agent.You have to apply&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;ssh-agent &lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Agent pid 5867
ssh-add &amp;lt;private-ssh-key-file-name&amp;gt; // eg. id_rsa &lt;span class="o"&gt;(&lt;/span&gt;not .pub&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Enter passphrase &lt;span class="k"&gt;for&lt;/span&gt; /home/you/.ssh/id_rsa: &lt;span class="o"&gt;[]&lt;/span&gt; Identity added: /home/you/.ssh/id_rsa &lt;span class="o"&gt;(&lt;/span&gt;/home/you/.ssh/id_rsa&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Try run &lt;code&gt;go mod tidy&lt;/code&gt; on your project&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>Database Indexes, please be careful when using it!</title>
      <dc:creator>Frastyawan Nym</dc:creator>
      <pubDate>Wed, 06 Apr 2022 05:28:52 +0000</pubDate>
      <link>https://dev.to/frasnym/database-indexes-please-be-careful-when-using-it-2j28</link>
      <guid>https://dev.to/frasnym/database-indexes-please-be-careful-when-using-it-2j28</guid>
      <description>&lt;p&gt;Lets do disclaimer before we start 😉.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is my current understanding of Database Index.&lt;br&gt;
If there is any mistake that write that lead to misunderstanding, please let me know and I will update this post ASAP.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's begin 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  What is database index?
&lt;/h2&gt;

&lt;p&gt;Database index is a built-in tools that will help us for searching data inside database. Index will quickly locate record of our queries.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;To help to understand, I will make up some use case. Example, we have a &lt;strong&gt;users&lt;/strong&gt; table that have &lt;code&gt;id, full_name &amp;amp; gender&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r-J6DXwn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gmeli90ltacf4z53tlel.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r-J6DXwn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gmeli90ltacf4z53tlel.png" alt="users table" width="285" height="212"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That &lt;strong&gt;users&lt;/strong&gt; table will have 1000 rows. 2 of them is &lt;strong&gt;male&lt;/strong&gt; and the rest (998) of them is &lt;strong&gt;female&lt;/strong&gt;.&lt;br&gt;
Say that we need to find our &lt;strong&gt;male user&lt;/strong&gt;, we will create query something like this &lt;code&gt;SELECT * FROM users WHERE gender = 'male'&lt;/code&gt;.&lt;br&gt;
After we executed that query, we will have result of 2 users.&lt;/p&gt;

&lt;p&gt;Behind the scene, database engine will &lt;strong&gt;search all of 1000 rows to find that 2 rows&lt;/strong&gt;.&lt;br&gt;
Yes, that sound inefficient. But that is how database engine works. 😵&lt;/p&gt;
&lt;h2&gt;
  
  
  What is the solution?
&lt;/h2&gt;

&lt;p&gt;The solution is to use Database Index. 💡&lt;br&gt;
With index, database engine will make some of algorithm that map our table based on the index we chose.&lt;/p&gt;

&lt;p&gt;Okay, so we create an index on &lt;code&gt;gender&lt;/code&gt; column inside &lt;strong&gt;users&lt;/strong&gt; table.&lt;br&gt;
Back again to our query, now if we execute &lt;code&gt;SELECT * FROM users WHERE gender = 'male'&lt;/code&gt;, we will get 2 users again as result (of course!).&lt;/p&gt;

&lt;p&gt;The difference is, right now database engine will &lt;strong&gt;search on 2 rows to find that 2 rows&lt;/strong&gt;.&lt;br&gt;
Now that sound efficient❗&lt;/p&gt;
&lt;h2&gt;
  
  
  But wait...
&lt;/h2&gt;

&lt;p&gt;After we know that, maybe there is a thinking like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"let's create index for all of our column, so we can get quick result every time we search something 🤔"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thats right, you will get a quick query every search.&lt;br&gt;
But please don't over-used it. Even though Index have upside, Index also have downside.&lt;/p&gt;

&lt;p&gt;If we create an index, behind the scene database engine will write additional data to our database.&lt;/p&gt;

&lt;p&gt;Lets back again to our users table. The calculation is like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2 index (1 for ID, 1 for gender) * 1000 rows = 2000
# PK is always get index
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Imagine if we put index to all of our column&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4 index (ID, gender, full_name, created_at) * 1000 rows = 4000
# Thats only 4 columns.
# The more column we create, the more usage it will take when CREATE, UPDATE, DELETE, etc.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the conclusion is: please use it wisely. 😇&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: How to create index
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;PostgreSql
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;"customers"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nv"&gt;"id"&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;"gender"&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;"full_name"&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;"created_at"&lt;/span&gt; &lt;span class="nb"&gt;timestamp&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="nv"&gt;"customers"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"gender"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;MySql
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;`customers`&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nv"&gt;`id`&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="n"&gt;AUTO_INCREMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;`gender`&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nv"&gt;`full_name`&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nv"&gt;`created_at`&lt;/span&gt; &lt;span class="nb"&gt;timestamp&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="nv"&gt;`customers_index_0`&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="nv"&gt;`customers`&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;`gender`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>database</category>
      <category>sql</category>
    </item>
    <item>
      <title>TypeScript Linting and Code Formatter</title>
      <dc:creator>Frastyawan Nym</dc:creator>
      <pubDate>Sat, 10 Apr 2021 03:23:12 +0000</pubDate>
      <link>https://dev.to/frasnym/typescript-linting-and-code-formatter-4k2</link>
      <guid>https://dev.to/frasnym/typescript-linting-and-code-formatter-4k2</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Btw, before I forgot to mention it.&lt;br&gt;
This is a series post about &lt;strong&gt;Create Express API TypeScript Boilerplate&lt;/strong&gt; and this is the first post.&lt;br&gt;
After the second, third, etc. releases, I will mention it here. 👍&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Still learning it thought, how to create a series post on this site. 😂&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Let's Get Started! 🏃
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; 🤝: &lt;a href="https://github.com/frasnym/Express-API-TypeScript-Boilerplate/tree/chore/linting-and-formatter" rel="noopener noreferrer"&gt;Source Code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On this project, we will use the famous &lt;strong&gt;Visual Studio Code&lt;/strong&gt;. &lt;br&gt;
So please install it first so you can expect same result in the end 😁.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;And to avoid unexpected things happened, let's install some extension to VSCode.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint" rel="noopener noreferrer"&gt;ESLint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode" rel="noopener noreferrer"&gt;Prettier&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Setup Lint 🚨
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install &lt;a href="https://eslint.org/docs/user-guide/getting-started" rel="noopener noreferrer"&gt;ESLint&lt;/a&gt; package: &lt;code&gt;npm i -D eslint&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is the main package. This package support not only &lt;strong&gt;JavaScript&lt;/strong&gt; but &lt;strong&gt;TypeScript&lt;/strong&gt; as well.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt; package: &lt;code&gt;npm i -D typescript&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is a package that we will use to work with &lt;strong&gt;TypeScript&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Initialize TypeScript: &lt;code&gt;npx tsc --init&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can initialize typescript with this command. This command will be make a file that called &lt;code&gt;tsconfig.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Inside that file, we can specify what config we need. Let's just leave it by default for now. Example: &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6aaifrov68fb59i5i767.png" alt="Example"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Initialize ESLint: &lt;code&gt;npx eslint --init&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now initialize the ESLint configuration. You can copy my settings below for TypeScript support. &lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5343czrbnfe6jp9ytttj.png" rel="noopener noreferrer"&gt;Example&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Try it Out!&lt;/strong&gt; 🚀&lt;/li&gt;
&lt;li&gt;How to make ESLint catch error on code that we write: &lt;code&gt;npx eslint src/*.ts&lt;/code&gt;. &lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6umjl7ucwr1dv5783ben.png" rel="noopener noreferrer"&gt;Example&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;How to fix the error: &lt;code&gt;npx eslint src/*.ts --fix&lt;/code&gt;. Example: &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5n3725dzd52895tuul1.png" alt="Example"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setup Code Formatter 🎨
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;We will use &lt;a href="https://prettier.io/" rel="noopener noreferrer"&gt;Prettier&lt;/a&gt; to help us here&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install the required package: &lt;code&gt;npm i -D prettier-eslint&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next we will install cli version of prettier-eslint: &lt;code&gt;npm i -D prettier-eslint-cli&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Try it Out!&lt;/strong&gt; 🚀&lt;/li&gt;
&lt;li&gt;How to format the file: &lt;code&gt;npx prettier-eslint 'src/**/*.ts'&lt;/code&gt;. Example: &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpace4dz4e0awn90ues79.png" alt="Example"&gt;
&lt;/li&gt;
&lt;li&gt;How to format and actually change the file: &lt;code&gt;npx prettier-eslint 'src/**/*.ts' --write&lt;/code&gt;. Example: &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flmmjfkgj5kqcx1daq0v3.png" alt="Example"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add additional settings on Prettier to follow ESLint&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create &lt;code&gt;.prettierrc.yaml&lt;/code&gt; file. We choose YAML format so we can add comments. There is others format if you want to set differently: &lt;a href="https://prettier.io/docs/en/configuration.html" rel="noopener noreferrer"&gt;Link&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set the settings' value on &lt;code&gt;.prettierrc.yaml&lt;/code&gt;:&lt;br&gt;
&lt;br&gt;
&lt;code&gt;semi: false # We don't need semicolons at the end of line&lt;br&gt;
singleQuote: true # Use single quote&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add additional settings too on &lt;code&gt;.vscode/settings.json&lt;/code&gt;: &lt;code&gt;"editor.formatOnSave": true&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you don't have this file, just create one.&lt;/li&gt;
&lt;li&gt;This setting will tell VSCode to format the code on file save.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;That's all I can share with you for now 😊&lt;br&gt;
If you have any question, you can post it here.&lt;br&gt;
Or maybe you can reach me on my &lt;a href="https://twitter.com/frasnym" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; 👋&lt;/p&gt;

&lt;p&gt;Until then... 🚀&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Connecting NextJS Mini Project with Google Spreadsheets as Database</title>
      <dc:creator>Frastyawan Nym</dc:creator>
      <pubDate>Thu, 11 Feb 2021 04:12:53 +0000</pubDate>
      <link>https://dev.to/frasnym/connecting-your-nextjs-mini-project-with-google-spreadsheets-as-database-1o2d</link>
      <guid>https://dev.to/frasnym/connecting-your-nextjs-mini-project-with-google-spreadsheets-as-database-1o2d</guid>
      <description>&lt;p&gt;Did you know that we can use &lt;strong&gt;Google Sheets&lt;/strong&gt; as our database?&lt;br&gt;
Yes! We can do that 👍.&lt;/p&gt;

&lt;p&gt;Today, I will share step by step to do it.&lt;br&gt;
I will use one of the Javascript Frontend Library to do this, it's &lt;strong&gt;NextJS&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So, let's get started! 🚀&lt;/p&gt;

&lt;h1&gt;
  
  
  Create Your Google Project
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Go to your google console page&lt;/li&gt;
&lt;li&gt;Create your project, or you can visit through this &lt;a href="https://console.developers.google.com/projectcreate" rel="noopener noreferrer"&gt;Link&lt;/a&gt; 🔗&lt;/li&gt;
&lt;li&gt;🔙 Back to &lt;strong&gt;APIs &amp;amp; Services&lt;/strong&gt; page, click on &lt;strong&gt;ENABLE APIS AND SERVICES&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Search for &lt;a href="https://console.cloud.google.com/apis/api/sheets.googleapis.com" rel="noopener noreferrer"&gt;&lt;strong&gt;Google Sheets API&lt;/strong&gt;&lt;/a&gt; then enable it 🖱️
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy3zaf6eollro3wdyoo5l.JPG" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;li&gt;🔙 Back again to &lt;strong&gt;APIs &amp;amp; Services&lt;/strong&gt; page, click &lt;strong&gt;Credentials&lt;/strong&gt;, &lt;strong&gt;CREATE CREDENTIALS&lt;/strong&gt;, &lt;strong&gt;Service Account&lt;/strong&gt;. Or through this &lt;a href="https://console.cloud.google.com/iam-admin/serviceaccounts/create" rel="noopener noreferrer"&gt;Link&lt;/a&gt; 🔗&lt;/li&gt;
&lt;li&gt;Input required field and you can ignore optional field (of course 😅)&lt;/li&gt;
&lt;li&gt;🔙 Back to your &lt;strong&gt;Credentials&lt;/strong&gt; page, under &lt;strong&gt;Service Accounts&lt;/strong&gt; you will see your email. Copy that!&lt;/li&gt;
&lt;li&gt;Open your &lt;strong&gt;Service Account&lt;/strong&gt;. Click on &lt;strong&gt;ADD KEY&lt;/strong&gt;, choose &lt;strong&gt;JSON&lt;/strong&gt; as type. Then your credentials will be automatically downloaded. This will be used when connecting you &lt;strong&gt;NextJS&lt;/strong&gt; to the sheets.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F650oajmzqecsqz511dub.JPG" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;li&gt;Now you can create new &lt;strong&gt;spreadsheets&lt;/strong&gt; or use your existing one, &lt;strong&gt;Open it&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Share it to your &lt;strong&gt;Service Account Email&lt;/strong&gt; you just copied a second ago&lt;/li&gt;
&lt;li&gt;This step is done 🎊&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Create NextJS App
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Reference: &lt;a href="https://nextjs.org/docs" rel="noopener noreferrer"&gt;NextJS Docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Create an app```
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;npx create-next-app [APP_NAME]&lt;/p&gt;

&lt;h1&gt;
  
  
  or
&lt;/h1&gt;

&lt;p&gt;yarn create next-app [APP_NAME]&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2. 🏃‍♂️ Run your app with `npm run dev`, wait until server started
3. Without making any changes, you can access you page on **localhost:3000**. You will see awesome Next starter page 😎
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1s90tzp88i3tgxq1f800.JPG)
4. Continue 🚀, Setup Environment Variables
5. Create **env.local** file. You will need set this key-value pair. The value you can get on downloaded .JSON file before from google console```


GOOGLE_SHEETS_PRIVATE_KEY=[YOUR KEY]
GOOGLE_SHEETS_CLIENT_EMAIL=[YOUR ACCOUNT EMAIL]
SPREADSHEET_ID=[YOU CAN GET THIS ON URL OF YOUR SHEETS]


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

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;We will need &lt;a href="https://www.npmjs.com/package/googleapis" rel="noopener noreferrer"&gt;googleapis&lt;/a&gt; package to help us doing this, so install it```
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;npm i googleapis&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;7. Next, create a file for connecting to our sheet. For me is under **libs/sheets.js**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;import { google } from 'googleapis';&lt;br&gt;
export async function getEmojiList() {&lt;br&gt;
  try {&lt;br&gt;
    const target = ['&lt;a href="https://www.googleapis.com/auth/spreadsheets.readonly'" rel="noopener noreferrer"&gt;https://www.googleapis.com/auth/spreadsheets.readonly'&lt;/a&gt;];&lt;br&gt;
    const jwt = new google.auth.JWT(&lt;br&gt;
      process.env.GOOGLE_SHEETS_CLIENT_EMAIL,&lt;br&gt;
      null,&lt;br&gt;
      (process.env.GOOGLE_SHEETS_PRIVATE_KEY || '').replace(/\n/g, '\n'),&lt;br&gt;
      target&lt;br&gt;
    );&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const sheets = google.sheets({ version: 'v4', auth: jwt });
const response = await sheets.spreadsheets.values.get({
  spreadsheetId: process.env.SPREADSHEET_ID,
  range: 'emoji', // sheet name
});

const rows = response.data.values;
if (rows.length) {
  return rows.map((row) =&amp;gt; ({
    title: row[2],
    subtitle: row[3],
    code: row[4],
    browser: row[5],
    short_name: row[17],
    emojipedia_slug: row[18],
    descriptions: row[19],
  }));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;} catch (err) {&lt;br&gt;
    console.log(err);&lt;br&gt;
  }&lt;br&gt;
  return [];&lt;br&gt;
}&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;### Description:
- We will specify our target connection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;const target = ["&lt;a href="https://www.googleapis.com/auth/spreadsheets.readonly%22" rel="noopener noreferrer"&gt;https://www.googleapis.com/auth/spreadsheets.readonly"&lt;/a&gt;];&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Declare our jwt for authentication
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;const jwt = new google.auth.JWT(&lt;br&gt;
    process.env.GOOGLE_SHEETS_CLIENT_EMAIL,&lt;br&gt;
    null,&lt;br&gt;
    (process.env.GOOGLE_SHEETS_PRIVATE_KEY || '').replace(/\n/g, '\n'),&lt;br&gt;
    target&lt;br&gt;
);&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Get the sheet data, don't forget to change **sheet name**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;const sheets = google.sheets({ version: 'v4', auth: jwt });&lt;br&gt;
const response = await sheets.spreadsheets.values.get({&lt;br&gt;
   spreadsheetId: process.env.SPREADSHEET_ID,&lt;br&gt;
   range: 'emoji', // sheet name&lt;br&gt;
});&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Declare the row as your sheet data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;const rows = response.data.values;&lt;br&gt;
if (rows.length) {&lt;br&gt;
    return rows.map((row) =&amp;gt; ({&lt;br&gt;
        title: row[2],&lt;br&gt;
        subtitle: row[3],&lt;br&gt;
        code: row[4],&lt;br&gt;
        browser: row[5],&lt;br&gt;
        short_name: row[17],&lt;br&gt;
        emojipedia_slug: row[18],&lt;br&gt;
        descriptions: row[19],&lt;br&gt;
    }));&lt;br&gt;
}&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
That was a lot of text, now let's get the easy part 😬
# Populate Your Data
This is my `index.js` file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;import Head from 'next/head';&lt;br&gt;
import { getEmojiList } from '../libs/sheets';&lt;/p&gt;

&lt;p&gt;export default function IndexPage({ emojis }) {&lt;br&gt;
  return (&lt;br&gt;
    &amp;lt;&amp;gt;&lt;br&gt;
      &lt;/p&gt;
&lt;br&gt;
        Title - FrasNym&lt;br&gt;
        &lt;br&gt;
      &lt;br&gt;
      {emojis[0].title}&lt;br&gt;
    &amp;lt;/&amp;gt;&lt;br&gt;
  );&lt;br&gt;
}

&lt;p&gt;export async function getStaticProps(context) {&lt;br&gt;
  const emojis = await getEmojiList();&lt;br&gt;
  return {&lt;br&gt;
    props: {&lt;br&gt;
      emojis: emojis.slice(1, emojis.length), // remove sheet header&lt;br&gt;
    },&lt;br&gt;
    revalidate: 1, // In seconds&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You can already see our data from `emojis` variable that passed through `props`.

As you expect, We load the data from **Google Sheets** via our `getEmojiList` function. Then we call that function from `getStaticProps` function and pass it as props to our component.

On `getStaticProps`, we pass `revalidate: 1` so we hope that NextJS page will render when our sheets updated (At most once every second).

# Summary
This tools will help us to do a small project with database easily.
💡 FYI, You can insert to sheet via API too. You can connect this sheet with Your NodeJS with [google-spreadsheet](https://www.npmjs.com/package/google-spreadsheet) package, for example.

# Closing
That's all I can share with you for now 😊
If you have any question, you can post it here.
Or maybe you can reach me on my [Twitter](https://twitter.com/frasnym) 😁

Until then... 🚀
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>nextjs</category>
      <category>database</category>
      <category>javascript</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>How to Create Dockerized NodeJS with MySQL Database</title>
      <dc:creator>Frastyawan Nym</dc:creator>
      <pubDate>Tue, 09 Feb 2021 09:48:58 +0000</pubDate>
      <link>https://dev.to/frasnym/how-to-create-dockerized-nodejs-with-mysql-database-1o44</link>
      <guid>https://dev.to/frasnym/how-to-create-dockerized-nodejs-with-mysql-database-1o44</guid>
      <description>&lt;p&gt;TLDR;&lt;br&gt;
You can access the code here on &lt;a href="https://github.com/frasnym/Docker-NodeJS-MySQL"&gt;Github&lt;/a&gt;&lt;br&gt;
(&lt;em&gt;step by step how to run included&lt;/em&gt; 🤝)&lt;/p&gt;

&lt;p&gt;Hello 👋, This will be my first post on this forum.&lt;br&gt;
I will show you guys how to create a &lt;strong&gt;NodeJS&lt;/strong&gt;-&lt;strong&gt;MySQL&lt;/strong&gt; database with help of &lt;strong&gt;Docker&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;FYI, I just learn using docker too and I found that docker is very good to help development process faster ⚡.&lt;/p&gt;

&lt;h2&gt;
  
  
  Here we go
&lt;/h2&gt;

&lt;p&gt;I will assume that you already know what docker is and already installed it on your machine. I will use &lt;code&gt;docker-compose&lt;/code&gt; to create this project.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create MySQL Container, I'm using MySQL image to help me build this container.&lt;/li&gt;
&lt;li&gt;Create &lt;code&gt;docker-compose.yaml&lt;/code&gt; file. I this file we will be specifying our docker app.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3.8'

services: 
  mysqldb:
    image: mysql
    restart: always
    env_file: ./.env
    environment:
      MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
      MYSQL_DATABASE: $MYSQL_DATABASE
    ports:
      - $MYSQL_LOCAL_PORT:$MYSQL_DOCKER_PORT
    volumes: 
      - db-config:/etc/mysql
      - db-data:/var/lib/mysql
      - ./db/backup/files/:/data_backup/data

volumes: 
  db-config:
  db-data:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Description:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;version: '3.8'&lt;/code&gt;: This first line of code must be provided on &lt;em&gt;docker-compose.yaml&lt;/em&gt; file. This will tell docker which version of docker we used&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;services:&lt;/code&gt;: Inside this tag we will tell docker what service we will make&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mysqldb:&lt;/code&gt;: The first service is &lt;strong&gt;mysqldb&lt;/strong&gt;. You're free to choose the name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;image: mysql&lt;/code&gt;: We tell docker what image we will use. &lt;strong&gt;mysql&lt;/strong&gt; is official image for MySQL&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;restart: always&lt;/code&gt;: This command will tell docker always restart the container regardless of the exit status&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;env_file: ./.env&lt;/code&gt;: We specify our &lt;strong&gt;.env&lt;/strong&gt; path&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;environment:&lt;/code&gt; ON this tag we provide our MySQL connection setting&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MYSQL_ROOT_PASSWORD:&lt;/code&gt;: Specify password for root username&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$MYSQL_ROOT_PASSWORD&lt;/code&gt; is key from .env&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MYSQL_DATABASE: $MYSQL_DATABASE&lt;/code&gt;: create initial database&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ports:&lt;/code&gt;: we specify what port docker will be used. We will specify 2 port&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$MYSQL_LOCAL_PORT&lt;/code&gt;: The first one is what port on our machine will be used&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$MYSQL_DOCKER_PORT&lt;/code&gt;: The second one is what port we used inside docker container&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;volumes:&lt;/code&gt;: Volume will help us to keeping our data alive though restart&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;db-config:/etc/mysql&lt;/code&gt;: Volume to save config&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;db-data:/var/lib/mysql&lt;/code&gt;: Volume to save database data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;./db/backup/files/:/data_backup/data&lt;/code&gt;: Mount bind backup data&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;That a lot of typing already LOL 😂&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Let's continue 🚀
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Now we make our NodeJS app, inside of &lt;em&gt;app&lt;/em&gt; folder&lt;/li&gt;
&lt;li&gt;You can initialize npm as usual&lt;/li&gt;
&lt;li&gt;Here we will be create a &lt;strong&gt;Dockerfile&lt;/strong&gt;, this will help us to create image for NodeJS App
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:14

WORKDIR /app

COPY /app/package.json .

RUN npm install

COPY /app .

EXPOSE 3000

CMD [ "npm", "start" ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Description:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;FROM node:14&lt;/code&gt;: Specify base image for node. I take official image of NodeJS&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WORKDIR /app&lt;/code&gt;: Define working directory of docker. Our app will be placed on this folder inside docker&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;COPY /app/package.json .&lt;/code&gt;: Copy our &lt;em&gt;package.json&lt;/em&gt; file to our working directory (declared by dot(.) code)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RUN npm install&lt;/code&gt;: Install npm dependency as always&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;COPY /app .&lt;/code&gt;: Next we will copy our rest of file to working directory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EXPOSE 3000&lt;/code&gt;: We expose port to access via localhost&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CMD [ "npm", "start" ]&lt;/code&gt;: Specify script to run after image is builded&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Did you confused? If yes, me too when first learning this docker thing 😁&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Continue 🚀
&lt;/h2&gt;

&lt;p&gt;Back to our &lt;em&gt;docker-compose.yaml&lt;/em&gt; file&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Now we will define our NodeJS App on docker-compose
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  app:
    build:
      context: .
      dockerfile: ./app/Dockerfile
    image: node-mysql-app
    depends_on:
      - mysqldb
    stdin_open: true
    tty: true

volumes: 
  db-config:
  db-data:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command is more or less the same&lt;/p&gt;

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;app:&lt;/code&gt;: This is our second service's name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;build:&lt;/code&gt;: For custom image we will use &lt;code&gt;build&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;context: .&lt;/code&gt;: Specify the file PATH&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dockerfile: ./app/Dockerfile&lt;/code&gt;: This will be our previous Dockerfile&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;image: node-mysql-app&lt;/code&gt;: Define name to our custom image&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;depends_on: - mysqldb&lt;/code&gt;: This will tell docker that the second service will depends on first service&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;stdin_open: true&lt;/code&gt;: This will tell docker that keep open the terminal after complete building container&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tty: true&lt;/code&gt;: Same as above&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;volumes:&lt;/code&gt;: Last, we tell docker that we have named volume inside our service&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;db-config:&lt;/code&gt;: This is the name of the named volume&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;db-data:&lt;/code&gt;: This is the name of the named volume&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;And there we go, that's all is needed for creating our docker app 👍&lt;br&gt;
Lastly, we will execute this command to start our apps: &lt;code&gt;docker-compose up&lt;/code&gt;&lt;br&gt;
After success, you can access your app on &lt;strong&gt;localhost:3000&lt;/strong&gt; 🐳&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;With this, We don't need to install MySQL locally to start development right. I think this is the power of docker "To speed up our development process"&lt;br&gt;
That's all I can share with you for now 😊&lt;br&gt;
If you have any question, you can post it here. I hope that I can help to answer it 💪&lt;/p&gt;

&lt;p&gt;Or maybe you can reach me on my &lt;a href="https://twitter.com/frasnym"&gt;Twitter&lt;/a&gt;&lt;br&gt;
I love to build a new connection 😁&lt;/p&gt;

&lt;p&gt;Until then... 🚀&lt;/p&gt;

</description>
      <category>docker</category>
      <category>javascript</category>
      <category>mysql</category>
      <category>node</category>
    </item>
  </channel>
</rss>
