<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Shuvojit's Blog]]></title><description><![CDATA[Shuvojit's Blog]]></description><link>https://blog.shuvojit.dev</link><generator>RSS for Node</generator><lastBuildDate>Mon, 13 Apr 2026 08:37:20 GMT</lastBuildDate><atom:link href="https://blog.shuvojit.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to Implement Verbose Mode in a Go CLI App Using the Standard Library]]></title><description><![CDATA[A lot of CLI tools provide a verbose mode to get logs with additional information, which is helpful for scenarios when something breaks or when a user wants to understand in more detail what is happening in the background.
It is an essential part of ...]]></description><link>https://blog.shuvojit.dev/how-to-implement-verbose-mode-in-a-go-cli-app-using-the-standard-library</link><guid isPermaLink="true">https://blog.shuvojit.dev/how-to-implement-verbose-mode-in-a-go-cli-app-using-the-standard-library</guid><category><![CDATA[Go Language]]></category><category><![CDATA[cli]]></category><category><![CDATA[logging]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Shuvojit Sarkar]]></dc:creator><pubDate>Sun, 17 Sep 2023 19:37:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1694979379382/ccbdad6d-70ce-457f-8c6c-0c686e3f7f93.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A lot of CLI tools provide a verbose mode to get logs with additional information, which is helpful for scenarios when something breaks or when a user wants to understand in more detail what is happening in the background.</p>
<p>It is an essential part of the standard experience expected of a CLI app.</p>
<p>One such example is the <strong>cURL</strong> command. Following is a gif of the difference in output when using the <code>curl</code> command with the verbose flag and without.</p>
<p><a target="_blank" href="https://asciinema.org/a/595706"><img src="https://asciinema.org/a/595706.svg" alt="asciicast" /></a></p>
<p>Today we'll try to see how to implement such a feature in a CLI app using Go.</p>
<h3 id="heading-defining-the-feature">Defining the feature</h3>
<p>Let's define the flag we are going to implement</p>
<ul>
<li><p>It should work for all commands and subcommands in the application</p>
</li>
<li><p>When provided, it should show additional logs of all the commands, in addition, to the output that is shown by default.</p>
</li>
<li><p>It should be easy to maintain, every command or every log statement must not need to handle or know about this flag</p>
</li>
</ul>
<p>Luckily for us, Go has amazing standard packages we can compose to create this effect with ease.</p>
<h3 id="heading-tres-amigos">Tres Amigos</h3>
<p>We will use three packages to accomplish this.</p>
<ol>
<li><p><a target="_blank" href="https://pkg.go.dev/flag">flag</a>: We will use it to easily parse the arguments provided by the user</p>
</li>
<li><p><a target="_blank" href="https://pkg.go.dev/log">log</a>: We will use the standard package to log stuff</p>
</li>
<li><p><a target="_blank" href="https://pkg.go.dev/io">io</a>: We will utilise a very special Writer provided by this package.</p>
</li>
</ol>
<h4 id="heading-flag">flag</h4>
<p>The flag parsing works in three steps which need to be followed in the exact same order</p>
<ol>
<li><p>Define the expected flags</p>
</li>
<li><p>Invoke the <code>Parse()</code> method</p>
</li>
<li><p>Start accessing the values</p>
</li>
</ol>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">// Define the flag that is expected </span>
    <span class="hljs-comment">// We can pass the name, a default value &amp; a description</span>
    <span class="hljs-comment">// It will return a pointer which is guranteed to have value </span>
    <span class="hljs-comment">// Only after flag.Parse is called</span>
    verboseP := flag.Bool(<span class="hljs-string">"v"</span>, <span class="hljs-literal">false</span>, <span class="hljs-string">"Enable verbosity"</span>)

    <span class="hljs-comment">// From the docs: Must be called after all flags are defined </span>
    <span class="hljs-comment">// and before flags are accessed by the program.</span>
    flag.Parse()

    <span class="hljs-comment">// Access the value after </span>
    isVerbose := *verboseP
}
</code></pre>
<h4 id="heading-log">log</h4>
<p>Log package contains a function called <code>SetOutput</code> which can be set to anything that implements the <code>Writer</code> interface.</p>
<p>We can use this to redirect all the logs to a specific writer.</p>
<p><code>log.setOutput(SomeWriter)</code></p>
<h4 id="heading-io">io</h4>
<p>IO will provide us with the last missing piece, <code>Writer</code> which does nothing.</p>
<p>Basically discards any logs sent to it. It's called <code>io.Discard</code></p>
<h3 id="heading-putting-it-all-together">Putting it all together</h3>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"flag"</span>
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"io"</span>
    <span class="hljs-string">"log"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">// Define the flags</span>
    verboseP := flag.Bool(<span class="hljs-string">"v"</span>, <span class="hljs-literal">false</span>, <span class="hljs-string">"Enable verbosity"</span>)

    <span class="hljs-comment">// Invoke the parser</span>
    flag.Parse()

    <span class="hljs-comment">// Access it </span>
    isVerbose := *verboseP

    <span class="hljs-comment">// If verbosity is not required discard all upcoming logs</span>
    <span class="hljs-keyword">if</span> !isVerbose {
        log.SetOutput(io.Discard)
    }

    fmt.Println(<span class="hljs-string">"Hello world!"</span>)
    log.Println(<span class="hljs-string">"I'm tired of printing this"</span>)
}
</code></pre>
<p><a target="_blank" href="https://asciinema.org/a/608521"><img src="https://asciinema.org/a/608521.svg" alt="asciicast" /></a></p>
<p>Try it on <a target="_blank" href="https://replit.com/@ShuvojitSarkar/Simple-Verbose-Flag#main.go">repl.it</a></p>
]]></content:encoded></item><item><title><![CDATA[How to make sense of error logs?]]></title><description><![CDATA[Errors are scary for most people; especially when starting off. 
I’m not talking about the scenario where you expect a certain result and get something else; that might be related more to the code you personally wrote.
I’m specifically talking of a s...]]></description><link>https://blog.shuvojit.dev/how-to-make-sense-of-error-logs</link><guid isPermaLink="true">https://blog.shuvojit.dev/how-to-make-sense-of-error-logs</guid><category><![CDATA[error handling]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[programming]]></category><category><![CDATA[Java]]></category><dc:creator><![CDATA[Shuvojit Sarkar]]></dc:creator><pubDate>Tue, 27 Sep 2022 22:29:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1664317485225/5bRqh4brb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Errors</strong> are scary for most people; especially when starting off. </p>
<p>I’m not talking about the scenario where you expect a certain result and get something else; that might be related more to the code you personally wrote.</p>
<p>I’m specifically talking of a scenario when you either got started up at a new place with a completely new project; maybe the framework is new for you; maybe they have a custom-made framework for their org.</p>
<p>One day while working on a task; you somehow introduced a bug that throws some sort of exception which you have no idea why it came nor can you deduce how your code could have broken anything. You don’t even know the codebase well enough to be able to figure out remotely what could’ve caused it.</p>
<p>During a time like this, you can either get overwhelmed by that 200 lines of errors; or calmly befriend them. As it is the only thing that can help you understand the issue the quickest; not solve, but understand.</p>
<p>Error messages might not specifically help you fix the issue or come up with a solution, but they’re a great tool to understand what went wrong.</p>
<p>In layman terms, the gibberish that gets printed when your code fails is known as a stack trace.</p>
<h2 id="heading-understanding-stack-traces">Understanding Stack-Traces</h2>
<p>For example, you have a piece of code that starts executing from a file called A, calls a function in file B, and B, in turn, calls a function in C; something goes wrong in C and it throws an exception Ec; which if not handled, will result in the program to exit with non-zero code. For such a scenario, you can always assume that the info about C will come first followed by B and A.</p>
<p>There’s a very special reason for this as well; since thinking outside-in in a scenario like this wouldn’t really help much for a developer to understand the context as well. As when you start from the outside you have a lot of context to understand and process till you reach that line that actually throws an error. And also have to think about code that might not even be related to the error you’re trying to debug.</p>
<p>So the better way is to look inside-out; you start with looking at the most minimal context and try to figure out the reason why it failed; failed to understand? Ok, increase a level of context, now you can look at B which is called C, and figure out what might’ve gone wrong there, and just move contexts up and gradually build up on it until you figure out what actually went wrong.</p>
<h2 id="heading-what-does-it-look-like">What does it look like?</h2>
<p>Generally speaking, a stack trace will start with the name of an exception(or error); it will provide some background information about it and then there will be N number of lines starting from where the exception originated in leading up to where the execution began from.</p>
<p>Most probably, each line of the stack trace will also contain some information about which function/method the exception originated from, and additionally also provide information about the file and even the line number where it happened.</p>
<p>For example:</p>
<pre><code>caused by SomeException
    at someClass.someFunction(SomeFileName.someExt:lineNumber)
    at someClass.someFunction(SomeFileName.someExt:lineNumber)
</code></pre><h2 id="heading-needle-in-a-haystack-recognising-lines-of-interest">Needle in a haystack - Recognising lines of interest</h2>
<p>I feel like stating the obvious, but the quickest way to understand the reason why some error came lies in trying to understand the flow of control leading up to the error; i.e. how did the flow of control reach that point of failure; and what was the path in terms of lines of code it travels.</p>
<p>However, it may not seem obvious when we think about how modern software development works; we mostly use a framework or a bunch of library functions to get started. And while we try to manifest the app we want to create, we often end up using a lot of functions that we ourselves have not written; aka library code. </p>
<p>So, realistically in a stack trace, you can expect only at most 5 lines in a stack trace to be significant enough for you to pay attention to; but those 5 lines will be hidden within a plethora of methods from the framework or library which is being used.</p>
<p>So, the lines you need to be paying attention to are basically lines that are from your project; as those are the only lines where you might have added something which would break the app.</p>
<p>This is where IDEs can be of good help; most good IDE has this amazing feature where while showing errors they highlight all the files that belong to your project and are written by you as well as gives a link over it, upon clicking which the exact file and line is opened on that IDE.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1664315080378/TBNEQT6dG.png" alt="Image of an error log in Intellij Community." /></p>
<p>In the above image, we can see a stack trace of what seems like a validatePassword gone wrong. You can very easily just glance and locate the orange lines, and you will notice that all of those lines start with <strong>com.company</strong> which is the package name for the current project.</p>
<p>This is how IDEs may help in this first step of zoning into specific lines from a bigger stack trace. </p>
<h2 id="heading-avoid-this-silly-mistake">Avoid this silly mistake</h2>
<p>A lot of people; to be ‘safe’ tend to wrap their code in try-catch blocks while catching the <code>java.lang.Exception</code> class. This is scary; as now all the exceptions the programmer hasn’t even thought about getting ‘caught’ and since the bubbling of that event is stopped, it gets very hard to catch or debug that issue. As there will be no stacktrace for it at all.</p>
<p>I’m talking about a code somewhat like this </p>
<pre><code class="lang-java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doSomething</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">try</span> {
        someService.createSomeThing();
    <span class="hljs-keyword">catch</span> (Exception ex) {
        logger.error(<span class="hljs-string">"Something went wrong"</span>, ex);
    }
}
</code></pre>
<p>If the code is like this; and somehow the database goes down, instead of throwing a scary 500 which will prompt everyone to quickly look at it, it will silently handle that error and just provide a log statement as a response. Even while trying to investigate in such a scenario when someone will look into the logs they will only see the classname of the error that happened, and that’s it.</p>
<p>One thing that <strong>can</strong> be done(not should) is on top of just printing the <code>ex</code> we can also log <code>ex.getStackTrace()</code> to be sure that in such scenarios atleast the whole stacktrace is logged for us to then read and understand the issue.</p>
<p>However, what I think should be done is we should only handle exceptions that we expect; anything else that we didn’t probably means it is something that should fail our app.</p>
<p>As an example; let’s say you have a <code>createUserName</code> method which creates a userName for a specific user. If you know it can only throw two exceptions, <code>UserNameAlreadyExists</code> or <code>UserNameFormatInvalid</code>; then you should only handle those two exceptions and handle them accordingly and not catch <code>java.lang.Exception</code> as that means you will literally catch all exceptions that might happen downstream.</p>
<h2 id="heading-find-out-exactly-what-to-google">Find out exactly what to google</h2>
<p>Let’s say now you’ve gotten comfortable at looking at stacktrace, and you know where to look at and also how to locate lines relevant for you, the next simple step is googling. Learning how to read stacktrace will give you exactly what you need to google to understand the issue.</p>
<p>For example; let’s say you have a big stacktrace, and you locate 3lines of it where your own code is mentioned, and at the topmost entry an exception is thrown that you have never heard of, this is the time to just google the specific name, learn about it and think how your code could have thrown it; as massive hints you now know exactly which lines to look at in exactly which files; which will make this process a bit faster.</p>
<h2 id="heading-closing-thoughts">Closing thoughts</h2>
<p>This was a very basic guide; however every language and framework has a few things slightly different and you might need to fine-tune those while working to be at an advantage; for example with Laravel; whenever a 500 is thrown in a debug-enabled environment, the error page includes all the environment variables that were set and all the request params that came in for the request. So if you know about that, debugging an issue that is related to a wrong or cached environment variable will be a breeze.</p>
]]></content:encoded></item><item><title><![CDATA[How I used Github Co-pilot in my full-time job]]></title><description><![CDATA[In this article, I'll mostly cover my experience writing a bunch of backend code during my full-time job using co-pilot and will try to share a bit about how I was using it to be more productive.
Discovering co-pilot
I started using copilot maybe wit...]]></description><link>https://blog.shuvojit.dev/how-i-used-github-co-pilot-in-my-full-time-job</link><guid isPermaLink="true">https://blog.shuvojit.dev/how-i-used-github-co-pilot-in-my-full-time-job</guid><category><![CDATA[GitHub]]></category><category><![CDATA[Git]]></category><category><![CDATA[Visual Studio Code]]></category><category><![CDATA[coding]]></category><category><![CDATA[Developer Tools]]></category><dc:creator><![CDATA[Shuvojit Sarkar]]></dc:creator><pubDate>Fri, 06 May 2022 21:22:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1643393957386/6Q5Ipt25e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, I'll mostly cover my experience writing a bunch of backend code during my full-time job using co-pilot and will try to share a bit about how I was using it to be more productive.</p>
<h2 id="heading-discovering-co-pilot">Discovering co-pilot</h2>
<p>I started using copilot maybe within 3months of them starting to roll it out; during the time I was working on a fresh new backend project. Which was built using Typescript. For a while, after installing it I was reluctant to use it and had only tried it out a few times for just creating a function to add two numbers and stuff. </p>
<p>I did try to get into it though, but found it rather slow and eventually disabled it and moved on. </p>
<p>Until one fine day, I had a bit of extra work and needed to squeeze it in somehow when I remembered this tool and it immediately was so much better than the last time I had used it; it was predicting correctly and quickly. </p>
<p>Since then I had used co-pilot extensively for a lot of my work and hobby projects.</p>
<h2 id="heading-my-experience-using-it">My experience using it</h2>
<p>I have actually used co-pilot to write large chunks of backend code; basically reading from tables, fetching from tables, query generation, converting queries into knex implementations; and the list goes on.</p>
<p>And I’ve messed up a lot of times as well, you see, just like autocomplete, co-pilot also impairs you someway, very slowly you start giving in to it, and start letting go of the cognitive load cause now you only think one level of abstraction above the actual implementation, you start thinking in terms of specification rather than implementation.</p>
<p>Let me explain, during this time, I noticed myself getting into bugs that I would normally never get into, and stuff that was really hard to explain at first, almost one of those times you’d perform the sin of questioning the compiler. Almost all of those bugs were small typos which I’d miss because I overlooked them as I myself didn't write any of those 20LOC.</p>
<h2 id="heading-things-co-pilot-is-really-good-at">Things co-pilot is really good at</h2>
<ul>
<li>Converting very specific instruction in english into code, the less the abstraction the better</li>
<li>This means, it's really good at writing singular units of code where context is limited to it’s scope</li>
<li>It is also good at picking up additional information present in the file, i.e. it will intelligently pick up which variables must be used in the next operation and which other functions might be called as a side effect of the current one</li>
<li>Commenting and documenting your code, you can expect to start documenting a piece of code and you’ll find co-pilot brilliantly fill in the details for you by understanding the implementation</li>
<li>You can sort of get it to do chores for you as well, I had a bunch of code where there was a SQL prepared statement and I had the task to refactor it out, and co-pilot helped beautifully. Ever since then, I got into a habit of playing with queries in the MySQL console, pasting it in the ide, and making co-pilot write the knex equivalent for it.</li>
</ul>
<h2 id="heading-things-it-isnt-good-at">Things it isn’t good at</h2>
<ul>
<li>In my personal opinion, co-pilot isn’t very good with magic code, i.e. code that is heavily abstracted</li>
<li>It isn’t good with libraries or patterns which are uncommon. Let’s say your org has a big internal library which is very unique, you can’t really expect copilot to predict it that well; however, if you have similar implementations in the same file you can start typing it out and co-pilot sorta fizzy finds it’s way to whichever implementation you'd wanna use.</li>
</ul>
<h2 id="heading-best-use-cases-right-now">Best use cases right now</h2>
<ul>
<li>Use it as google/StackOverflow; whenever there’s a piece of code that you have already written once in your life, and know how it works you can easily describe it as a comment and co-pilot should lead you there. The co-pilot is a beast at this.</li>
<li>Refactor and chores. First of all, make sure you read each and every piece of code generated by this, as small diversions from the expected code can make the code behave in ways you wouldn’t be able to catch very quickly, and it should be tough as you are not the person who implemented it. I’d say co-pilot mostly gets it right, even contextual information, I’ve seen it refactor a nested SQL query into beautiful knex.</li>
</ul>
<h2 id="heading-examples">Examples</h2>
<h4 id="heading-example-1">Example 1</h4>
<p>In the gif below, you'll see me asking co-pilot to create a function which gets users from somewhere, the most common usecase being fetching it from a relational database. After the first suggestion, you'll notice I changed the function signature a bit hinting at a possible pagination implementation, after which co-pilot very quickly understood the context and implemented the pagination code in the query on it's own. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1643314096188/T5cERleou.gif" alt="fetching-users-from-database.gif" /></p>
<p>This is how you can calibrate in scenarios where you need an unconventional or uncommon code you 
can either open up the co-pilot suggestion list (<kbd>Ctrl</kbd> <kbd>Enter</kbd>) and pick one that's matches.</p>
<p>If you don't find the exact code you're looking for, get one that is closest and then just write the rest on your own, however, if you don't even find a resembling piece then maybe you're describing a really big and abstract code and maybe you can try breaking it into subtasks and asking github to fill in the code per atomic operation.</p>
<h4 id="heading-example-2">Example 2</h4>
<p>In the gif below, you will see I am not making co-pilot write a new piece of code, rather making it do refactoring work, I really enjoy taking it's help while doing stuff which is necessary but sometimes boring.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1643317713260/Xpmhawp7Y.gif" alt="doing-chores-cleaned.gif" /></p>
<h4 id="heading-example-3">Example 3</h4>
<p>In the gif below, you'll see that I wanted to have a function which uploads a local file to a s3 bucket, however I wanted to implement it using <code>boto3.resource</code> and not <code>boto3.client</code>; in this scenario changing the function definition doesn't make sense, so we add a comment to guide co-pilot into the right direction.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1643318045404/nWlRl5IAJ.gif" alt="Copilot writing code to upload image to s3" /></p>
<h2 id="heading-closing-thoughts">Closing thoughts</h2>
<p>After using co-pilot for a while, you guys will learn this sense of guiding copilot; I’ve eventually developed this way of setting up the stage around the part of my file where I’d want co-pilot to fill in some lines, and if you do the setup just right, you can guide co-pilot really well to predict the exact code that you’d want to generate.</p>
]]></content:encoded></item></channel></rss>