<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Sanjay Nair's Blog</title>
  <subtitle>Software Engineering and Technology</subtitle>
  <link href="https://sanjaynair.me/feed.xml" rel="self"/>
  <link href="https://sanjaynair.me/"/>
  <updated>2026-06-24T02:37:38Z</updated>
  <id>https://sanjaynair.me/</id>
  <author>
    <name>Sanjay Nair</name>
    <email>email@sanjaynair.dev</email>
  </author>
  
  <entry>
    <title>The Personal Project to Win Your Next Career Fair</title>
    <link href="https://sanjaynair.me/blog/2018-02-25-personal-project-career-fair/"/>
    <updated>2018-02-25T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2018-02-25-personal-project-career-fair/</id>
    <content type="html">&lt;p&gt;&lt;em&gt;Disclaimer: This article is aimed at &lt;strong&gt;beginners&lt;/strong&gt; to software development or those looking to enhance their personal project experience.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I do a lot of recruiting for my job, mainly for entry level or interns for software engineering. A common question I always get asked about this from prospective new hires is: &amp;quot;How do I stand out?&amp;quot; The answer for me is simple. Have experience building software and be able to confidently and intelligently talk about it.&lt;/p&gt;
&lt;p&gt;I think personal projects are a great way that any beginner with a computer and an internet connection can get relevant software experience while building something cool in the process. I always say that all the necessary knowledge to qualify for an entry level developer position is freely available online. I see far too many people I interview who flat out tell me they have no project experience to speak to or they have a hard time coming up with ideas for personal projects to work on.&lt;/p&gt;
&lt;p&gt;So instead of repeating my advice to every second person, I thought I would get it down in writing. Here&#39;s my go-to, straightforward, biggest bang for your buck personal project that you can put on your resume, show off the recruiters, and build your software engineering skill-sets. If you have a free weekend before your next career fair, I guarantee this exercise will give you a step up over everyone else. 🔑&lt;/p&gt;
&lt;h3&gt;Two words: Personal Website&lt;/h3&gt;
&lt;p&gt;Yes! Seems a bit cliche, but building yourself a personal website is a simple and effective way to get real experience in the following areas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Front-end web development&lt;/li&gt;
&lt;li&gt;Continuous integration&lt;/li&gt;
&lt;li&gt;Deployment to a public cloud-based platform as a service&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&#39;s see how. 🚀&lt;/p&gt;
&lt;h4&gt;1. Build the Website and Show off the Code!&lt;/h4&gt;
&lt;p&gt;Start small. Decide on the content of your website. You can go as simple as a single page with your resume/CV information, or go nuts and add a blog, photo gallery, etc.&lt;/p&gt;
&lt;p&gt;Once you&#39;re ready to build, pick what you&#39;re going to use to build it. Ideally pick something you&#39;re not so familiar with so that as you build, you learn.&lt;/p&gt;
&lt;p&gt;Keep it basic with just HTML/CSS/JS (Here&#39;s a &lt;a href=&quot;https://medium.com/codingthesmartway-com-blog/build-a-real-world-html5-css3-responsive-website-from-scratch-afc079f8bb6b&quot;&gt;tutorial&lt;/a&gt; you can follow for that). Or take it a step further and build it using a popular web framework. Here are a few examples:&lt;/p&gt;
&lt;aside class=&quot;editorial-note&quot; role=&quot;note&quot; aria-label=&quot;Editor&#39;s note&quot;&gt;
&lt;p class=&quot;editorial-note__header&quot;&gt;&lt;strong&gt;Editor&#39;s note &amp;middot; June 2026&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;editorial-note__body&quot;&gt;
&lt;p&gt;The Vue and Angular documentation links below have been updated to their current canonical URLs. The Vue 2 guide moved to &lt;a href=&quot;https://v2.vuejs.org/&quot;&gt;v2.vuejs.org&lt;/a&gt; when Vue 3 took over the main &lt;code&gt;vuejs.org&lt;/code&gt; domain, and Angular&#39;s site has since been rebranded to &lt;a href=&quot;https://angular.dev/&quot;&gt;angular.dev&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://v2.vuejs.org/v2/guide/&quot;&gt;VueJS&lt;/a&gt;: great for small projects, has a lot of similar concepts to other frameworks.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/facebook/create-react-app&quot;&gt;React&lt;/a&gt;: One of the most popular frameworks out there right now.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://angular.dev/&quot;&gt;Angular&lt;/a&gt;: Still plenty popular in enterprise.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you build, push everything to a public repo on &lt;a href=&quot;https://github.com/&quot;&gt;Github&lt;/a&gt; (get familiar with Git and version control if you need to because &lt;strong&gt;you need to&lt;/strong&gt;). Write a nice README into the repo, outline your development process and giving some simple instructions on how to pull down and run your code.&lt;/p&gt;
&lt;p&gt;Next time your talk to a recruiter, you have a new talking point to add to your pitch.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Here&#39;s my personal website I built using ________ . Here&#39;s the code in my public Github repo&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Check that box off ✅&lt;/p&gt;
&lt;h4&gt;2. Create an Automated CI Pipeline&lt;/h4&gt;
&lt;p&gt;This is a skill some professional developers don&#39;t even have a grasp on and a lot of companies are still trying to figure out how to implement. The basic idea is this: create an automated process to build, test, analyze, and publish results about your code every time you update it in Github. This is what&#39;s called a &lt;em&gt;continuous integration pipeline&lt;/em&gt; ✨.&lt;/p&gt;
&lt;p&gt;What this pipeline can do is pretty endless, but here are a few free tools to easily get started:&lt;/p&gt;
&lt;aside class=&quot;editorial-note&quot; role=&quot;note&quot; aria-label=&quot;Editor&#39;s note&quot;&gt;
&lt;p class=&quot;editorial-note__header&quot;&gt;&lt;strong&gt;Editor&#39;s note &amp;middot; May 2026&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;editorial-note__body&quot;&gt;
&lt;p&gt;Travis CI effectively retired its free tier for open-source projects in 2020, so the link below largely points to a paid plan today. For a new project in 2026, &lt;a href=&quot;https://github.com/features/actions&quot;&gt;GitHub Actions&lt;/a&gt; is the most direct free alternative and integrates with your repo with zero setup.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://travis-ci.com/getting_started&quot;&gt;Travis CI&lt;/a&gt;: Easily integrate with your Github repos and have jobs trigger every time you push code. Useful if you need to build or test you code and extensible for when you need to deploy it (read about that further down).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://circleci.com/docs/2.0/hello-world/&quot;&gt;CircleCI&lt;/a&gt;: Another free CI tool that lets you run automated tasks every time your code updates.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sonarsource.com/products/sonarcloud/&quot;&gt;SonarCloud&lt;/a&gt;: Have your code scanned and analyzed for quality.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Here&#39;s the continuous integration pipeline that builds, tests, and quality scans my code automatically every time I make update to it in Github.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;At this point, the recruiter is already going to remember you.&lt;/p&gt;
&lt;h4&gt;3. Deploy Your Website to a Public PaaS&lt;/h4&gt;
&lt;p&gt;So often the last but more crucial step to really finishing a project is skipped. If you don&#39;t deploy your website somewhere, then how do you expect to show it off to anyone outside of your localhost?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://pages.github.com/&quot;&gt;Github pages&lt;/a&gt; is an easy and free way to host a static website through a free, public Github repo. It&#39;s where I host &lt;a href=&quot;https://sanjaynair.me/&quot;&gt;my website&lt;/a&gt;! If you took the HTML/CSS/JS route in step 1, this might be a good choice.&lt;/p&gt;
&lt;p&gt;But if you really want to take it to the next level, using one of the many free cloud service provides to host a site is a great way to get the same cool effect while gaining an extra skill under your belt. It can the final punch that really knocks the recruiter&#39;s socks off.&lt;/p&gt;
&lt;aside class=&quot;editorial-note&quot; role=&quot;note&quot; aria-label=&quot;Editor&#39;s note&quot;&gt;
&lt;p class=&quot;editorial-note__header&quot;&gt;&lt;strong&gt;Editor&#39;s note &amp;middot; May 2026&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;editorial-note__body&quot;&gt;
&lt;p&gt;Heroku retired its free dyno tier on November 28, 2022, so the &quot;free account on Heroku&quot; path described below is no longer available. Modern free-tier alternatives worth considering include &lt;a href=&quot;https://fly.io/&quot;&gt;Fly.io&lt;/a&gt;, &lt;a href=&quot;https://render.com/&quot;&gt;Render&lt;/a&gt;, &lt;a href=&quot;https://railway.app/&quot;&gt;Railway&lt;/a&gt;, and &lt;a href=&quot;https://vercel.com/&quot;&gt;Vercel&lt;/a&gt; or &lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt; for static and serverless workloads.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;Sign up for a free account on &lt;a href=&quot;https://devcenter.heroku.com/start&quot;&gt;Heroku&lt;/a&gt;. They provide support for deploying apps written in all kinds of languages. Go through the steps to manually deploy your app to their platform and enjoy your website, now publicly available for everyone to see!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;My site is deployed to Heroku. I have it running on one of their free-tier dynos. The site deploys automatically every time I push new code to the repo.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you&#39;ve knocked all that out, here are some extra credit steps to try out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hook up your CI pipeline to Heroku so that when you push new code to Github, it will not only run through a build and code scans, but it can then automatically be deployed live without you having to do anything else!&lt;/li&gt;
&lt;li&gt;Buy a custom domain name through &lt;a href=&quot;https://www.namecheap.com/&quot;&gt;Namecheap&lt;/a&gt; or another domain provider and set it up to route to your hosted website. Now you have a personalized and simple URL to get to your site while learning about setting up DNS entries.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you go through this process, you will struggle through a lot of new and unfamiliar concepts. But if you really take the time to dive deep into something with a goal in mind, you will come out learning a whole lot and with a pretty cool product to show for it.&lt;/p&gt;
&lt;p&gt;I didn&#39;t go into detail about how to do any of the steps I mentioned on purpose. Click through some of the links I included. Go through the getting started guides. Make some mistakes and spend a lot of time banging your head against your desk in frustration. At the end of it all, you should feel confident in the skills you executed to make it happen.&lt;/p&gt;
&lt;p&gt;My hope is that no up-and-coming developer should ever feel lost when trying to find ways to expand their experience and skill sets. Hope this helps you get started. Good luck.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Getting to Know Terraform</title>
    <link href="https://sanjaynair.me/blog/2018-03-16-getting-to-know-terraform/"/>
    <updated>2018-03-16T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2018-03-16-getting-to-know-terraform/</id>
    <content type="html">&lt;aside class=&quot;editorial-note&quot; role=&quot;note&quot; aria-label=&quot;Editor&#39;s note&quot;&gt;
&lt;p class=&quot;editorial-note__header&quot;&gt;&lt;strong&gt;Editor&#39;s note &amp;middot; June 2026&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;editorial-note__body&quot;&gt;
&lt;p&gt;The Vagrant and Vault product links below have been updated to their current canonical URLs. HashiCorp has since consolidated its product documentation under &lt;a href=&quot;https://developer.hashicorp.com/&quot;&gt;developer.hashicorp.com&lt;/a&gt;, so the standalone &lt;code&gt;vagrantup.com&lt;/code&gt; and &lt;code&gt;vaultproject.io&lt;/code&gt; marketing sites redirect there today.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;Every few weeks or so, I try to spend some quality time getting to know a concept or technology outside my core proficiency of web application development. About half a year ago, I had the chance to dabble in some cloud infrastructure management. It was, to some degree, restricted to a lot of repetitive, manual tasks on a tiny corner of the platform. With the rise of the big cloud providers like Google Cloud Platform, AWS, and Azure, it seemed like being comfortable with the fundamentals of moving through those systems was becoming an ever increasingly necessary skill to have. However, with my limited experience, I didn&#39;t feel like I could confidently say I had good experience in &amp;quot;cloud infrastructure management.&amp;quot;&lt;/p&gt;
&lt;p&gt;Fast forward to today, and an article on the front page of Hacker News caught my eye. It was called &lt;a href=&quot;https://blog.agilebits.com/2018/01/25/terraforming-1password/&quot;&gt;Terraforming 1Password&lt;/a&gt;, written by the founder of Agile Bits, the company behind the popular password manager: 1Password. It outlined the process that the company went through to convert their system of &amp;quot;Infrastructure as code,&amp;quot; moving from the AWS proprietary provisioning tool called Cloudformation, to Terraform: an open source solution built by Hashicorp. You might be familiar with some of their other products: like &lt;a href=&quot;https://developer.hashicorp.com/vagrant&quot;&gt;Vagrant&lt;/a&gt; and &lt;a href=&quot;https://developer.hashicorp.com/vault&quot;&gt;Vault&lt;/a&gt;. Give the article a read when you get a chance, it&#39;s a good one.&lt;/p&gt;
&lt;p&gt;I thought back to experiences manually provisioning and deploying cloud infrastructure. I thought Terraform seemed to make all those past pains go away. I figured learning something about it would move me in the right direction of getting properly familiar with some cloud infrastructure fundamentals. And it did! But in some ways I didn&#39;t initially expect.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2018-03-16-getting-to-know-terraform/0xWLrJSGVGb-wRTExG.jpg&quot; alt=&quot;A little kid splashing in the water in wellies in Rīgas pilsēta by Daiga Ellaby on Unsplash&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;Getting My Feet Wet&lt;/h4&gt;
&lt;p&gt;Before I started, the cloud service provider I was most familiar with was Google Cloud Platform, at least from the basics of how to work with the tools and what suite of services it offered. However, I figured to get the full understanding of what Terraform had to offer, I needed to spend some time getting familiar with some other cloud service providers. So I signed up for a free tier of all three cloud services.&lt;/p&gt;
&lt;p&gt;GCP seemed to have one of the better trial offerings (at least at the time of writing this piece) with a year long trial including $300 of free credit to apply to various services. AWS follows a slightly different model where each month, you can remain in a free tier by staying below a threshold of usage for each of their services (which is set at a plenty generous level for a hobbyist). Azure has a mix of both models where you get $200 in credit monthly, a selection of services free for a year, and the rest billed at a free usage tier.&lt;/p&gt;
&lt;p&gt;With that, I had a multi-cloud, basically free, playground to start automating some infrastructure.&lt;/p&gt;
&lt;h4&gt;Getting My Hands Dirty&lt;/h4&gt;
&lt;p&gt;With my cloud playground up and running, I started following along with some guides and the Terraform documentation offered by Hashicorp. The &lt;a href=&quot;https://www.pluralsight.com/courses/terraform-getting-started&quot;&gt;Terraform: Getting Started&lt;/a&gt; course offered by Pluralsight was also a good place to start, since it was based mainly on Amazon Web Services with a sprinkling of Microsoft Azure. Soon enough I was up and running, or more specifically, spinning up and immediately tearing down infrastructure between GCP and AWS.&lt;/p&gt;
&lt;p&gt;Terraform follows a modular design principle with a well-defined set of abstract components to play with, each with different flavors based on what concrete cloud environment it corresponds to. All the specifications are done in the Hashicorp configuration language, which itself is easy enough to pick up. One struggle I faced was the open endedness of how Terraform files come together. It seemed the best way to go about it was to simply copy and paste existing examples from documentation and modify it to your needs.&lt;/p&gt;
&lt;p&gt;I started by copying some of the basic examples I found online for each of the cloud providers. Spinning up a nano instance on EC2 or GCE, putting it behind a simple load balancer, maybe provisioning a database service, making sure it all worked together properly, and promptly tearing it down.&lt;/p&gt;
&lt;p&gt;Then I ventured into the wild west of making these provisioned components work &lt;em&gt;between clouds&lt;/em&gt;. I thought this was actually pretty cool. With Terraform, I could break down the barrier the industry thrives on: getting customers tightly integrated within their ecosystem of products and making it pretty hard to break away from them. It was one of the reasons I was so isolated to GCP before I started this whole exercise. I do have to say though, even with that extra utility, it was still enough of a struggle to get an AWS lambda function to publish messages to Google Pubsub. I didn&#39;t try much after that, opting to spending my time writing this instead :). I&#39;d be interested in what other examples could be thought up, that could take advantage of the best parts of each cloud and bring them together.&lt;/p&gt;
&lt;p&gt;Additionally, it was a different experience to run code that had an external impact, that if I messed up, could potentially cost me a good chunk of money. Every time I ran &lt;code&gt;terraform apply&lt;/code&gt; and got an error, there was a small part of me that feared some rogue process was left unattended, eating through my free tier of usage and piling on some uncapped cost onto my credit card. Or some malicious agent stole my access key and was provisioning compute instances to mine Bitcoin. So is the nature of working with cloud providers: having the potential to scale your app fast means having the risk of having to pay for it…fast. Luckily, I was very liberal about running &lt;code&gt;terraform destroy&lt;/code&gt; and keeping my environments clean. My costs never went above a few bucks a month. Keep those secret keys out of Github!&lt;/p&gt;
&lt;h4&gt;Moving the Needle Forward&lt;/h4&gt;
&lt;p&gt;After spending a few good days with Terraform, here are my takeaways.&lt;/p&gt;
&lt;p&gt;What I learned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Terraform is a very powerful tool that is highly customizable, interoperable with your platform of choice, and easy enough to pick up and run with. It may be overkill for your hobby projects, but certainly a fun way to get a better handle on cloud infrastructure management.&lt;/li&gt;
&lt;li&gt;On the surface, most cloud providers offer similar services. However, the actual experience of working with them can be drastically different form a developer and operations perspective. Some examples include authorization and IAM, API offerings to access platform features, and customizability of offered components.&lt;/li&gt;
&lt;li&gt;There a &lt;strong&gt;&lt;em&gt;lot&lt;/em&gt;&lt;/strong&gt; you can do in the cloud for free or with a few bucks a month. Consider taking your personal projects to the next level by taking advantage of what&#39;s offered for free.&lt;/li&gt;
&lt;li&gt;I gained a lot more familiarity of with the plethora of services offered by cloud providers. &lt;a href=&quot;https://aws.amazon.com/products/&quot;&gt;Every&lt;/a&gt;, &lt;a href=&quot;https://cloud.google.com/products/&quot;&gt;single&lt;/a&gt;, &lt;a href=&quot;https://azure.microsoft.com/en-us/services/&quot;&gt;cloud&lt;/a&gt; has that that one marketing page with a hellacious number of services. Going through and getting using some of them actually made the whole collection as a whole less intimidating.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And some questions I pose:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;My definition of what a &amp;quot;Full Stack Developer&amp;quot; seems to be expanding further and further out. Does it still mean &amp;quot;I am proficient from the backend to the frontend of the application stack,&amp;quot; or should it include the scope of &lt;em&gt;devops&lt;/em&gt; where you not only own the application but also the infrastructure it runs on?&lt;/li&gt;
&lt;li&gt;Are cloud service offering going to continue to diversity with different service providers, consolidate into fewer into the few and big, or will we mix and match them as we need like programming languages today? If tools like Terraform are any indication of what&#39;s possible, I&#39;d wager on the last option.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you can probably tell, my journey into learning this one tool expanded out into an unexpectedly broader study of navigating cloud service providers and getting to know their pros and cons. However, this exploration might not have happened without a unique, open-source tool like Terraform available to tinker with and learn from.&lt;/p&gt;
&lt;p&gt;So for that, go sign up for some trials of AWS or GCP or Azure or whatever you fancy today. Play around with some Terraform scripts, and learn something new while having some fun.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Asynchronous JavaScript</title>
    <link href="https://sanjaynair.me/blog/2018-04-01-asynchronous-javascript/"/>
    <updated>2018-04-01T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2018-04-01-asynchronous-javascript/</id>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;Callbacks vs Promises vs Async/Await&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;JavaScript and many other programming languages support an abstraction known as asynchronous execution. What this means is when you want to execute some task that might return some data in an unknown amount of time, JavaScript lets you predefine what to do once that data does show up while continuing to run the rest of your program.&lt;/p&gt;
&lt;p&gt;An example of this might be calling an HTTP service which might take 500 milliseconds to return a value with a good network connection or 5 seconds if the network connection is poor. Instead of locking up your program for up to 5 seconds, JavaScript just lets you say what to do when the value does come back, continues on its merry way, and only handles the response when it has to.&lt;/p&gt;
&lt;p&gt;As of the date I am writing this article and the current ECMAScript8 specification JavaScript follows, there are 3 main ways to write these asynchronous abstractions. Here&#39;s a brief overview of each.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Each abstraction presented below will achieving the same result: call a function that does an asynchronous task like calling an external service over a network that returns some data and prints that data to the console.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Callbacks&lt;/h3&gt;
&lt;p&gt;Callbacks are the original and usually simplest abstraction to first learn about asynchronous programming. Basically, when you have a function that you want to run asynchronously, you include a &amp;quot;callback function&amp;quot; as one of the input parameters. When the function finishes what it&#39;s doing, it will &amp;quot;call back&amp;quot; that function with some data if its successful. You can extend this by passing more than one callback function, usually one to handle when the function succeeds, and one for when there is an error.&lt;/p&gt;
&lt;p&gt;Example in JavaScript:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;console.log(&amp;quot;Start of my code&amp;quot;)
const myCallbackFunction = function(dataReturned) {
    console.log(&amp;quot;Got the data!&amp;quot;)
}

// Simulating a service call that takes 50ms to return data
// Then calls the callback function
setTimeout(myCallbackFunction, 50);

console.log(&amp;quot;End of my code&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Should result in the following output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Start of my code
End of my code
Here&#39;s the data returned
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://codepen.io/Nirespire/pen/QmrxgZ&quot;&gt;Run it here!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What&#39;s good&lt;/strong&gt;: A pretty simple abstraction for beginners to learn and easy to debug.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What&#39;s not so good&lt;/strong&gt;: So-called &amp;quot;callback hell&amp;quot; when you have to chain together multiple asynchronous operations, your code can get messy and unreadable fast.&lt;/p&gt;
&lt;h3&gt;Promises&lt;/h3&gt;
&lt;p&gt;Promises are a step up from callbacks in that instead of having to predefine how you want to handle the result of your asynchronous operation up front in the same context, you use what&#39;s called a Promise object to represent your request and handle it when and where you want.&lt;/p&gt;
&lt;p&gt;When you call an asynchronous function that supports Promises, it will immediately return a Promise object. This object can be in 1 of 3 states: &lt;em&gt;pending&lt;/em&gt;, &lt;em&gt;resolved&lt;/em&gt;, or &lt;em&gt;rejected&lt;/em&gt;. Each of these states means the request is still being worked on, the request has been completed with a result, or the request has failed with an error respectively.&lt;/p&gt;
&lt;p&gt;You can pass the promise object around, and when you are ready, you can use the built in &lt;code&gt;.then&lt;/code&gt; function to handle the result or the &lt;code&gt;.catch&lt;/code&gt; function to handle an error.&lt;/p&gt;
&lt;p&gt;Example in JavaScript:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;console.log(&amp;quot;Start of my code&amp;quot;);

function getMyData() {
  return new Promise(function(resolve, reject) {
    // Simulate getting the data successfully
    resolve(&amp;quot;Some data&amp;quot;);
  });
}

getMyData()
  .then(myData =&amp;gt; {
    console.log(&amp;quot;Got the data!&amp;quot;);
  })
  .catch(error =&amp;gt; {
    console.log(&amp;quot;something went wrong&amp;quot;);
  });

console.log(&amp;quot;End of my code&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Should result in the following output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;quot;Start of my code&amp;quot;
&amp;quot;End of my code&amp;quot;
&amp;quot;Got the data!&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://codepen.io/Nirespire/pen/dmeppB&quot;&gt;Run it here!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What&#39;s good&lt;/strong&gt;: Give&#39;s you a lot more flexibility to organize your code. You can chain together multiple asynchronous operations with &lt;code&gt;.then&lt;/code&gt; functions easily. Good library support to handle parallel groups of asynchronous operations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What&#39;s not so good&lt;/strong&gt;: Doesn&#39;t provide any runtime advantages like better performance compared to callbacks. Really just cleaner code.&lt;/p&gt;
&lt;h3&gt;Async/Await&lt;/h3&gt;
&lt;p&gt;The async/await abstraction is the new and shiny for developers looking to be on the cutting edge of JavaScript development. It is only recently getting standard support in browsers but has been available to use through transpilers like Babel. This is due mainly to the fact that async/await is really just syntactic sugar over the existing Promise abstraction.&lt;/p&gt;
&lt;p&gt;What async/await lets us do is write asynchronous code in a more linear fashion than callbacks or Promises. If a function is going to do an async operation, you just slap an &lt;code&gt;async&lt;/code&gt; keyword in front of it. Then when you call the async function, just provide the &lt;code&gt;await&lt;/code&gt; keyword before it, and your code will run as if it is waiting for the function to return before running the next line of code.&lt;/p&gt;
&lt;p&gt;This should be nothing new for anyone programming in a language that is written with the expectation of synchronous execution like Java or C++.&lt;/p&gt;
&lt;p&gt;Example in JavaScript:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function getMyData() {
  return new Promise(function(resolve, reject) {
    // Simulate getting the data successfully
    resolve(&amp;quot;Some data&amp;quot;);
  })
    .then(function(data){return data});
}

async function getMyAsyncData(){
  console.log(&amp;quot;Start of my code&amp;quot;);
  
  const myData = await getMyData();
  console.log(&amp;quot;Got my Data! &amp;quot;, myData);
  
  console.log(&amp;quot;End of my code&amp;quot;);
}

getMyAsyncData();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Should result in the following output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;quot;Start of my code&amp;quot;
&amp;quot;Got my Data! &amp;quot; &amp;quot;Some data&amp;quot;
&amp;quot;End of my code&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://codepen.io/Nirespire/pen/aYGmBQ&quot;&gt;Run it here!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What&#39;s good&lt;/strong&gt;: Let&#39;s your write asynchronous code linearly with no new constructs like callback functions or Promise object syntax. Since it&#39;s just Promises under the hood however, it&#39;s easy to debug and is by far the cleanest way to keep your code concise.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What&#39;s not so good&lt;/strong&gt;: As of writing this article, support for async/await is still picking up speed, both in tooling and with developers. It&#39;s supported by all the major browsers and Node, however backwards compatibility still requires polyfills. Check on its current support &lt;a href=&quot;https://caniuse.com/#feat=async-functions&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;If you&#39;re working with JavaScript, you&#39;re going to encounter one of these abstractions at some point. More likely, you&#39;re going to have to write some asynchronous code yourself. A good rule of thumb is if you are writing new code, start by using Promises, as they lend themselves to future maintainability the best. As the codebase grows, your code should stay cleaner comparatively than if you used callbacks. If you see places where the Promise syntax might be a bit too verbose, try to swap it out for async/await. Keep in mind what browsers/platforms you are building for and add transpilers or polyfills as necessary.&lt;/p&gt;
&lt;h3&gt;Further Reading&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Documentation on the Mozilla Developer Network:&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Callback_function&quot;&gt;Callbacks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;Promises&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function&quot;&gt;Async&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await&quot;&gt;Await&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://caniuse.com/&quot;&gt;CanIUse.com&lt;/a&gt;: to see what language features are supported by which browsers&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>What is CICD — Concepts in Continuous Integration and Deployment</title>
    <link href="https://sanjaynair.me/blog/2018-05-06-what-is-cicd/"/>
    <updated>2018-05-06T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2018-05-06-what-is-cicd/</id>
    <content type="html">&lt;aside class=&quot;editorial-note&quot; role=&quot;note&quot; aria-label=&quot;Editor&#39;s note&quot;&gt;
&lt;p class=&quot;editorial-note__header&quot;&gt;&lt;strong&gt;Editor&#39;s note &amp;middot; June 2026&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;editorial-note__body&quot;&gt;
&lt;p&gt;The Travis CI links in this post (&lt;code&gt;travis-ci.com&lt;/code&gt; and &lt;code&gt;travis-ci.com/getting_started&lt;/code&gt;) are preserved as the canonical service URL but are largely obsolete in 2026 - Travis CI retired its free open-source tier in 2020 and the service has since been overshadowed by &lt;a href=&quot;https://github.com/features/actions&quot;&gt;GitHub Actions&lt;/a&gt;, &lt;a href=&quot;https://circleci.com/&quot;&gt;CircleCI&lt;/a&gt;, and other modern CI providers.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;Modern software moves fast and demands more from developers than ever. Tools and concepts around CICD help developers deliver value faster and more transparently.&lt;/p&gt;
&lt;p&gt;You might have heard the term CI, Continuous Integration, CICD, or Continuous delivery. It&#39;s a concept that goes by many names but covers the same basic ideas. In short, it lays out some practices to follow in order for the code you write to more quickly and safely get to your users and ultimately generate value.&lt;/p&gt;
&lt;p&gt;While this idea might seem best suited for software written for enterprises or some capital venture, I bet that by the end of this article you will find CICD to be a valuable practice whether you&#39;re building enterprise applications at scale or simply trying to get your personal project up and running.&lt;/p&gt;
&lt;h3&gt;CI : Continuous Integration&lt;/h3&gt;
&lt;p&gt;The CI part of CICD can be summarized with: you want all parts of what goes into making your application go to the same place and run through the same processes with results published to an easy to access place.&lt;/p&gt;
&lt;p&gt;The simplest example of continuous integration is something you might not have even thought of being significant: committing all your application code in a single repository! While that may seem like a no-brainer, having a single place where you &amp;quot;integrate&amp;quot; all your code is the foundation for extending other, more advanced practices.&lt;/p&gt;
&lt;p&gt;Once you have all your code and changes going to the same place, you can run some processes on that repository every time something changes. This could include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run automatic code quality scans on it and generate a report of how well your latest changes adhere to good coding practices&lt;/li&gt;
&lt;li&gt;Build the code and run any automated tests that you might have written to make sure your changes didn&#39;t break any functionality&lt;/li&gt;
&lt;li&gt;Generate and publish a test coverage report to get an idea of how thorough your automated tests are&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These simple additions (made easy with tooling that will be mentioned later) allows you, the developer, to focus on writing the code. Your central repository of code is there to receive your changes while your automated processes can build, test, and scan your code while providing reports.&lt;/p&gt;
&lt;h3&gt;CD : Continuous Deployment&lt;/h3&gt;
&lt;p&gt;Deploying code can be hard. If you&#39;ve ever been jamming on building a project for a while, shifting your mindset to getting it ready to be deployed can be jarring.&lt;/p&gt;
&lt;p&gt;One of the best things you can do to avoid this, much like other things in software, is to automate it! Make it so that your code gets automatically deployed to wherever you or your users can get to it.&lt;/p&gt;
&lt;p&gt;There are many freely available tools to let you do this easily. One popular example is &lt;a href=&quot;https://travis-ci.com/&quot;&gt;Travis CI&lt;/a&gt;, which integrates directly with Github. You can configure Travis to automatically run CI tasks like unit tests and push your code to a hosting platform like Heroku every time you push new changes to a branch.&lt;/p&gt;
&lt;h3&gt;Examples of CICD in Real Projects&lt;/h3&gt;
&lt;p&gt;You can find examples of CICD being used all over the place; you just need to know what to look for. Usually, its as easy as finding some colorful badges linked at the top of a Github README.&lt;/p&gt;
&lt;h4&gt;ReactJS&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2018-05-06-what-is-cicd/1xXphK15Zv2ANybcW288qN6A.png&quot; alt=&quot;React CICD badges&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The React JavaScript framework developed and maintained by Facebook has a great example of a robust and high visible CICD pipeline. If you visit its &lt;a href=&quot;https://github.com/facebook/react&quot;&gt;Github page&lt;/a&gt; and click through the badges displayed at the top of their README, you can get an idea of what type of automated processes they run their codebase through. The Coverage badge links to &lt;a href=&quot;https://coveralls.io/&quot;&gt;Coveralls&lt;/a&gt;, which is a tool to display unit test coverage reports. You can click on the &lt;a href=&quot;https://circleci.com/gh/facebook/react&quot;&gt;CircleCI&lt;/a&gt; badge which shows a history of all the builds automatically run against Pull Requests submitted by contributors. If you click on a build, you can even see every step in the CI process and how their pipeline is configured.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2018-05-06-what-is-cicd/1xefvjxrDcIsW3Vkc2UG-7Rg.png&quot; alt=&quot;CircleCI build steps&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;Homebrew&lt;/h4&gt;
&lt;p&gt;If you do any sort of development on MacOS, then you&#39;ve probably at least heard of the popular package manager &lt;a href=&quot;https://github.com/Homebrew/brew#contributing&quot;&gt;Homebrew&lt;/a&gt;. It uses TravisCI with coverage reporting on &lt;a href=&quot;https://codecov.io/gh/Homebrew/brew&quot;&gt;codecov.io&lt;/a&gt;. Check out &lt;a href=&quot;https://codecov.io/gh/Homebrew/brew&quot;&gt;Homebrew/brew&lt;/a&gt; on Github and scroll down to the Contributing section to find those same familiar badges.&lt;/p&gt;
&lt;h4&gt;TensorFlow&lt;/h4&gt;
&lt;p&gt;Machine Learning and AI related projects have been rising in popularity for a while now and I think Google&#39;s TensorFlow library has had a lot to do with that. TensorFlow is an open source Python framework for building ML and AI applications. Their Github README is decorated with the same familiar badges but with an additional twist.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2018-05-06-what-is-cicd/1xsWXSg7ezlnPTAUAjVn2qYw.png&quot; alt=&quot;TensorFlow build status&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Since TensorFlow is a cross-platform tool that can run on CPU and GPU hardware, the maintainers have set up multiple pipelines to build and test the tool on different operating system platforms and CPU/GPU configurations. Their pipelines are built using &lt;a href=&quot;https://jenkins.io/&quot;&gt;Jenkins&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;re looking for more examples, I would start by looking through what&#39;s &lt;a href=&quot;https://github.com/search?q=stars:%3E1&amp;amp;s=stars&amp;amp;type=Repositories&quot;&gt;popular on Github&lt;/a&gt;. Chances are, if there are a lot of users and contributes to the project, there&#39;s probably some publicly visible CICD process in place to help the project scale with the number of developers involved with it.&lt;/p&gt;
&lt;p&gt;Consider some open source tool or library you might be using right now. See if you can track down if it uses CICD in some way. If not, maybe that&#39;s something you could contribute back to the project!&lt;/p&gt;
&lt;h3&gt;Next Steps&lt;/h3&gt;
&lt;p&gt;Now that you hopefully have a better idea of what CICD actually is and how it is woven into the way modern software is built, you can take those considerations into mind when working on your next project. Always give some thought to what processes could be automated when changes are introduced. How can information about the project be more transparently communicated to the team working on it? How can the project more efficiently be delivered to its users?&lt;/p&gt;
&lt;p&gt;I encourage you to pick up a CICD tool and introduce it to one of your existing projects or use it when you&#39;re spinning up that next personal project.&lt;/p&gt;
&lt;h4&gt;Tools:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://travis-ci.com/getting_started&quot;&gt;TravisCI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://circleci.com/&quot;&gt;CircleCI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gocd.org/&quot;&gt;GoCD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://coveralls.io/&quot;&gt;Coveralls&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sonarqube.org/&quot;&gt;SonarQube&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Convoluted Convolution</title>
    <link href="https://sanjaynair.me/blog/2018-05-29-convoluted-convolution/"/>
    <updated>2018-05-29T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2018-05-29-convoluted-convolution/</id>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;This post was originally published when I was in college in 2014. I was enrolled in a digital design class that dealt with designing and implementing digital circuits through software. It was one of the first posts I shared publicly where I tried to write about something I learned about and work on.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This past semester, I had the opportunity work on a couple of pretty interesting class projects. Normally, I would say my classes are not usually the prime source of creative projects, and therefore would avoid writing about them altogether. However, a couple of them stood out to me as valuable learning experiences. Each gave me insight into an aspect of technology that I was worth discussing in detail. The first project I would like to discuss was working with the VHDL programing language and FPGA hardware to implement a one-dimensional time domain convolution application. The project gave me some intriguing insight into the differences between working with hardware vs. software platforms. On the surface, the project was easy. Implement a custom circuit to perform one-dimensional convolution with a constant kernel size of 96, 16 bit elements. If none of this is making sense, read this to get familiar with what convolution is all about.&lt;/p&gt;
&lt;p&gt;An implementation of this application in software could be condensed down to these short lines of code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 1D convolution
int y[outputSize];
for (i=0; i &amp;lt; outputSize; i++) { 
	y[i] = 0;
	for (j=0; j &amp;lt; kernelSize; j++) { 
		y[i] += x[i - j] * h[j]; 
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In one dimension, the kernel is represented as a constant array of values that are repeatedly multiplied over an input array in the same manner as a sliding window. The output can be described as a signal that has been “convoluted” by the kernel.&lt;/p&gt;
&lt;p&gt;At a high level, our hardware implementation would have three parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An input SRAM that would hold the input signal to be fed into the convolution routine&lt;/li&gt;
&lt;li&gt;The application datapath, which in this case would hold a 96 element wide multiply-accumulate tree to perform the convolution in parallel&lt;/li&gt;
&lt;li&gt;An output SRAM that would store the results returned from the datapath&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;How this would go in software&lt;/h1&gt;
&lt;p&gt;Designing this application in software, even for higher dimensional inputs, seems trivial. A few lines of code and a user-friendly interface (which might end up taking more time to build) and you’re done. You have a vast library of languages, function libraries, data structures, and tools by which to develop, debug, and publish the application swiftly and cleanly. What you write is purely deterministic and would never act randomly unless you explicitly wrote such a feature in. If something isn’t working right, then it was your fault. Simply copy the code I provided above into your language of choice, debug, test, and you’re off.&lt;br /&gt;
Welcome to the world of hardware&lt;/p&gt;
&lt;p&gt;The previous description had been my experience for the past 3 years when building applications in general. This is not to make it seem easy (it is certainly NOT easy), but rather to contrast it with my experience developing the same application in hardware. Software always works the way you have specified. Whether or not you made a mistake is your problem. Hardware sometimes works the way you specified. However, it will always be victim to the laws of physics over which we sometimes have no power.&lt;/p&gt;
&lt;p&gt;First, a bit of background on the development process. This application was to be first designed in software with VHDL. My group members and I could thoroughly test every single circuit we designed using hardware simulation software (ModelSim) to provide some assurance that our digital design made sense before we put it onto a physical circuit. The design would then be synthesized onto a Xilinx Vertex4 FPGA housed on a Nallatech PCI Express card housed in a server room somewhere on the University campus. If that last part sounded a bit weird, it was meant to. We had not physical access to the hardware the application would run on. Our design was synthesized into a “bitfile” that had to be remotely uploaded to the server. Then, through software, we would configure the FPGA with the bitfile and run the circuit with some input. The only feedback we could get was from the software output on the console we were interacting with. The process was basically design, test, synthesize, run, and pray everything worked on the board. You might say, “That was the point of all that testing you did before you ran it on the FPGA, right? To make sure execution on the board worked perfectly!” Well, partially. Unlike software where, if all variabilities are known then a piece of code should always run as tested, hardware can be victim to the randomness of the physical world.&lt;/p&gt;
&lt;h1&gt;Metastability — how physics beat us&lt;/h1&gt;
&lt;p&gt;Without boring you with the fine details, certain aspects of our circuit had the potential inherent randomness built into them. Connected sequential circuit elements always expect each other to only change on a rising (or falling) clock edge. When connected elements like registers are running off different clock frequencies, this guarantee disappears and some really weird stuff can happen. Output signals can resolve to incorrect values and flood your circuit with errors. This phenomenon can be attributed to metastability, or the unpredicatable “third” state of digital signals. Anyone who has worked with even the simplest digital logic (even just in theory) knows that a single bit out of place could destroy the logical soundness of a system.&lt;/p&gt;
&lt;p&gt;Without the proper precautions and countermeasures, running a circuit on the board would result in perfectly non-deterministic results. And the worst part, there was basically no way for us to debug the problem. First, because the problem itself could be changing on each execution. Second, the physical hardware was physically inaccessible to us. Third and most importantly, the software simulation we used could not simulate metastability. Even if our simulation worked perfectly, it was no guarantee the circuit would work on the board.&lt;/p&gt;
&lt;h1&gt;Our Project Results&lt;/h1&gt;
&lt;p&gt;When the project was finally completed, it had been thoroughly tested and run on the board with no errors. After the files had been submitted and when the due date came around, we ran the project again…but there were quite a few errors this time. Not a single line of code had been changed. The simulation still showed 100% on all tests. Yet the circuit consistently passed only 96% of the tests on the board. We still have no idea why this happened, and we never might. So I learned how unpredictable and mysterious hardware design can be sometimes.&lt;/p&gt;
&lt;h1&gt;Conclusions&lt;/h1&gt;
&lt;p&gt;Metastability is nothing new to hardware design. Plenty of solutions have been created to overcome this issue in circuits with multiple clocks to ensure they perform deterministically (at least with a significantly high probability). Yet, these ideas really got me thinking about the primitive building blocks of computing as a whole. Our physical world is said to be deterministic and governed by the laws of physics (don’t mention quantum uncertainty because I still need to do more research before tackling that topic properly). We build digital circuits with the assurance that a 1 would be a 1 and a 0 would be a 0 exactly when we want. But no matter how tightly we constrain the physics, when even the slightest element of variability enters the scenario, everything falls apart. If a single bit on the input to a flip-flop changes a nanosecond too early, our deterministic assumptions disappear. We may build our circuits around this random possibility, but that is exactly the point I found to be important: when we design in hardware, we must overcome physics itself.&lt;/p&gt;
&lt;p&gt;Software is deterministic because it runs on hardware that was designed to function perfectly 99.999% of the time. It is designing directly with hardware that has made me acknowledge this fact and come to appreciate how different software design is as its core.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>How to Make a Q&amp;A Chatbot With Machine Learning</title>
    <link href="https://sanjaynair.me/blog/2018-07-11-how-to-make-a-qa-chatbot-with-machine-learning/"/>
    <updated>2018-07-11T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2018-07-11-how-to-make-a-qa-chatbot-with-machine-learning/</id>
    <content type="html">&lt;p&gt;This article will teach you how to write your very own Slack chatbot that answers simple questions using some basic machine learning tools. Most of the more complex stuff around natural language processing and math behind creating machine learning models is mostly abstracted out, leaving room for us to easily build a finished product in a pretty short amount of time. If you&#39;re looking for a simple and effective way to get a semi-intelligent bot answering questions on Slack fast, then this guide is the one for you.&lt;/p&gt;
&lt;p&gt;If you want to skip to the finished code, check out the link to the Github repo &lt;a href=&quot;https://github.com/Nirespire/FAQBot&quot;&gt;here&lt;/a&gt; or at the end of the post.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Edit 10/27/19&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Because the library I used (Botkit) had a few critical security vulnerabilities and I couldn&#39;t get the latest version of the library working, I switched over to the &lt;a href=&quot;https://slack.dev/node-slack-sdk/rtm-api&quot;&gt;Slack RTM API&lt;/a&gt;. The below code examples should work just fine, but if you&#39;re interested in using the latest version of the code, check out the example repo at the bottom. &lt;a href=&quot;https://github.com/Nirespire/FAQBot/pull/2&quot;&gt;Link to Pull Request with all code changes&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Some Setup&lt;/h3&gt;
&lt;p&gt;This guide assumes you have basic knowledge about Node development, as this will be the main tool we will be using to build with. You&#39;re also going to need the following installed and working on your machine. I&#39;m usually most productive in a unix-like terminal environment, aka bash. Here&#39;s what else you will need:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;An installation of NodeJS with the npm package manager. I used Node v10.1.0 with npm v6.1.0 when writing this, but any relatively recent version should work (like v6 and up).&lt;/li&gt;
&lt;li&gt;A Slack workspace that you have administrative rights in. If you can&#39;t find one, just &lt;a href=&quot;https://slack.com/get-started#create&quot;&gt;make a new one&lt;/a&gt;. This is the playground where we will be developing and testing out bots capabilities.&lt;/li&gt;
&lt;li&gt;A code editor. I&#39;m a big fan of &lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;VS Code&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once you have your Slack workspace open, go to any channel and click on the settings gear icon. We&#39;re going to add an app to our workspace.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2018-07-11-how-to-make-a-qa-chatbot-with-machine-learning/1xbyGuMKAATI6kEB-rGHIG-g.png&quot; alt=&quot;How to add an integration to a Slack workspace&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Search for bot and add the Bots integration.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2018-07-11-how-to-make-a-qa-chatbot-with-machine-learning/1xU6y3jGXnT0v9Qvat7osdTw.png&quot; alt=&quot;Searching for the &amp;quot;Bots&amp;quot; integration in Slack&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Add the configuration and give it a name you like. This will basically create a special type of user in your workspace you can send messages to, just like any other user. You can change the name and icon of the bot later, but what we need now is the &lt;strong&gt;API Token&lt;/strong&gt; value that get&#39;s generated. &lt;em&gt;&lt;strong&gt;BE SURE TO KEEP THIS VALUE SECRET&lt;/strong&gt;&lt;/em&gt;. If someone gets access to this, they get free access to read and post messages in your workspace.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2018-07-11-how-to-make-a-qa-chatbot-with-machine-learning/1xez3ze-YKqbuLvlCsAqpwxA.png&quot; alt=&quot;Copy the API token generated on this page (blacked out in this picture)&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Keep that value handy. We&#39;re going to use it soon as we start writing some code.&lt;/p&gt;
&lt;h3&gt;Time to Code&lt;/h3&gt;
&lt;h4&gt;Basic bot setup&lt;/h4&gt;
&lt;p&gt;To get something set up, let&#39;s start by getting some boilerplate code out of the way. The following npm commands should get the basics set up.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Starting in the directory where your code is going
npm init -f
npm i --save natural botkit@0.7.4 dotenv
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice the three libraries we will be using.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/NaturalNode/natural&quot;&gt;natural&lt;/a&gt;: Provides basic text processing and classification functions&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/howdyai/botkit&quot;&gt;botkit&lt;/a&gt;: A wrapper around the Slack API to easily write programs with integration with Slack&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/motdotla/dotenv&quot;&gt;dotenv&lt;/a&gt;: Let&#39;s us manage environment variables in a file for local development and testing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From there we can start writing some code. Let&#39;s start by making sure we can connect to Slack using the API token we set up previously. Create a file named &lt;code&gt;.env&lt;/code&gt; and paste in the following contents replacing the part after the &lt;code&gt;=&lt;/code&gt; with your API token.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SLACK_API_TOKEN=
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;If you are using something like git to maintain your code changes, make sure to add &lt;code&gt;.env&lt;/code&gt; to your &lt;code&gt;.gitignore&lt;/code&gt; file so you don&#39;t accidentally push it somewhere others can see it!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Next let&#39;s get to the real code. We&#39;re going to start with some simple setup to make sure we can connect to our Slack workspace using the API token and with some help from the botkit library. We can start with the an &lt;code&gt;index.js&lt;/code&gt; file like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const botkit = require(&#39;botkit&#39;)

// Load our environment variables from the .env file
require(&#39;dotenv&#39;).config();

// What are the types of chats we want to consider
// In this case, we only care about chats that come directly to the bot
const scopes = [
    &#39;direct_mention&#39;,
    &#39;direct_message&#39;,
    &#39;mention&#39;
];

// Get our Slack API token from the environment
const token = process.env.SLACK_API_TOKEN;

// Create a chatbot instance using Botkit
const Bot = BotKit.slackbot({
    debug: true,
    storage: undefined
});

// Function to handle an incoming message
// In this example function the bot will just reply with &amp;quot;got it&amp;quot;
function handleMessage(speech, message) {
    console.log(speech, message);
    speech.reply(message, &amp;quot;got it&amp;quot;);
}

// Configure the bot
// .* means match any message test
// The scopes we pass determine which kinds of messages we consider (in this case only direct message or mentions)
// handleMessage is the function that will run when the bot matches a message based on the text and scope criteria
Bot.hears(&#39;.*&#39;, scopes, handleMessage);

// Instantiate a chatbot using the previously defined template and API 
// Open a connection to Slack&#39;s real time API to start messaging
Bot.spawn({
    token: token
}).startRTM();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code above should be simple enough to get your bot up and running. You just need to execute &lt;code&gt;node index.js&lt;/code&gt;, and your bot should connect to the Slack API and show up as &amp;quot;Active&amp;quot; in your workspace. If you send it a message, it should reply back with &amp;quot;got it&amp;quot;. You could also modify the code to have the bot respond with whatever you like.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2018-07-11-how-to-make-a-qa-chatbot-with-machine-learning/1xtzZ91By6WcIg-Fh8X11oPw.png&quot; alt=&quot;It&#39;s alive!&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;Adding some machine learning&lt;/h4&gt;
&lt;p&gt;Now that we have the basic setup done, we can start to add some intelligence to our bot. Since we&#39;re aiming to have our bot answer questions, we need to take a bit of an open ended approach. Not everyone asks questions the same way. So we need a way to match different questions or phrases coming in with what topic they&#39;re associated with, and then give the appropriate answer.&lt;/p&gt;
&lt;p&gt;Like I might ask: &amp;quot;What time is it?&amp;quot; while you might ask the same thing by typing &amp;quot;Give me the current time.&amp;quot; Both phrases could be matched to the topic of &amp;quot;current-time,&amp;quot; so we can&#39;t just use strict equality in our code. We are going to employ some machine learning to do this fuzzy matching.&lt;/p&gt;
&lt;p&gt;The first thing we need for this is a training data set with a pre-populated set of phrases, associated labels, and appropriate responses or answers. The training data format will be JSON that outlines some phrases and keywords that represent a type of question and a single answer that the bot should respond with when it sees a question like those phrases or keywords. For example, here&#39;s a training data set with only two topics, each with a set of possible phrases, and an appropriate response:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
    &amp;quot;self&amp;quot;: {
        &amp;quot;questions&amp;quot;: [
            &amp;quot;introduce yourself&amp;quot;,
            &amp;quot;sup&amp;quot;,
            &amp;quot;hi&amp;quot;,
            &amp;quot;hello&amp;quot;
        ],
        &amp;quot;answer&amp;quot;: &amp;quot;Hello! I&#39;m a chatbot tasked with answering your questions! `Beep, Boop` :robot_face:&amp;quot;
    },
    &amp;quot;world&amp;quot;: {
        &amp;quot;questions&amp;quot;: [
            &amp;quot;what is the world&amp;quot;,
            &amp;quot;answer to the universe and everything&amp;quot;
        ],
        &amp;quot;answer&amp;quot;: &amp;quot;42&amp;quot;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Put this in a file called &lt;code&gt;trainingData.json&lt;/code&gt; in the root of your project.&lt;/p&gt;
&lt;p&gt;Each group of questions and answer has a label. This is how our bot will try to classify all the input it receives and figure out how to respond.&lt;/p&gt;
&lt;p&gt;Now let&#39;s add some code to consume the data and train a classifier we can later use to intelligently match and respond to questions. We can create a simple function to read our &lt;code&gt;trainingData.json&lt;/code&gt; file and convert it into a JavaScript object we can read from.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;/**
 * Function to easily parse a given json file to a JavaScript Object
 * 
 * @param {String} filePath 
 * @returns {Object} Object parsed from json file provided
 */
function parseTrainingData(filePath) {
    const trainingFile = fs.readFileSync(filePath);
    return JSON.parse(trainingFile);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we can load our training data using the function like so.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// Load our training data
const trainingData = parseTrainingData(&#39;./trainingData.json&#39;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next up is creating what&#39;s called a classifier to consume our training data and create a machine learning model to later make decisions to incoming questions based on what it has learned. Basically, given the set of phrases and responses we provide, the model should be able to extrapolate what response to provide to a phrase it sees as similar to one it has seen before. If you want to learn more about what exactly a classifier is in the context of machine learning, &lt;a href=&quot;https://www.udacity.com/course/intro-to-machine-learning--ud120&quot;&gt;check this out&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;re going to use a library for this. So start by importing the &lt;code&gt;natural&lt;/code&gt; library we installed earlier and create a new &lt;code&gt;LogisticRegressionClassifier&lt;/code&gt; at the top of you file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const NLP = require(&#39;natural&#39;);
// Create a new classifier to train
const classifier = new NLP.LogisticRegressionClassifier();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next we need a function for the classifier to be able to ingest training examples. In this case: what questions (phrases) match up to a given answer type (label).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;/**
 * Will add the phrases to the provided classifier under the given label.
 * 
 * @param {Object} classifier
 * @param {String} label
 * @param {Array.String} phrases
 */
function trainClassifier(classifier, label, phrases) {
    console.log(&#39;Teaching set&#39;, label, phrases);
    phrases.forEach((phrase) =&amp;gt; {
        console.log(`Teaching single ${label}: ${phrase}`);
        classifier.addDocument(phrase.toLowerCase(), label);
    });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we have a way for our bot to learn some examples of phrases it might see and classify them appropriately, we need a way for it to handle sending back a proper reply.&lt;/p&gt;
&lt;p&gt;Since our training data includes an answer for a set of example phrases under a label, we can use it to have the bot send back the same reply. So if our chatbot sees an incoming message that looks like &amp;quot;sup&amp;quot;, based on our training data, it should classify it with the label &amp;quot;self&amp;quot; and send back the answer associated with that label: &amp;quot;Hello! I&#39;m a chatbot tasked with answering your questions! &lt;code&gt;Beep, Boop&lt;/code&gt; :robot_face:&amp;quot;. Look back at &lt;code&gt;trainingData.json&lt;/code&gt; if you need to see that example again.&lt;/p&gt;
&lt;p&gt;One thing it considers is the fact that our classifier&#39;s guesses will usually not be perfect. Each guess will have a different confidence value associated with it corresponding to how confident the classifier is to matching a label to the phrase provided. As a result, we need to put in some logic to only give a response if the classifier is pretty certain it has the right guess of how to label the input phrase. If not, we basically respond with &amp;quot;¯_(ツ)_/¯ don&#39;t know what you&#39;re talking about. I&#39;m not trained to respond to that.&amp;quot;&lt;/p&gt;
&lt;p&gt;That&#39;s a lot of explaining, let&#39;s see what our function to interpret incoming text looks like.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;/**
 * Uses the trained classifier to give a prediction of what
 * labels the provided pharse belongs to with a confidence
 * value associated with each and a a guess of what the actual
 * label should be based on the minConfidence threshold.
 * 
 * @param {String} phrase 
 * 
 * @returns {Object}
 */
function interpret(phrase) {
    console.log(&#39;interpret&#39;, phrase);
    const guesses = classifier.getClassifications(phrase.toLowerCase());
    console.log(&#39;guesses&#39;, guesses);
    const guess = guesses.reduce((x, y) =&amp;gt; x &amp;amp;&amp;amp; x.value &amp;gt; y.value ? x : y);
    return {
        probabilities: guesses,
        guess: guess.value &amp;gt; (0.7) ? guess.label : null
    };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice where we check if &lt;code&gt;guess.value &amp;gt; 0.7&lt;/code&gt;. What this says is that if our classifier does not match a label with a confidence of at least 70%, then we say we didn&#39;t find a match. Whatever message came in didn&#39;t match anything we trained our classifier to respond to, so we return &lt;code&gt;null&lt;/code&gt; and our ¯_(ツ)_/¯ response.&lt;/p&gt;
&lt;p&gt;This is like if someone asked you &amp;quot;What time is it?&amp;quot; you know exactly how to respond because you learned what that question means and how to get the answer. If someone game up and said &amp;quot;Blargen Flostel Bhigba&amp;quot; chances are you never learned how to respond to that, so you&#39;ll probably throw up a ¯_(ツ)_/¯.&lt;/p&gt;
&lt;p&gt;So now we need a function to match up that label with the answer that corresponds to that label. Let&#39;s modify our &lt;code&gt;handleMessage&lt;/code&gt; function to do this. Instead of sending back the same reply to everything, let&#39;s &lt;code&gt;interpret&lt;/code&gt; what the message was, then use the label our classifier generates to provide the appropriate answer based on our training data. If our attempt to interpret the message didn&#39;t yield a result, the bot can simply reply that it didn&#39;t understand.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;/**
 * Callback function for BotKit to call. Provided are the speech
 * object to reply and the message that was provided as input.
 * Function will take the input message, attempt to label it 
 * using the trained classifier, and return the corresponding
 * answer from the training data set. If no label can be matched
 * with the set confidence interval, it will respond back saying
 * the message was not able to be understood.
 * 
 * @param {Object} speech 
 * @param {Object} message 
 */
function handleMessage(speech, message) {
    const interpretation = interpret(message.text);
    console.log(&#39;InternChatBot heard: &#39;, message.text);
    console.log(&#39;InternChatBot interpretation: &#39;, interpretation);

    if (interpretation.guess &amp;amp;&amp;amp; trainingData[interpretation.guess]) {
        console.log(&#39;Found response&#39;);
        speech.reply(message, trainingData[interpretation.guess].answer);
    } else {
        console.log(&#39;Couldn&#92;&#39;t match phrase&#39;)
        speech.reply(message, &#39;Sorry, I&#92;&#39;m not sure what you mean&#39;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Last up, let&#39;s bring it all together by calling all the functions we just created and the existing ones we have to get our bot up and running. Notice the code at the bottom is basically the same, except we&#39;ve modified the &lt;code&gt;handleMessage&lt;/code&gt; function to be a bit smarter this time around.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// For each of the labels in our training data,
// train and generate the classifier
var i = 0;
Object.keys(trainingData).forEach((element, key) =&amp;gt; {
    trainClassifier(classifier, element, trainingData[element].questions);
    i++;
    if (i === Object.keys(trainingData).length) {
        classifier.train();
        const filePath = &#39;./classifier.json&#39;;
        classifier.save(filePath, (err, classifier) =&amp;gt; {
            if (err) {
                console.error(err);
            }
            console.log(&#39;Created a Classifier file in &#39;, filePath);
        });
    }
});

// Configure the bot
// .* means match any message test
// The scopes we pass determine which kinds of messages we consider (in this case only direct message or mentions)
// handleMessage is the function that will run when the bot matches a message based on the text and scope criteria
Bot.hears(&#39;.*&#39;, scopes, handleMessage);

// Instantiate a chatbot using the previously defined template and API token
// Open a connection to Slack&#39;s real time API to start messaging
Bot.spawn({
    token: token
}).startRTM();
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Taking it for a spin&lt;/h3&gt;
&lt;p&gt;Let&#39;s see what our bot can do! Go ahead and run &lt;code&gt;node index.js&lt;/code&gt; in your console in the root of your project directory. If all goes to plan, you should see your bot injecting your training data examples and start up waiting for input.&lt;/p&gt;
&lt;p&gt;Head back to Slack and try to ask it to introduce itself!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2018-07-11-how-to-make-a-qa-chatbot-with-machine-learning/1x03cYxuxELUoIsE5_5Zp5sg.png&quot; alt=&quot;It&#39;s alive! (and a little intelligent)&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Ask it something else you trained it to respond to!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2018-07-11-how-to-make-a-qa-chatbot-with-machine-learning/1xDbtx99vit0Q19INdUgh_lg.png&quot; alt=&quot;Such wisdom&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If you ask it something it hasn&#39;t been trained for, expect an appropriate response.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2018-07-11-how-to-make-a-qa-chatbot-with-machine-learning/1xuYcyfVwukojbgSxPPDfztw.png&quot; alt=&quot;But not magic&quot; /&gt;&lt;/p&gt;
&lt;p&gt;But you could always train the bot to respond to that by adding it to your training data! Just create a new label and add some questions and an answer you&#39;d like the bot to respond with.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;I was going to write some extra stuff about how to deploy the bot somewhere and potential ideas for enhancements, but this post has already become longer than I anticipated. I never did get around to writing that follow up, but in the meantime, please comment with your feedback. Was following along easy enough? What skill level are you at with Node development or ML concepts? Also don&#39;t forget to share the cool bots you create!&lt;/p&gt;
&lt;h4&gt;Other resources&lt;/h4&gt;
&lt;p&gt;Complete code example available here: &lt;a href=&quot;https://github.com/Nirespire/FAQBot&quot;&gt;Nirespire/FAQBot&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Udacity Intro to Machine Learning: &lt;a href=&quot;https://www.udacity.com/course/intro-to-machine-learning--ud120&quot;&gt;intro-to-machine-learning--ud120&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The Wide World of Databases</title>
    <link href="https://sanjaynair.me/blog/2018-08-27-the-wide-world-of-databases/"/>
    <updated>2018-08-27T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2018-08-27-the-wide-world-of-databases/</id>
    <content type="html">&lt;aside class=&quot;editorial-note&quot; role=&quot;note&quot; aria-label=&quot;Editor&#39;s note&quot;&gt;
&lt;p class=&quot;editorial-note__header&quot;&gt;&lt;strong&gt;Editor&#39;s note &amp;middot; June 2026&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;editorial-note__body&quot;&gt;
&lt;p&gt;Two external references in this post have been refreshed: the Stack Overflow 2018 Developer Survey citation in the image caption below was updated from &lt;code&gt;insights.stackoverflow.com&lt;/code&gt; (the old subdomain Stack Overflow used for survey results) to the current &lt;a href=&quot;https://survey.stackoverflow.co/2018/&quot;&gt;survey.stackoverflow.co&lt;/a&gt;. The RethinkDB link further down is preserved, but note that RethinkDB the company shut down in 2016; the project is now community-maintained under the Linux Foundation.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;Working in software, it&#39;s easy to get caught up in all the latest and greatest technologies and frameworks. Every other week there seems to be a new JavaScript framework that &amp;quot;solves&amp;quot; all your problems. However, one of the most fundamental pieces of any non-trivial application is how you store and retrieve your data, i.e. your database.&lt;/p&gt;
&lt;p&gt;In this post, I&#39;ll go over some of the most common types of databases you might encounter in modern software development and what makes them unique.&lt;/p&gt;
&lt;h2&gt;Relational Databases&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Probably what they&#39;re teaching at school.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The trusty relational database (RDB) is usually the first thing you encounter if you take the traditional, academic avenue into software development. This is very much on purpose, as shown by the StackOverflow Developer Skills Survey from 2018, four out of the five most used database technologies by all respondents were RDBs (excluding MongoDB).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2018-08-27-the-wide-world-of-databases/1xGtHSGssY-c-WBOY0hsbcpA.png&quot; alt=&quot;Source: https://survey.stackoverflow.co/2018/#technology-databases&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If you&#39;re planning on taking your learned skills from school into industry, you&#39;re probably going to need to know something about RDBs.&lt;/p&gt;
&lt;p&gt;RDBs are designed around the mathematical concepts of &lt;a href=&quot;https://en.wikipedia.org/wiki/Relational_algebra&quot;&gt;relational algebra&lt;/a&gt;. Everything you can do in a RDB can be modeled with a relational algebra expression. The SQL query language is designed after these expressions and provides a pretty simple interface to interact with data. Efficiently organizing your data requires following the rules of &lt;a href=&quot;https://en.wikipedia.org/wiki/Database_normalization&quot;&gt;normalization&lt;/a&gt; or the normal forms. Each entry is identified by a &lt;strong&gt;primary key&lt;/strong&gt; with data structured into &lt;strong&gt;tables&lt;/strong&gt; that can be joined together.&lt;/p&gt;
&lt;p&gt;RDBs have been around quite a long time (&lt;a href=&quot;https://www.ibm.com/history/relational-database&quot;&gt;back in the 1970s&lt;/a&gt;) and are very good for general purpose data access patterns for applications. As a result, they are often the go-to choice for general application workloads for the web and enterprises.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why they&#39;re good:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Commonly used around industry with wide support&lt;/li&gt;
&lt;li&gt;Very efficient and fast if following well established practices for modeling data and systems administration&lt;/li&gt;
&lt;li&gt;Great for simple application workloads like writing and reading small chunks of data on well-defined identifiers or keys&lt;/li&gt;
&lt;li&gt;Usually &lt;a href=&quot;https://en.wikipedia.org/wiki/ACID_%28computer_science%29&quot;&gt;ACID&lt;/a&gt; compliant, meaning they provide strong guarantees about the integrity of your data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Why they&#39;re not so good:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Typically, relational models of data are hard to change once they&#39;re heavily in use, limiting effectiveness when building fast-changing POCs&lt;/li&gt;
&lt;li&gt;Running through very large sets of data for aggregations can be very inefficient&lt;/li&gt;
&lt;li&gt;Performing &amp;quot;fuzzy&amp;quot; queries when a key or search query isn&#39;t well-defined&lt;/li&gt;
&lt;li&gt;Horizontal scalability isn&#39;t usually built into the implementations and are usually achieved through some higher level abstraction layer. You might find real-world implementations to be very monolithic as a result.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Some Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mysql.com/&quot;&gt;MySQL&lt;/a&gt; — Free, opensource, &lt;a href=&quot;https://www.mysql.com/customers/view/?id=1269&quot;&gt;used widely at Uber&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.postgresql.org/&quot;&gt;Postgres&lt;/a&gt; — Free, opensource, also widely used in industry&lt;/li&gt;
&lt;li&gt;SQLite — Free, opensource, stores all its data in a single file, commonly used in embedded applications like smartphones&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ibm.com/analytics/us/en/db2/&quot;&gt;IBM DB2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oracle.com/database/index.html&quot;&gt;OracleDB&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Document Databases&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;You&#39;ve heard of MongoDB, right?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Document databases usually fall under the umbrella of NoSQL databases. They typically don&#39;t follow concepts of relational algebra in their design and you usually don&#39;t interact with them through SQL. The rules as to how to define a data model are a lot more flexible. Each entry in your database is a &lt;strong&gt;document&lt;/strong&gt;, which is usually just a JSON object stored as binary data with an associated key. You can group your documents into logical &lt;strong&gt;collections&lt;/strong&gt; where there&#39;s no strict requirement about how the data in each collection or even adjacent documents can look. It works well for simple, flat data that is read and written in simple patterns.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why they&#39;re good:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No predefined schema means it is really easy to get up and running when building POCs or test applications&lt;/li&gt;
&lt;li&gt;Use-cases outside of simple reads and writes, like search queries&lt;/li&gt;
&lt;li&gt;Easier to horizontally scale through multiple nodes since collections and documents do not share any strict data relation&lt;/li&gt;
&lt;li&gt;Storing simple, contiguous, independent entities of data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Why they&#39;re not so good:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Complex queries that filter on multiple values across documents or collections&lt;/li&gt;
&lt;li&gt;Data that has a lot of relationships and links. Check out this &lt;a href=&quot;https://hackernoon.com/the-problem-with-mongodb-d255e897b4b&quot;&gt;article&lt;/a&gt; for more about that&lt;/li&gt;
&lt;li&gt;Many implementations do not provide ACID guarantees&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Some Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mongodb.com/&quot;&gt;MongoDB&lt;/a&gt; — Opensource, probably the most recognizable brand in document databases&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.couchbase.com/&quot;&gt;Couchbase&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.elastic.co/&quot;&gt;Elasticsearch&lt;/a&gt; — Opensource, used for common search workloads&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rethinkdb.com/&quot;&gt;RethinkDB&lt;/a&gt; — Opensource, realtime database for online applications&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Key Value Stores&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Basically a really, really sophisticated hash map.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Key value stores or KV stores are commonly used when your data needs are simple enough that you can boil them down to querying for a &lt;strong&gt;key&lt;/strong&gt; and getting your data &lt;strong&gt;value&lt;/strong&gt; back. No relations or extra logic needed. This pattern can be applied to persistent data on disk, or temporary stores used as caches for increased performance and availability. Once again, KV stores fall under the NoSQL umbrella of databases because their storage and access designs don&#39;t follow any relational models.&lt;/p&gt;
&lt;p&gt;Some example use-cases include Redis, which is a popular in-memory KV datastore commonly used as a caching mechanism in applications. Since it stores all its data in memory by default, it gets the benefits of performance while lacking any guarantee the data will be preserved after it is shut down. For example, if an application is commonly querying a disk-based database for the same few entries, it might get them from disk once, then store those entries by key in Redis so it could retrieve them faster next time. If Redis goes down or the application restarts, the only cost would be a slower first retrieval of the data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why they&#39;re good:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Super fast performance&lt;/li&gt;
&lt;li&gt;Highly scalable&lt;/li&gt;
&lt;li&gt;Great as a supporting datastore for application workloads to improve performance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Why they&#39;re not so good:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Inefficient at anything other that looking up data by keys&lt;/li&gt;
&lt;li&gt;Bad performance on complex queries or searches&lt;/li&gt;
&lt;li&gt;In-memory implementations are not designed to be the primary datastore for applications&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Some Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://redis.io/&quot;&gt;Redis&lt;/a&gt; — Popular in-memory KV store&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://memcached.org/&quot;&gt;Memcached&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/dynamodb/&quot;&gt;AWS DynamoDB&lt;/a&gt; — Amazon&#39;s managed, highly scalable KV store in the cloud&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Column-Oriented Databases&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;So, imagine a relational database…but sideways.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To explain column-oriented databases (yet another NoSQL set of databases), let&#39;s first see how data is stored on disk for this kind of database vs. the more common, row-oriented design. Below is a comparison of what data stored in a row-oriented vs column-oriented system would look like on disk:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2018-08-27-the-wide-world-of-databases/1x_N-W-v98jMESdqsWL1d3gA.png&quot; alt=&quot;Either rows or columns are placed close together on disk&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The performance of a database operation is largely depending on physical proximity of data, whether on a spinning hard disk or between nodes in a cluster. The immediate side effect of organizing column data close together is that queries over a full row become less efficient in favor of queries over a full column. Each row typically has a &lt;strong&gt;row key&lt;/strong&gt;, however the data is queried using the column values rather than keys on the rows. Some implementations group column key&#39;s or &lt;strong&gt;column qualifiers&lt;/strong&gt; into &lt;strong&gt;column families&lt;/strong&gt; to more easily group similar sets of data.&lt;/p&gt;
&lt;p&gt;As a result, column-oriented databases fall into some very specific application use-cases, mostly dealing with online analytical processing (OLAP) workloads rather than typical transactional workloads.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why they&#39;re good:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Great for big data and data analytics applications&lt;/li&gt;
&lt;li&gt;Running aggregation querying over very large data sets&lt;/li&gt;
&lt;li&gt;Efficient storing and querying of timeseries data&lt;/li&gt;
&lt;li&gt;Highly scalable depending on the layout of the data in the system&lt;/li&gt;
&lt;li&gt;Compression of data entries per column since the data is all structured the same&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Why they&#39;re not so good:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Inefficient for querying over a small, disparate sets of rows&lt;/li&gt;
&lt;li&gt;Online transaction processing (OLTP) workloads, typical for user-facing applications, are very inefficient&lt;/li&gt;
&lt;li&gt;Performance is highly dependent on key and data layout design. Google provides their own &lt;a href=&quot;https://cloud.google.com/bigtable/docs/keyvis-overview&quot;&gt;analysis tool&lt;/a&gt; just so customers of their column databases can better design their keys&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Some Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/bigtable/&quot;&gt;Google Cloud Big Table&lt;/a&gt; — Google&#39;s column oriented database as a service&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/redshift/&quot;&gt;Amazon Redshift&lt;/a&gt; — Amazon&#39;s version&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hbase.apache.org/&quot;&gt;Apache HBase&lt;/a&gt; — An open source alternative to the proprietary implementations&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Graph Databases&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;We&#39;re all connected&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The Graph we&#39;re dealing with here is the computer science version, i.e with one composed of vertices and edges. Graph databases take those same concepts and rename them to &lt;strong&gt;nodes&lt;/strong&gt; and &lt;strong&gt;relationships&lt;/strong&gt;. Simply put, graph databases represent data in nodes that are linked together using relationships. An obvious real-world use of a graph database would be for modeling social networks, where nodes are users and relationships are the links created between users like becoming friends.&lt;/p&gt;
&lt;p&gt;With these storage capabilities comes all the benefits that has come from the mathematics around graphs, including efficient graph traversal and analysis algorithms. If you find yourself thinking about your data like a network of connected nodes, a graph database would probably provide the easiest abstraction with plenty of sophisticated methods of interaction.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why they&#39;re good:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Good at representing complex relations between data&lt;/li&gt;
&lt;li&gt;Can deal with constantly changing relationship structures between data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Why they&#39;re not so good:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can only query data based on anything other than relationships&lt;/li&gt;
&lt;li&gt;Slow at storing and querying large amounts of data for OLAP applications&lt;/li&gt;
&lt;li&gt;Not efficient at running algorithms on the data that are not optimized for graph data structures&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Some Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://neo4j.com/&quot;&gt;Neo4j&lt;/a&gt; — A lot of what you will read about graph DBs will usually end up here&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Misc&lt;/h2&gt;
&lt;p&gt;I did want to mention &lt;a href=&quot;https://www.cockroachlabs.com/&quot;&gt;CockroachDB&lt;/a&gt; and Google &lt;a href=&quot;https://cloud.google.com/spanner/&quot;&gt;Cloud Spanner&lt;/a&gt;. Both are pitched as a database with a relational model that comes with all the benefits of ACID compliance while also having potential to scale to massive workloads. Spanner was introduced by Google as the first publicly available, managed service on the Google Cloud Platform to offer such stellar availability and performance from a ACID compliant RDB. CockroachDB came onto the scene not too long after as the opensource alternative that advertised the same benefits. Both are ultimately RDBs with some significant enhancements to enable some horizontal scalability that would otherwise not be straightforward with other RDB implementations.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;With these quick summaries and reference links, I hope you are better informed about the varied world of database solutions out there. Try your hand at getting one of them up and running and using it for your next personal project. Get familiar with the nuances of working with data between the different paradigms. Reconsider where and how the online data you see everyday is stored and retrieved.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The Wide World of Software Testing</title>
    <link href="https://sanjaynair.me/blog/2018-10-01-the-wide-world-of-software-testing/"/>
    <updated>2018-10-01T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2018-10-01-the-wide-world-of-software-testing/</id>
    <content type="html">&lt;p&gt;In a &lt;a href=&quot;https://sanjaynair.me/blog/2018-05-06-what-is-cicd/&quot;&gt;previous post&lt;/a&gt; about continuous integration and deployment, I alluded to the practice of constantly putting code through various tests and making the results visible, whether within a software team or to the public for an opensource project. In this post, I want to dive a little deeper into what &amp;quot;testing&amp;quot; &lt;em&gt;actually&lt;/em&gt; is in the context of writing quality software. Specifically, I&#39;d like to shed some light on the different types of testing and how they can help you write better software.&lt;/p&gt;
&lt;h3&gt;Unit Testing&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Absolute unit&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Unit testing is the lowest level of testing. It&#39;s about as simple as you can get when testing software, but don&#39;t discount its value. A few simple unit tests can go a long way to keep your codebase robust, bug-free, and maintainable over time.&lt;/p&gt;
&lt;p&gt;A good way to explain unit testing is by example. Say we have a function written in pseudocode like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function addNumbers(a, b) {
    // Makes a network call to validate inputs
    validateInputs(a, b)
    
    return a + b
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The unit test might look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;test(&amp;quot;addNumbers adds two numbers correctly&amp;quot;) {
    // Mock the network call
    mock(validateInputs).toReturn(true)
    
    result = addNumbers(1, 2)
    assert(result equals 3)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how we&#39;re only testing for what this function does and nothing else. Any dependent operations, like a network call, are &amp;quot;mocked&amp;quot; or functionally faked to resolve to a predetermined result. If your application runs inside a framework of some kind, it will usually be ignored in favor of just running the unit of code in question. In general, we&#39;d like a test only the unit. In this case: the function and it&#39;s expected behavior.&lt;/p&gt;
&lt;p&gt;As a result:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unit tests should be pretty lightweight and run fast since they don&#39;t depend on anything external to the unit of code being tested&lt;/li&gt;
&lt;li&gt;The only way they can fail is by changing the unit of code they are testing&lt;/li&gt;
&lt;li&gt;It is usually necessary to augment unit tests with more comprehensive testing methods to ensure complete confidence in your code working as expected&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Integration Testing&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;The whole kit and kaboodle&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While it&#39;s great if the different pieces of our codebase work correctly alone, it&#39;s also essential that they work properly together as a complete package. This is where integration tests come into play. Unlike unit tests, integration tests will typically bring surrounding frameworks and multiple internal components together to ensure they are working as expected. While this still might not include interactions with external resources outside the codebase being tested (like networked resources), integration tests typically give a more complete picture of how your whole application will actually run.&lt;/p&gt;
&lt;p&gt;Below is a piece of an integration test written with the MockMVC framework for a web application API written in Java.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Test
public void integrationTest_getMyResource() {
    this.mockMvc.perform(get(&amp;quot;/myResource/123&amp;quot;)
            .andExpect(status().isOk())
            .andExpect(jsonPath(&amp;quot;$.id&amp;quot;).value(&amp;quot;value&amp;quot;));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The test spins up the web application, the various internal application components, simulates one of its API endpoints being requested, and asserts that the expected output is produced. In this case, we assert that when requesting the &lt;code&gt;myResource&lt;/code&gt; endpoint with an id, we get a JSON payload back with that same id.&lt;/p&gt;
&lt;p&gt;Some resulting features of integration tests:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They are a bit more heavyweight and typically run slower compared to unit tests since they depend on multiple software components running together&lt;/li&gt;
&lt;li&gt;They give a better view of the &amp;quot;correctness&amp;quot; of your software beyond the code you write, but also for things like how libraries and frameworks affect how your application runs&lt;/li&gt;
&lt;li&gt;It&#39;s about as good as you&#39;re going to get with confidence that your software will run correctly without actually running it and testing it manually&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I want to disclaimer a bit here before continuing. In most cases, unit and integration testing will probably get the quality of your software to where it needs to be. Beyond that, more complex types of testing will deliver value only if your software exhibits a certain level of complexity or demands a high degree of scale. As a result, you will find the below flavors of testing mainly in enterprise or other professional settings. However, there&#39;s plenty of value to have awareness and know when they might be effective to introduce into a project&#39;s development.&lt;/p&gt;
&lt;h3&gt;End to End Testing&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;From the front to the back&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;End to end (or E2E) testing comes into play when the software solution you are delivering has multiple, independent parts that may not be able to be represented in a single codebase. As a result, it is necessary to run tests with real instances of the applications to ensure that input on one end results in the expected output on the other end.&lt;/p&gt;
&lt;p&gt;Since, by nature, E2E tests typically involve multiple codebases and applications, an example of an E2E test case can&#39;t really be represented by a simple code snippit. Rather, we could present an example software architecture and provide some examples of E2E tests scenarios we might like to execute, manually or through automation.&lt;/p&gt;
&lt;p&gt;Consider the following architecture:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2018-10-01-the-wide-world-of-software-testing/1xFcwphc6GDAEC6UEJObjHWQ.png&quot; alt=&quot;Example Application Architecture&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Some E2E test cases might include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When a button is clicked on the UI, a request is routed from the first app server to the second server, processed, and returned to the UI&lt;/li&gt;
&lt;li&gt;When a form is submitted on the UI, a corresponding entry is created in the database&lt;/li&gt;
&lt;li&gt;When a button is clicked on the UI, and the second app server encounters an error, the first app server can gracefully handle it without disruption to the user&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The same principles can be applied to any level of complex architecture.&lt;/p&gt;
&lt;p&gt;As a result of this open ended bound of complexity:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There really isn&#39;t a right or wrong way to do E2E tests, as long as validations are being made on appropriate inputs&lt;/li&gt;
&lt;li&gt;E2E tests are commonly performed manually since the value of automation can be nullified from the sheer number of changing parts of the system without tight integration with a codebase&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Performance Testing&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Run like the wind Bullseye!&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Some applications are built with a very high volume workload in mind. For that reason, it would be necessary to validate that software can handle the demanding workloads by simulating them and analyzing the results.&lt;/p&gt;
&lt;p&gt;For example, a web application could be expected to handle hundreds of requests per second while performing complex data transformations. A performance test might spin up an instance of the application and simulate high volume conditions while monitoring various application metrics like resource utilization and response time. The passing criteria for a performance test might be that every request is fulfilled within a defined time at peak load and computational resources are not exceeded.&lt;/p&gt;
&lt;h3&gt;Load Testing&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;I&#39;m givin&#39; her all she&#39;s got Captain!&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There&#39;s a subtle distinction that needs to be made between load testing and performance testing. In a sense, load testing might be considered a subset of performance testing. Load testing is a method which evaluates the performance of a system under high load. You might want to understand the characteristics of the system, like CPU usage or memory, while it is being constantly hammered by a massive amount of requests or computations.&lt;/p&gt;
&lt;p&gt;While performance testing might look directly at metrics like response time, load testing is more like a litmus test to ensure your application can hold up under stress. Think of it like a stress test for your application to make sure it doesn&#39;t fall over under a demanding workload. That way, you can have some confidence that when your application is under a high load in production, it will hum right along without crashing.&lt;/p&gt;
&lt;h3&gt;User Acceptance Testing&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;If we want users to like our software, we should design it to behave like a likeable person. -Alan Cooper&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The user acceptance test or UAT might just be the ultimate of all tests mentioned here. It throws automated validations and calculated metrics out the door and instead puts the final judgement of the &amp;quot;correctness&amp;quot; of your software in the hands of its user. A UAT usually happens right after or before the delivery of an application to production. An end user is presented with the application and is encouraged to use it as they would normally. The acceptance criteria is pretty simple: does the software do what it&#39;s supposed to do for the user according to the user?&lt;/p&gt;
&lt;p&gt;You could think of all the other types of testing we discussed here as servant to this final type. Ultimately, everything we do to make quality software is some way in service to the users of that software. We might have the most robust unit tests, ran our app through the battery of the hardest performance and load tests, and executed every E2E scenario imaginable. But in the end if the user doesn&#39;t get what they need, it&#39;s all pointless. However, we should still hold ourselves to a high standard of software quality. Eventually, that benefit should reach your users through less bugs, faster and more frequent delivery to production, and more flexibility to add features.&lt;/p&gt;
&lt;p&gt;I hope you are more informed about the varied options when it comes to testing your software. If you haven&#39;t already, I encourage you to check out my post on &lt;a href=&quot;https://sanjaynair.me/blog/2018-05-06-what-is-cicd/&quot;&gt;Continuous Integration and Deployment&lt;/a&gt; where software testing plays a central role.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>A Light Introduction to AI Safety</title>
    <link href="https://sanjaynair.me/blog/2018-11-02-a-light-introduction-to-ai-safety/"/>
    <updated>2018-11-02T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2018-11-02-a-light-introduction-to-ai-safety/</id>
    <content type="html">&lt;aside class=&quot;editorial-note&quot; role=&quot;note&quot; aria-label=&quot;Editor&#39;s note&quot;&gt;
&lt;p class=&quot;editorial-note__header&quot;&gt;&lt;strong&gt;Editor&#39;s note &amp;middot; June 2026&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;editorial-note__body&quot;&gt;
&lt;p&gt;Two Google AI references in this post have been updated to their current canonical URLs. DeepMind&#39;s site moved from &lt;code&gt;deepmind.com&lt;/code&gt; to &lt;a href=&quot;https://deepmind.google/&quot;&gt;deepmind.google&lt;/a&gt; after the broader Google AI consolidation, and the Google AI Blog (&lt;code&gt;ai.googleblog.com&lt;/code&gt;) was folded into &lt;a href=&quot;https://research.google/blog/&quot;&gt;research.google/blog&lt;/a&gt; with the Duplex post now reachable there.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;I was recently listening to an episode of the podcast &lt;a href=&quot;https://twimlai.com/twiml-talk-181-anticipating-superintelligence-with-nick-bostrom/&quot;&gt;This Week in Machine Learning and AI&lt;/a&gt;, featuring professor Nick Bostrom. He is the author of a book I recently read called &lt;a href=&quot;https://en.wikipedia.org/wiki/Superintelligence:_Paths,_Dangers,_Strategies&quot;&gt;Superintelligence&lt;/a&gt;, which explores the potential consequences of artificial intelligence that surpasses the capabilities of human beings by orders of magnitude. Bostrom is also a member of the &lt;a href=&quot;https://futureoflife.org/&quot;&gt;Future of Life Institute&lt;/a&gt; which seeks to steer humanity through a safe course into the future along with the rapid pace of technological advancement.&lt;/p&gt;
&lt;p&gt;On the podcast, Bostrom highlights the relatively brand new academic area of &lt;strong&gt;AI Safety&lt;/strong&gt;. It is a really fascinating topic which I feel is becoming increasingly relevant in the modern age, and I figured it was a topic that might not be familiar to many. So here is the beginners crash course of what AI safety is and why you should probably care about it.&lt;/p&gt;
&lt;h2&gt;A (Very) Brief History of AI&lt;/h2&gt;
&lt;p&gt;Contrary to what news media might make you think, the concept and implementation of AI is not a brand new, modern concept. It has existed since the 1950s, with academics like Marvin Minsky laying some of its foundational concepts. While mostly mathematical, these early concepts led to the creation of specialized areas of AI research including but not limited to:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Knowledge Representation&lt;/strong&gt;: Also known as &amp;quot;expert systems,&amp;quot; this area sought to collect and represent &amp;quot;ontologies&amp;quot; or absolute truths in various areas of human knowledge&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Natural Language Processing&lt;/strong&gt;: How to build abstractions and algorithms for computers to consume, process, and interpret language&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Computer Vision&lt;/strong&gt;: How to take raw visual information and translate it into &amp;quot;features&amp;quot; or add meaningful interpretations to it&lt;/p&gt;
&lt;p&gt;And many, many more…&lt;/p&gt;
&lt;p&gt;Digital implementations in these areas through various techniques resulted in systems that were significantly superior to humans in their specialized areas of expertise. Some famous examples include IBM&#39;s &lt;a href=&quot;https://en.wikipedia.org/wiki/Deep_Blue_%28chess_computer%29&quot;&gt;Deep Blue&lt;/a&gt;, which beat world champion chess player Gary Kasparov at his own game. While Deep Blue was more of a brute force implementation which computed many thousands of moves ahead and picked the statically best move, more recent achievements such as DeepMind&#39;s &lt;a href=&quot;https://deepmind.google/research/projects/alphago/&quot;&gt;Alpha Go&lt;/a&gt; overcame much greater statistical complexity of playing a game of Go through reinforcement learning techniques.&lt;/p&gt;
&lt;p&gt;A relatively recent product delivered directly to customers that implements concepts from computer vision and reinforcement learning is car manufacturer &lt;a href=&quot;https://www.tesla.com/autopilot&quot;&gt;Tesla&#39;s autopilot system&lt;/a&gt;, which can provide basic automated driving capabilities to their line of electric vehicles. Look at &lt;a href=&quot;https://research.google/blog/google-duplex-an-ai-system-for-accomplishing-real-world-tasks-over-the-phone/&quot;&gt;Google&#39;s Duplex&lt;/a&gt; system for smartphones that, through the use of natural language processing and deep neural nets, can effectively mimic a basic phone conversation.&lt;/p&gt;
&lt;p&gt;There&#39;s no question that with today&#39;s technology and techniques, it&#39;s possible to develop a specialized system that could learn to perform a narrow set of tasks, sometimes even better than a human.&lt;/p&gt;
&lt;h2&gt;The Possibility of Artificial General Intelligence&lt;/h2&gt;
&lt;p&gt;The technological achievements of AI are incredible, considering the pace at which the theory translated into implementations are delivering real world value. There literally are multi-million dollar businesses built on these technologies. However, these solutions could still be considered too specialized to pose any real threat. A chess playing robot is probably not posing any threat to humanity. Something that has still not been achieved (at least not publicly), is the concept of an Artificial General Intelligence or &lt;strong&gt;AGI&lt;/strong&gt;. Also known as &amp;quot;Strong AI&amp;quot;, I defer to the &lt;a href=&quot;https://en.wikipedia.org/wiki/Artificial_general_intelligence&quot;&gt;Wikipedia definition&lt;/a&gt; to summarize the idea:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Artificial general intelligence&lt;/strong&gt; (&lt;strong&gt;AGI&lt;/strong&gt;) is the intelligence of a machine that could successfully perform any intellectual task that a human being can.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the AI of science fiction: the kind that might be indistinguishable from a human in their intellectual capabilities. This is an AI system that might cross the boundaries of specialization and could perform functions in multiple intellectual domains. These systems might even be able to learn from a random set of unstructured data such as what&#39;s freely available on the internet.&lt;/p&gt;
&lt;h2&gt;The Fast Track to Superintelligence&lt;/h2&gt;
&lt;p&gt;Enter the concept of a &lt;strong&gt;superintelligence&lt;/strong&gt;. For the full explanation of the concept of superintelligence, consider reading Bostrom&#39;s previously mentioned &lt;a href=&quot;https://en.wikipedia.org/wiki/Superintelligence:_Paths,_Dangers,_Strategies&quot;&gt;book&lt;/a&gt; on the topic.&lt;/p&gt;
&lt;p&gt;The short version goes something like this: the progress of AI research and development is moving forward so rapidly to the point where nothing is slowing it down. Soon, we will cross a threshold of complexity and capability where AGI is a reality. This could be seen as a point of no return, much like previous scientific discoveries such as nuclear fission, which will change the course of human history. Once AGI is achieved, the exponential pace of advancement will result in what Bostrom calls a Superintelligence, or an artificial entity with general capabilities many orders of magnitude beyond what a human could possess, interpret, or control.&lt;/p&gt;
&lt;p&gt;Consider the depictions of AI in science fiction that plays the role of antagonist against humans due to their conflicting judgement of a situation and superior abilities over humans to act on that judgement. HAL from 2001; A Space Odyssey. The Terminators developed by Skynet. The colony ship AI, AUTO from Pixar&#39;s Wall-E. A superintelligent system in theory could easily fill the role of any of these characters and prove to be a concrete threat to the human race.&lt;/p&gt;
&lt;h2&gt;The Need for AI Safety&lt;/h2&gt;
&lt;p&gt;Elon Musk is one of the more famous personalities that has consistently spoken out about the dangers of unbounded AI research. You only need scroll through some of his tweets on the subject to see that a man who is pushing innovative boundaries daily thinks very strongly about the dangers of AI and superintelligence posing a threat to humanity.&lt;/p&gt;
&lt;p&gt;The future of life institute provides &lt;a href=&quot;https://futureoflife.org/background/benefits-risks-of-artificial-intelligence/&quot;&gt;extensive details&lt;/a&gt; on the subject of AI being a threat to human wellness and even provides a plethora of reference reading to support their points. Some of the main dangers they outline include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The development of an AI who&#39;s interests do not align with those of humanity. Consider the sci-fi trope of a machine that considers humanity a threat to the Earth and decides to wipe it out&lt;/li&gt;
&lt;li&gt;The AI is intentionally designed to do something destructive. It&#39;s not hard to imagine the conflicts of world politics driving a nation to develop a superintelligent AI with the sole purpose of destroying political enemies.&lt;/li&gt;
&lt;li&gt;The AI reaches the point where humans can&#39;t reason how or why it does what it does. Do some reading on deep neural networks and you might realize we&#39;re already at the point where we really don&#39;t know why some algorithms actually work so well.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What Can be Done?&lt;/h2&gt;
&lt;p&gt;Just as we can turn to fiction to feed our fears about the inevitable threat of AI and the machines taking over, we can also look to it for some answers on how to prevent such a future. Author Isaac Asimov outlined a rather short and elegant set of laws he saw as the fundamental building blocks to ensure robots would never come in conflict with humans. The &lt;a href=&quot;https://www.auburn.edu/~vestmon/robotics.html&quot;&gt;Three Laws of Robots&lt;/a&gt; according to Asimov go as follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A robot may not injure a human being or, through inaction, allow a human being to come to harm.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;A robot must obey orders given it by human beings except where such orders would conflict with the First Law.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;A robot must protect its own existence as long as such protection does not conflict with the First or Second Law.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Besides the potential harm a highly advanced AI might pose to humans, there&#39;s also the risk of humanity developing a system it cannot understand or reason about. Even with the sometimes unfathomable complexity of technology we see all around us today, most of it can be completely understood by a human. However, once we trade interpretability for capability, we enter a scenario where our systems are &amp;quot;black boxes&amp;quot; where we can validate the accuracy of its results but cannot reason as to how the result was derived.&lt;/p&gt;
&lt;p&gt;So a solution might be that AI systems must be required to explain how they arrived to a solution. While some might see this as a hindrance to progress now, in the future it might be the only way we can feel assured that systems beyond our human capabilities are making decisions in our best interest.&lt;/p&gt;
&lt;h2&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;If any of this peaks of interest, I encourage you to do more reading on the subject. Some interesting places to start include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href=&quot;https://twimlai.com/twiml-talk-181-anticipating-superintelligence-with-nick-bostrom/&quot;&gt;TWIML AI podcast episode&lt;/a&gt; on the topic&lt;/li&gt;
&lt;li&gt;The book &lt;a href=&quot;https://en.wikipedia.org/wiki/Superintelligence:_Paths,_Dangers,_Strategies&quot;&gt;Superintelligence&lt;/a&gt; by Nick Bostrom&lt;/li&gt;
&lt;li&gt;Dr. &lt;a href=&quot;https://www.nytimes.com/2017/11/21/magazine/can-ai-be-taught-to-explain-itself.html&quot;&gt;Michal Kosinski&#39;s study&lt;/a&gt; on facial recognition and encountering the &amp;quot;black box&amp;quot; problem&lt;/li&gt;
&lt;li&gt;The loads of content on the &lt;a href=&quot;https://futureoflife.org/background/existential-risk/&quot;&gt;Future of Life website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Elon Musk&#39;s &lt;a href=&quot;https://twitter.com/elonmusk/status/495759307346952192?lang=en&quot;&gt;twitter feed&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Enjoy! 🤖&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>A Light Introduction to Cloud Services</title>
    <link href="https://sanjaynair.me/blog/2019-01-10-a-light-introduction-to-cloud-services/"/>
    <updated>2019-01-10T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2019-01-10-a-light-introduction-to-cloud-services/</id>
    <content type="html">&lt;p&gt;As software engineers, there are lots of tools available for us to use. We might start simple with a programming language or two. From there, we might explore software libraries that help us be more productive when solving problems, or tools to help with collaboration. If our use-case requires it, we could reach for advanced monitoring tools to alert us when our software is doing something it shouldn&#39;t.&lt;/p&gt;
&lt;p&gt;At some point in this process, many of us might have crossed paths with the new hotness in software development: &lt;em&gt;&lt;strong&gt;The Cloud&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If you&#39;re reading this, then you might have at least heard about &amp;quot;cloud technologies&amp;quot;. You might want to learn more about what &lt;em&gt;&lt;strong&gt;The Cloud&lt;/strong&gt;&lt;/em&gt; is and how it can enable us to build better software.&lt;/p&gt;
&lt;p&gt;In short, &lt;em&gt;&lt;strong&gt;The Cloud&lt;/strong&gt;&lt;/em&gt; can be seen as just another set of tools for those that want to be more productive when developing software. Most cloud providers offer many of the same types of tools, albeit with slight variations of advertised functionality or developer experience when using them. However, understanding these types of tools and what problems they solve is a key category of information I found very helpful when navigating the cloud technology landscape and implementing my own software solutions.&lt;/p&gt;
&lt;p&gt;This will hopefully serve as a high level introduction to the main types of tools available and what problems they can solve. Once you have a handle on them, you should have good context to confidently explore different service offerings by cloud providers.&lt;/p&gt;
&lt;h3&gt;Compute — Virtual Machines&lt;/h3&gt;
&lt;p&gt;Virtual machines could be thought of as a foundational service offered in the cloud. In short, you can provision a virtual computer with specified operating system, resources like RAM, CPU and storage, and use it to run whatever software you like. You are charged based on the amount of VM&#39;s you provision, as well as the amount of resources they are utilizing. More VM&#39;s with more power = more money. You would also most likely have an option to pick where, geographically in the world your VM is deployed. This could help enable faster response times to customers in certain areas or redundancy if a data center experiences downtime.&lt;/p&gt;
&lt;p&gt;You can use these services as a platform to host your application for yourself or make it available to the public. They typically don&#39;t include any extra features outside of basic autoscaling; so installing, running, and making your app accessible will take some extra time and effort.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Virtual Machine services:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/compute/&quot;&gt;Google Compute Engine (GCE)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/ec2/&quot;&gt;Amazon Elastic Compute Cloud (EC2)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://azure.microsoft.com/en-us/services/virtual-machines/&quot;&gt;Azure Virtual Machines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.digitalocean.com/products/droplets/&quot;&gt;Digital Ocean Droplets&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Object Storage&lt;/h3&gt;
&lt;p&gt;Storage is another cloud service that is probably pretty easy to wrap your head around. It&#39;s a place to store your data that&#39;s not on your computer for some money. The complexity comes in the different ways you can structure and access that data, which serves themselves to solving very different problems.&lt;/p&gt;
&lt;p&gt;One flavor of cloud storage is file storage, or generically described as &amp;quot;object storage.&amp;quot; Object storage is usually a highly configurable place to store data assets based on your development needs. Are you trying to build the backend for a file archive where the data volume is very high but the access rate is very infrequent? Are you handing photo uploads from users at 1000 times per second and photo downloads at ten times that? What kind of transfer protocols are you using to move the data? If these are relevant questions for your software, then object storage services will probably have the configurations and pricing details to solve your data storage and access needs. You are typically charged based on how much data you want to store, how fast you want to access it, where in the world you need it to be accessible, and how much of it is going in and out of the cloud.&lt;/p&gt;
&lt;p&gt;Another cool feature of object storage is the ability to host static websites from them. Most object storage solutions offer some type of simple web frontend to serve static assets like a web server (&lt;a href=&quot;https://sanjaynair.me/&quot;&gt;my website&lt;/a&gt; is hosted like this!). So if your website doesn&#39;t have any interactive elements and can be expressed in plain HTML/JS/CSS, static web hosting through object storage is plenty cheaper than most other application platforms to deploy a website.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Object Storage services:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/s3/&quot;&gt;Amazon S3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/storage/&quot;&gt;Google Cloud Storage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.digitalocean.com/products/spaces/&quot;&gt;DigitalOcean Spaces&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ibm.com/cloud/object-storage&quot;&gt;IBM Cloud Object Storage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Databases&lt;/h3&gt;
&lt;p&gt;When the data structures you need to persist are a bit more complex than simply storing individual files or objects, but you don&#39;t want to have to install and run a database on your hardware or even a VM in the cloud, you might reach for a managed database offering.&lt;/p&gt;
&lt;p&gt;Cloud providers have simple and easy ways to get a database up and running with a few clicks. Along with that simplicity, you get a lot of the other strengths of having the service running on a cloud provider&#39;s infrastructure like regional availability, built-in monitoring, automatic backups, and automatically expandable capacity. Of course, like most things in the cloud, all these features are fully configurable. But the more you ask for, the more you&#39;re probably going to be paying. If the primary business objectives are not managing databases, incurring extra operational cost versus having to hire and manage someone to administer databases is a valid tradeoff.&lt;/p&gt;
&lt;p&gt;Most opensource databases like Postgres and MongoDB can be found as a preconfigured, managed services on most cloud platforms with some proprietary offerings available as well. For example, Google Cloud offers the ubiquitous &lt;a href=&quot;https://cloud.google.com/bigquery/&quot;&gt;Big Query&lt;/a&gt; tool for efficient and affordable storage and access of very large data sets. Similarly, &lt;a href=&quot;https://cloud.google.com/spanner/&quot;&gt;Spanner&lt;/a&gt; is Google Cloud&#39;s managed, high availability and high performance relational database service. AWS has similar proprietary offerings in the form of &lt;a href=&quot;https://aws.amazon.com/redshift/&quot;&gt;Amazon Redshift&lt;/a&gt; relational databases and &lt;a href=&quot;https://aws.amazon.com/dynamodb/&quot;&gt;DynamoDB&lt;/a&gt; key-value stores.&lt;/p&gt;
&lt;p&gt;With managed database services, the main tradeoff for convenience and speed to market is potential vendor lock in to a specific set of tooling and cost depending on the amount of features you require.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Managed Database Services:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/products/databases/&quot;&gt;Databases on AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/products/storage/&quot;&gt;GCP Cloud Storage Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://azure.microsoft.com/en-us/product-categories/databases/&quot;&gt;Azure Databases&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Application Platforms as a Service&lt;/h3&gt;
&lt;p&gt;When you don&#39;t want to worry about systems management of a VM and simply want to deploy your application and manage it at a high level, you might consider a Platform as a Service or PaaS offering.&lt;/p&gt;
&lt;p&gt;When working with a PaaS, you can typically get an application written and deployed with only some small configuration in the middle. Assuming you are following the principles of &lt;a href=&quot;https://12factor.net/&quot;&gt;12 factor&lt;/a&gt; application development, getting your app from coded to deployed should only include some small amount of extra configuration. You don&#39;t have to worry about VM&#39;s or systems administration and can focus more on writing code. You typically pay a premium for this convenience, but for many this is well worth it.&lt;/p&gt;
&lt;p&gt;Cloud platforms vary a bit here as far as how approachable they made the developer experience when it comes to directly running apps in the cloud. Some of the first PaaS offerings, like the ever popular &lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt;, make deploying as easy as pushing to a git repo and managing your app painless through their web-based tooling. On the flip side, offerings on AWS like Elastic Beanstalk are targeted more at enterprise customers, and therefore trade off convenience for flexibility, customization, and scalability.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Platforms as a Service:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.heroku.com/dynos&quot;&gt;Heroku Dynos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vercel.com/&quot;&gt;Vercel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/appengine/&quot;&gt;Google App Engine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/elasticbeanstalk/&quot;&gt;AWS Elastic Beanstalk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Serverless Platforms&lt;/h3&gt;
&lt;p&gt;The paradigm of &lt;em&gt;serverless computing&lt;/em&gt; is relatively new in the mainstream discussions of software development. To some degree, the serverless model could be throught of as a direct result of the rise in ubiquitousness of cloud platforms.&lt;/p&gt;
&lt;p&gt;The basic idea behind serverless platforms boils down to this: cloud platforms make their money based on the amount of resources their customers use. That could be every CPU or GB of RAM you add to a VM times how long that VM is running. However, the simple fact is sometimes you don&#39;t need an application running 24/7 on a VM that&#39;s costing you money every minute its up and running. Sometimes you just need something to run a very small percentage of time, maybe to handle a few requests an hour. You could think of it like a shipping company sending out a tractor trailer to ship a few shoes. Why not just send a bike?&lt;/p&gt;
&lt;p&gt;Serverless offers an alternative for these unique compute workloads. Instead of deploying a full app, you only deploy a &amp;quot;function&amp;quot; that does the unit of work you want it to and nothing more. The cloud platform then charges you for when the function runs but none of the time it is sitting idle. For example, check out the pricing model for the &lt;a href=&quot;https://cloud.google.com/functions/pricing&quot;&gt;Cloud Functions&lt;/a&gt; offering on Google Cloud Platform. They literally give you the first 2 million times your functions runs FOR FREE. And even after that, its only 40 cents per 20 MILLION INVOCATIONS. (*Disclaimer: These costs are accurate as of writing this)&lt;/p&gt;
&lt;p&gt;The clear advantage of this model is obviously the lower cost and opportunity to write less code to get simple jobs done. However a cloud function (today) still takes some time to get &amp;quot;warmed up&amp;quot; and will probably not be as responsive as a continuously running app on the first invocation. Consider this for processes that are pretty simple functionally and don&#39;t need to run super fast from the get go.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples of Serverless platforms:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/lambda/&quot;&gt;AWS Lambda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/functions/&quot;&gt;Google Cloud Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://azure.microsoft.com/en-us/services/functions/&quot;&gt;Azure Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fnproject.io/&quot;&gt;Oracle Fn Project&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Streaming and Data Processing&lt;/h3&gt;
&lt;p&gt;Similar to my &lt;a href=&quot;https://sanjaynair.me/blog/2018-10-01-the-wide-world-of-software-testing/&quot;&gt;previous article&lt;/a&gt; on software testing, it&#39;s around here where we get into some of the more specialized tooling offered in the cloud. While specific in their intended use cases, this category of cloud services still spans their own significant portion of most platforms out there and is worth understanding at a high level.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2019-01-10-a-light-introduction-to-cloud-services/0xpfuE1pNi3eMbGJ5K.png&quot; alt=&quot;An example of a Dataflow pipeline&quot; /&gt;&lt;br /&gt;
&lt;em&gt;An example of a Dataflow pipeline (&lt;a href=&quot;https://cloud.google.com/solutions/processing-logs-at-scale-using-dataflow&quot;&gt;https://cloud.google.com/solutions/processing-logs-at-scale-using-dataflow&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Most cloud platforms will offer some kind of scalable, high throughput, data pipeline processing tool. These might be useful when you&#39;re trying to build a high volume or throughput system that requires a lot of computing power. A managed data streaming service would give you abstractions around the hardware where your algorithms are running, how to separate and link different steps, and the ways to configure how it scales with incoming data volume. Like other managed service offerings specific to cloud platforms, these data streaming services typically integrate very easily with other managed services like databases and object storage.&lt;/p&gt;
&lt;p&gt;Examples of data streaming services:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/dataflow/&quot;&gt;GCP Dataflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/kinesis/&quot;&gt;Amazon Kinesis&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Another common streaming tool is the Publish-Subscribe or &amp;quot;pubsub&amp;quot; service. These services provide a publish-subscribe messaging system with no worries about infrastructure and minimal configuration and the guarantees of fast delivery of messages. You are charged based on the volume of ingress and egress from the system with the prices typically designed for very high throughput situations. Reach for these if you&#39;re building a distributed system, perhaps between multiple, decoupled microservices that need to communicate a decoupled fashion.&lt;/p&gt;
&lt;p&gt;Examples of managed pubsub services:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/pubsub/docs/overview&quot;&gt;Google Pubsub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/sns/&quot;&gt;Amazon Simple Notification Service&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;AI and Machine Learning&lt;/h3&gt;
&lt;p&gt;With the mainstream rise of Machine Learning and AI as an area of software specialization, cloud providers are more than ready to provide managed solutions to some of the main problems posed by this up-and-coming area.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2019-01-10-a-light-introduction-to-cloud-services/0xEYsVULBoHbKVcc0M.png&quot; alt=&quot;Example of face detection through Google Vision API&quot; /&gt;&lt;br /&gt;
&lt;em&gt;Example of face detection through Google Vision API (&lt;a href=&quot;https://developers.google.com/vision/&quot;&gt;https://developers.google.com/vision/&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Most modern cloud providers (especially the ones that already developed high fidelity ML and AI tools for the other business ventures - I&#39;m looking at you Google) offer managed solutions to overcome the barriers to entry into the space. For example, they might provide image recognition tools to provide high quality image recognition without the need to write implementations from scratch or worry about collecting training data sets. They effectively take care of all the implementation and training while letting you, the customer, reap the benefits through a friendly API.&lt;/p&gt;
&lt;p&gt;These implementations extend into other areas such as neural networks, natural language processing, with the list growing larger by the day.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As a sidenote, these are &lt;strong&gt;excellent&lt;/strong&gt; tools to grab for a weekend hackathon to take your project to that next level&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Examples of managed ML and AI cloud solutions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/dialogflow&quot;&gt;Google Dialogflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/vision/&quot;&gt;Google Vision API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ibm.com/cloud/ai&quot;&gt;IBM Watson&lt;/a&gt; (Yes, Watson from Jeopardy is now a product you can use)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://clarifai.com/&quot;&gt;Clarifai&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/rekognition/&quot;&gt;AWS Rekognition&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Configuration and Administration&lt;/h3&gt;
&lt;p&gt;The last and probably most boring but still important to understand items in the cloud toolbelt are the interfaces to manage everything I just talked about, aka administration and configuration tools. To keep the boring section short, I&#39;ll break it down into the main components as per my experience:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Identity Access Management&lt;/strong&gt;: Since projects are often accessed by dozens to thousands of different people, this is a way to keep track of them all are and what permissions they have. &lt;em&gt;Don&#39;t give the intern admin access to the production database.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Networking&lt;/strong&gt;: Just like you can manage all the resources on your cloud platform project, so can you control how they connect to each other through Virtual Private Networks and how the outside world connects to them through Load Balancers and Content Delivery Networks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logging&lt;/strong&gt;: Your software is probably writing a lot of logs that you would like to browse and filter through. Most cloud platforms will have a central way to access and manage those logs for debugging purposes or metrics collection.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monitoring and Alerting&lt;/strong&gt;: You might want to know when stuff breaks so you can go fix it before your customer or boss finds out. Cloud providers have options for monitoring mostly everything running on their platform (including the platform itself like &lt;a href=&quot;https://status.cloud.google.com/&quot;&gt;Google&#39;s Cloud Platform Status page&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Billing&lt;/strong&gt;: Ah yes, the item at the top of every managers mind (and maybe yours if you are running it for yourself), how much are all these toys going to cost? Considering how this is how these Cloud Providers make their money, they make very well designed and convenient ways to tell you how much of your money they are taking. But hey, for what you&#39;re getting, it&#39;s not that bad of a deal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So in (not so) short, that&#39;s what &lt;em&gt;&lt;strong&gt;The Cloud&lt;/strong&gt;&lt;/em&gt; is all about. If I missed something you think is important (which I probably did), whether a section or link I didn&#39;t include, please let me know. And if you&#39;re new to this whole cloud platform thing, let me know if this gave you a better idea of what all the hoopla is about.&lt;/p&gt;
&lt;p&gt;With that, go and making something awesome.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Getting Started With Open Source</title>
    <link href="https://sanjaynair.me/blog/2019-02-26-getting-started-with-opensource/"/>
    <updated>2019-02-26T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2019-02-26-getting-started-with-opensource/</id>
    <content type="html">&lt;aside class=&quot;editorial-note&quot; role=&quot;note&quot; aria-label=&quot;Editor&#39;s note&quot;&gt;
&lt;p class=&quot;editorial-note__header&quot;&gt;&lt;strong&gt;Editor&#39;s note &amp;middot; June 2026&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;editorial-note__body&quot;&gt;
&lt;p&gt;The GitHub help link in this post has been updated to its current canonical URL. GitHub retired the &lt;code&gt;help.github.com&lt;/code&gt; domain in favor of &lt;a href=&quot;https://docs.github.com/&quot;&gt;docs.github.com&lt;/a&gt;, and the pull request templates article now lives under the Communities section there.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;Did you know that a large part of the software you use everyday was probably built with tools and technologies that are freely available for anyone to download, install, study, and modify?&lt;/p&gt;
&lt;p&gt;The operating system running the server that&#39;s delivering this webpage to you. The library securing your network traffic to this website. The framework used to build this website. All of these thing were build on or with the help of open source technology.&lt;/p&gt;
&lt;p&gt;Software being open source means that not only is all of its source code available to download and view publicly, but its also available for anyone to modify and contribute back to. In fact, a lot of the success of open source software by definition is dependent on volunteers contributing changes and collaboratively making the software better.&lt;/p&gt;
&lt;p&gt;Contributing to someone else&#39;s codebase might seem like a daunting proposition, but all you really need is a computer connected to the internet and a desire to dive into the deep end of an interesting problem you want to contribute your time to.&lt;/p&gt;
&lt;p&gt;In this piece, I hope to shed some light on the specifics of how to approach getting started with participating in open source.&lt;/p&gt;
&lt;h3&gt;Step 1: Go to the Source (Code)&lt;/h3&gt;
&lt;p&gt;There&#39;s no &amp;quot;official&amp;quot; platform or methodology used by the open source community to get their work done. That being said, today most of it is done on &lt;a href=&quot;https://github.com/&quot;&gt;Github&lt;/a&gt;. There are other git-based alternatives like Gitlab and Bitbucket and even some that are not git-based at all. The Linux Kernel is one of the largest and most active open source projects to date and it is entirely managed through emails of code patches! However, Github is currently the most popular open source platform and is very easy for beginners to get started with.&lt;/p&gt;
&lt;p&gt;Github is a place for people to upload their code and have it viewable by the public or privately. Public code repositories or &amp;quot;repos&amp;quot; have many features that make it easy for anyone with some basic knowledge of the software in question to contribute their efforts to making the product better in some way. Not every contribution even needs to be technical in nature. Lots of contributors spend their time moderating dialogs or creating and managing documentation.&lt;/p&gt;
&lt;p&gt;A good first step would be to create an account there, if you haven&#39;t already, and get familiar with navigating around the site. Check out the &lt;a href=&quot;https://github.com/trending&quot;&gt;trending&lt;/a&gt; page for a list of public code repos getting a lot of attention on any given day. Click through some of the different tabs on each repo and explore around. Check out the Issues tab to see what sorts of discussions people are having about the problems they are encountering with the software and how the community has responded in discussion threads. The Pull Requests tab typically has examples of how people have contributed to fixing outstanding issues or added new features.&lt;/p&gt;
&lt;p&gt;Most of the remaining steps in this piece will deal with navigating around Github, so make sure you&#39;re comfortable with it!&lt;/p&gt;
&lt;h3&gt;Step 2: Find Something to Contribute To&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Necessity is the mother of invention&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sometimes the hardest part about getting into open source is finding a project or initiative that you can connect with or are inspired to contribute to. Sometimes you need to go out and find it, and other times it falls right into your lap as a problem you need to overcome. If you work with code and software a decent amount, chances are you ran into some feature you wished was there or a bug you really wish wasn&#39;t there.&lt;/p&gt;
&lt;p&gt;One example of this comes from an issue my team ran into at work: We had multiple code repos on Github with many team members all making changes and submitting requests to have those changes be reviewed before they were deployed. We needed a way to concisely display all the open changes that needed review for our code repos. After some googling, I found the &lt;a href=&quot;https://github.com/joeattardi/github-pr-dashboard&quot;&gt;Github PR Dashboard&lt;/a&gt;, which quickly solved our problem. After using it with the team and getting great value from it, we eventually contributed back some features and enhancements for others to use. Check out my &lt;a href=&quot;https://github.com/joeattardi/github-pr-dashboard/pulls?q=is%3Apr+is%3Aclosed+author%3ANirespire&quot;&gt;past contributions&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;If you don&#39;t have an existing desire to fix or improve something already, there are some great resources available to get you pointed in the right direction. &lt;a href=&quot;https://www.firsttimersonly.com/&quot;&gt;First Timers Only&lt;/a&gt; is a project specifically aimed at highlighting opportunities for beginners to contribute to open source projects. There&#39;s a &lt;a href=&quot;https://www.youtube.com/watch?v=GWCcZ6fnpn4&quot;&gt;great talk&lt;/a&gt; from the React NYC conference on how someone used this kind of resource to contribute code to the React JS codebase which is currently one of the most popular web development tools used today.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hacktoberfest.digitalocean.com/&quot;&gt;Hacktoberfest&lt;/a&gt; is another great initiative around getting folks into open source. Every year during the month of October, companies who maintain open source projects encourage new contributors to submit changes for the opportunity to win real-world prizes like T-Shirts and stickers. Any organization is open to participate in this event and each has their own guidelines for how to contribute and win prizes. When October rolls around, be sure to keep an eye out for Hacktober opportunities popping up!&lt;/p&gt;
&lt;h3&gt;Step 3: Do Your Homework!&lt;/h3&gt;
&lt;p&gt;Now you have something you want to contribute to, what&#39;s next? Well the answer is: it depends. Your open source search might have landed you in a small and simple codebase like some student&#39;s side project, or something way more complex and far-reaching like a multi-faceted project backed by hundreds of other contributors and used by multi-billion dollar companies. Both types of repos will have different levels of quality and guidelines on how to contribute.&lt;/p&gt;
&lt;p&gt;The best place to start to figure out where to start is the &lt;strong&gt;README&lt;/strong&gt;. Any good open source project should have a good README. Good might mean different things to different people, but you can judge that for yourself. Here are some basic things to look for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Does it have a concise and informative description of what the project is at a high level and what problem it is trying to solve?&lt;/li&gt;
&lt;li&gt;Does it have instructions on how to set up the project on your machine for development?&lt;/li&gt;
&lt;li&gt;Does it link to any additional documentation that would be helpful to someone trying to make changes to it?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can find great examples of READMEs in some of the larger open source projects like &lt;a href=&quot;https://github.com/facebook/react&quot;&gt;React&lt;/a&gt;, &lt;a href=&quot;https://github.com/Microsoft/vscode&quot;&gt;VSCode&lt;/a&gt;, &lt;a href=&quot;https://github.com/tensorflow/tensorflow&quot;&gt;Tensorflow&lt;/a&gt;, and more. Use the details in this document to get more familiar with what the repo is all about. Try to follow the getting started steps to clone the code locally and get it up and running.&lt;/p&gt;
&lt;p&gt;Next thing to look for is a CONTRIBUTING document. Where the README might include the &lt;em&gt;what&lt;/em&gt; and &lt;em&gt;why&lt;/em&gt;, the CONTRIBUTING document tells you the &lt;em&gt;how&lt;/em&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sometimes these details might be included in a README section, so don&#39;t worry if you don&#39;t find this specific document.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What are the guidelines that the repo maintainers have put forward for how they want you to make changes to the code? Sometimes it&#39;s as simple as opening a pull request and having someone approve and merge it. Larger projects might have stricter protocols that include opening an issue, validating the issue is not a duplicate, opening a pull request, having the pull request pass automated test suites or CI process, and finally being approved by a maintainer. Different projects operate in different ways, so be sure to know how the one you want to contribute to does.&lt;/p&gt;
&lt;p&gt;The VSCode project has a great &lt;a href=&quot;https://github.com/microsoft/vscode/blob/main/CONTRIBUTING.md&quot;&gt;CONTRIBUTING&lt;/a&gt; document that I&#39;ve always been directed to as a reference.&lt;/p&gt;
&lt;p&gt;Last but certainly not least is the CODE OF CONDUCT document. This document provides the guidelines by which contributors are expected to conduct themselves when collaborating online with the community. Some can be short and sweet and simple say &amp;quot;Don&#39;t be a jerk.&amp;quot; Others can get into more details about what kind of interactions and behavior are considered inappropriate.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md&quot;&gt;Angular project&lt;/a&gt; has a short and sweet code of conduct that get&#39;s right to the point very effectively.&lt;/p&gt;
&lt;h3&gt;Step 4: Fork and Code&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Disclaimer: These next two sections assume you know the basics of Git including common operations like how to clone, branch, commit, merge, and push.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now you&#39;ve found some code you want to contribute to and you&#39;re familiar with the process put in place by the maintainers to do so. Next we&#39;re going to get into the nitty-gritty details about how to make your changes and actually submit them.&lt;/p&gt;
&lt;p&gt;Github has a feature called &amp;quot;forking&amp;quot; that essentially means: take this repo owned by someone else and create a linked copy in my personal Github profile.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2019-02-26-getting-started-with-opensource/1xdFemDPFGQUPsWic7W4rdjA.png&quot; alt=&quot;The github-pr-dashboard owned by joeattardi that I forked to my profile&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This allows you to create a branch and push code to your forked copy without having write access to the main repo.&lt;/p&gt;
&lt;p&gt;So now you should do exactly that. Clone the forked repo to your machine, make whatever changes you planned, and commit to a branch on your forked repo. If applicable, follow any branching, code style, and testing requirements outlined in the contributing guidelines.&lt;/p&gt;
&lt;h3&gt;Step 5: Open a Pull Request&lt;/h3&gt;
&lt;p&gt;Once you&#39;re happy with the changes, you can open a Pull Request.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2019-02-26-getting-started-with-opensource/1xS-fn57AUwFdoYLNWUezQFw.png&quot; alt=&quot;One way you can open a PR is clicking this button on the Pull requests tab of your forked repo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Make sure that the base branch you are proposing to merge your branch into is the appropriate branch of the &lt;em&gt;original&lt;/em&gt; repo. That way the maintainers will see your open PR in their list of pull requests.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2019-02-26-getting-started-with-opensource/1xdgmEMn3FuYyrqscJwmRJ5Q.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Again, follow the contributing guidelines to decide which is the correct default branch the maintainers want you to merge into and what details are expected in the Pull Request description. Some repos on Github are set up with &lt;a href=&quot;https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository&quot;&gt;Pull Request templates&lt;/a&gt; that will pre-fill the description with a basic scaffold you can add details too.&lt;/p&gt;
&lt;p&gt;Now just wait to get some feedback from the code owners to see if they think your changes are ready to be merged. Sometimes its a quick thumbs up and other times there might be some back and forth where additional changes might be requested. Remember that this whole process is about teamwork and communication. You the contributor and the maintainer are on the same team, so be sure to respect the &lt;strong&gt;code of conduct&lt;/strong&gt; for contributing and don&#39;t get discouraged if you don&#39;t get it right the first time!&lt;/p&gt;
&lt;p&gt;Once that&#39;s done, you did it! You have officially contributed to open source!&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I hope this guide provided some insight into how to get your foot in the door to contributing to open source. I&#39;d love to hear your feedback in the comments or on &lt;a href=&quot;https://x.com/Nirespire&quot;&gt;X&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&#39;ve since written a follow up to this piece about &lt;a href=&quot;https://sanjaynair.me/blog/2019-04-01-how-to-open-source-your-code/&quot;&gt;how to open source your own projects&lt;/a&gt;, so be sure to check that out next.&lt;/p&gt;
&lt;p&gt;If you&#39;re looking for some other great resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I&#39;m going to plug the &lt;a href=&quot;https://www.youtube.com/watch?v=GWCcZ6fnpn4&quot;&gt;great talk&lt;/a&gt; I mentioned above again because it has some great examples of PR&#39;s being rejected how it was dealt with properly&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.firsttimersonly.com/&quot;&gt;First Timers Only&lt;/a&gt;: A resource dedicated to those contributing to Open Source for the first time&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://react.dev/community#how-to-contribute&quot;&gt;ReactJS Contributing docs&lt;/a&gt; have guidelines specifically for directing beginners to appropriate Issues to contribute changes to&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/kentcdodds&quot;&gt;Kent C Dodds&lt;/a&gt; has a great &lt;a href=&quot;https://www.youtube.com/watch?v=k6KcaMffxac&quot;&gt;video&lt;/a&gt; on the topic of contributing to open source for beginners&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>How to Open Source Your Code</title>
    <link href="https://sanjaynair.me/blog/2019-04-01-how-to-open-source-your-code/"/>
    <updated>2019-04-01T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2019-04-01-how-to-open-source-your-code/</id>
    <content type="html">&lt;aside class=&quot;editorial-note&quot; role=&quot;note&quot; aria-label=&quot;Editor&#39;s note&quot;&gt;
&lt;p class=&quot;editorial-note__header&quot;&gt;&lt;strong&gt;Editor&#39;s note &amp;middot; June 2026&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;editorial-note__body&quot;&gt;
&lt;p&gt;All of the GitHub help links in this post have been updated to their current canonical URLs. GitHub retired the &lt;code&gt;help.github.com&lt;/code&gt; domain in favor of &lt;a href=&quot;https://docs.github.com/&quot;&gt;docs.github.com&lt;/a&gt;, and the articles on licensing, contributing guidelines, and healthy contributions have all moved to new paths under that domain.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;In my &lt;a href=&quot;https://sanjaynair.me/blog/2019-02-26-getting-started-with-opensource/&quot;&gt;last post&lt;/a&gt;, I outlined what open source is and presented some steps for how to get involved. Every open source project available today, even those with many thousands of contributors, all started with at least one person who had the drive to make what they were creating available for other to freely use and contribute to.&lt;/p&gt;
&lt;p&gt;If you fall into this category of people but don&#39;t have a good idea of how to get started, then this is hopefully a good place for you to start. We will cover some of the high level concepts and steps you can take to get your project ready for the world of open source.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;While these are my top picks for how to properly prepare a project to be open sourced, this list is by no means exhaustive. The best source for open source is always the community at large. Everything said here is based on my experience participating in open source as well as learning from others maintaining their own projects. After reading, I encourage you to go find one of the many amazing open source projects out there and follow their examples. There are some links at the end to help you get started!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Step 0: Identify the Opportunity&lt;/h3&gt;
&lt;p&gt;This is more of an optional step &lt;strong&gt;&lt;em&gt;but&lt;/em&gt;&lt;/strong&gt;, in my opinion, since open source is all about adding value through collaboration, your first step might be to consider some things about your code.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is this something that you got value out of?&lt;/li&gt;
&lt;li&gt;Is this something that you think others would get value out of?&lt;/li&gt;
&lt;li&gt;Do you think more people contributing would improve the quality of what is being provided by the code?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Big disclaimer: these are not questions that necessarily need a &amp;quot;yes&amp;quot; answer to move forward. The answers will mean more or less to your situation. Whether you&#39;re open sourcing your code to get a lot of contributors involved quickly, or just as an exercise to become more proficient in the relevant skills. Just consider how the answers might affect your results.&lt;/p&gt;
&lt;h3&gt;Step 1: Prep the Code&lt;/h3&gt;
&lt;p&gt;The baseline requirement for a project to be viable in the open source landscape comes down to the thing that makes open source a concept in the first place: enabling other people to be productive using, modifying, and improving its code. With that obvious requirement, you need to ask yourself a simple question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If I handed someone this project right now, how hard would it be for them to read the code, run the code, and change the code?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You could follow up on that with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Are there any tools that the contributor should install or be familiar with before getting started?&lt;/li&gt;
&lt;li&gt;Does it matter what platform the person is working on (Windows vs Mac vs Linux)?&lt;/li&gt;
&lt;li&gt;How can the person be confident that making a change in one place won&#39;t break something else in the code, i.e are there any tests?&lt;/li&gt;
&lt;li&gt;Is the code well organized and easy to follow?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of these points are really to say that if you&#39;re going to be putting something out there with the intention of others picking it up and working on it, you should take the necessary steps to set them up with a quality product. There are many books out there that outline some of the best practices for writing good code (&lt;a href=&quot;https://www.oreilly.com/library/view/clean-code/9780136083238/&quot;&gt;Clean Code&lt;/a&gt; comes to mind). You might consider handing off your project to someone with technical knowledge but who&#39;s not familiar with it and get their feedback for how easy some basic development task was to complete.&lt;/p&gt;
&lt;h3&gt;Step 2: README&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;README&lt;/strong&gt; might be the most important document included with a project when it comes to providing a newcomer with the summary of what your project is all about. In addition to a brief summary of what the the code is trying to accomplish, the README is the first place you can answer some of the questions listed above. Someone stumbling on your code should be able to start by going through the README and end by at least being able to understand what the code can do, download it to their machine, and run it.&lt;/p&gt;
&lt;p&gt;Try to find some examples of cool README documents from some of the prominent open source projects on Github. As flashy as they are with badges and logos, remember that they all answer the basic questions listed above in some way.&lt;/p&gt;
&lt;h3&gt;Step 3: The License&lt;/h3&gt;
&lt;p&gt;The open source &lt;strong&gt;license&lt;/strong&gt; is probably the second most important document you want to include in your project before releasing it out into the wild. In short, since you&#39;re putting your code out there for anyone to see, you probably want to have some control over what people can and can&#39;t do with it once they have it. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Are you OK with someone using it to run their business?&lt;/li&gt;
&lt;li&gt;Are you OK with someone modifying it and selling it as their own, new product?&lt;/li&gt;
&lt;li&gt;Does the entity using your code need to explicitly give your credit when using any original or modified version of your code?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The good news is, so much of the heavy legal work has already been done by other smart folks on the internet. Github does an amazing job with their &lt;a href=&quot;https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/licensing-a-repository&quot;&gt;helpful documentation&lt;/a&gt; as well as reminders when you create a public repo without a license to make sure you include the right one for your needs.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2019-04-01-how-to-open-source-your-code/1x6N_arUB-mpf6Hgd1SjChcQ.png&quot; alt=&quot;You can drop in a license right when you create the repo on Github!&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Step 4: How to Contribute&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;A set of contributing guidelines is the next important piece of documentation you should include, usually in the form of a &lt;strong&gt;CONTRIBUTING&lt;/strong&gt; document much like the README. The CONTRIBUTING document or set of documents serve to inform the prospective newcomer to your code on how you as a maintainer want them to go about making contributions.&lt;/p&gt;
&lt;p&gt;A CONTRIBUTING doc serves to answers some questions like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What are some ways I can contribute in the first place? Are you, the maintainer, just looking for bug fixes or new features?&lt;/li&gt;
&lt;li&gt;What&#39;s the first thing I should so when I want to make a change to this code?&lt;/li&gt;
&lt;li&gt;Should I create an issue or just fork and pull request?&lt;/li&gt;
&lt;li&gt;Are there any branching conventions I should follow?&lt;/li&gt;
&lt;li&gt;Should I write my commit messages in a certain way?&lt;/li&gt;
&lt;li&gt;Who are the maintainers aka. who&#39;s in charge here?&lt;/li&gt;
&lt;li&gt;Do you follow any coding styleguides?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&#39;s an example of a basic CONTRIBUTING document I came up with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Hello! Thanks for contributing to &amp;lt;Insert Awesome Project Here&amp;gt;

# How to Contribute
Step 1. Please open an Issue with a description of what you&#39;re trying to add/fix/change

Step 2. Fork and create a feature branch in the format &amp;lt;some-description&amp;gt;/&amp;lt;your issue number&amp;gt;

Step 3. Please squash all your commits into one with a good commit message before opening a pull request

Step 4. Open a pull request, reference your original issue, and provide a concise description of how your changes fixed the issue

Step 5. Your PR requires 2 approvals from maintainers before it can be merged.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can go as wild as you want with it. Just like the code, all the documentation is also open source, so it can also evolve and improve along with your project! Check out Github&#39;s &lt;a href=&quot;https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/setting-guidelines-for-repository-contributors&quot;&gt;documentation&lt;/a&gt; for some &lt;strong&gt;&lt;em&gt;amazing&lt;/em&gt;&lt;/strong&gt; examples of contributing documents in the wild. I particularly like the short and sweet &lt;a href=&quot;https://github.com/opengovernment/opengovernment/blob/master/CONTRIBUTING.md&quot;&gt;Open Government Contributing guidelines document&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Step 5: Community&lt;/h3&gt;
&lt;p&gt;Open source is at its best when you have a strong community behind it. Whether is just you and a couple of maintainers, or a project that you foresee spanning hundreds of contributors, it&#39;s important to set a precedent for the spirit of collaboration you want to establish around your projects.&lt;/p&gt;
&lt;p&gt;While documentation like the README and CONTRIBUTING guidelines could also touch on this subject in some ways, the &lt;strong&gt;CODE OF CONDUCT&lt;/strong&gt; is where you should be most direct about how you expect people to behave and interact with each other.&lt;/p&gt;
&lt;p&gt;People might not be explicitly asking the questions that the code of conduct document seeks to answer, but it can always be there to set a baseline standard of conduct if issues were to ever arise. Some of these implicit questions might be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Are contributors expected to converse with each other as if they were in a professional setting like an office, or is the tone more informal?&lt;/li&gt;
&lt;li&gt;What are some of the core values someone should adhere to when approaching interpersonal interactions within the community?&lt;/li&gt;
&lt;li&gt;What should someone do if they notice someone behaving inappropriately within the community?&lt;/li&gt;
&lt;li&gt;What, if any action, would be taken if someone were to break the etiquette rules?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&#39;s an example of the simplest code of conduct document I thought up.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Code of Conduct

- Be kind
- Be welcoming
- Don&#39;t be a jerk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Feel free to copy if you find it helpful!&lt;/p&gt;
&lt;p&gt;But in all seriousness, there are lots of great examples available to reference just like all the other documents. One example is Facebook&#39;s &lt;a href=&quot;https://engineering.fb.com/&quot;&gt;Open Source Code of Conduct&lt;/a&gt; which they link to in all of their open source project repos.&lt;/p&gt;
&lt;h3&gt;Step 6: Consistency&lt;/h3&gt;
&lt;p&gt;Making sure your open source project is successful and productive depends, just like any other project, on you giving it the appropriate amount of time it needs to succeed. This could include simple actions like regularly updating dependencies on major releases, or going through all the open Issues and Pull Requests at least once a week. It&#39;s always better to have someone come across your repo and see commits and merged PR&#39;s that are a few days old rather than a few weeks or months old.&lt;/p&gt;
&lt;p&gt;For larger projects with many users and contributors, it might mean making sure you&#39;re being responsive to emails or messages. A common practice among larger open source projects is to have a public instant messaging platform like Slack available for anyone with questions or suggestions to join the community discussion about the project.&lt;/p&gt;
&lt;h3&gt;Further Reading&lt;/h3&gt;
&lt;p&gt;I highly recommend &lt;a href=&quot;https://docs.github.com/&quot;&gt;Github&#39;s entire knowledge base&lt;/a&gt; for how to do open source right, specifically their section on &lt;a href=&quot;https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions&quot;&gt;Setting up your project for healthy contributions&lt;/a&gt; which I think is most relevant to the content in this piece.&lt;/p&gt;
&lt;p&gt;Below are some of my favorite example open source projects which have great, real-world examples of everything I mentioned above and more:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/facebook/react&quot;&gt;React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/prometheus/prometheus&quot;&gt;Prometheus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tensorflow/tensorflow&quot;&gt;Tensorflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Microsoft/vscode&quot;&gt;VS Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/concourse/concourse&quot;&gt;Concourse CI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/trending&quot;&gt;trending page on Github&lt;/a&gt; is also a great go-to for fresh, quality, open source content.&lt;/p&gt;
&lt;p&gt;I really hope this helps you get started with open sourcing your own projects. Let me know about your experiences on &lt;a href=&quot;https://x.com/Nirespire&quot;&gt;X&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Good luck and have fun!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Moving to GatsbyJS</title>
    <link href="https://sanjaynair.me/blog/2019-05-21-moving-to-gatsbyjs/"/>
    <updated>2019-05-21T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2019-05-21-moving-to-gatsbyjs/</id>
    <content type="html">&lt;aside class=&quot;editorial-note&quot; role=&quot;note&quot; aria-label=&quot;Editor&#39;s note&quot;&gt;
&lt;p class=&quot;editorial-note__header&quot;&gt;&lt;strong&gt;Editor&#39;s note &amp;middot; May 2026&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;editorial-note__body&quot;&gt;
&lt;p&gt;When this post was written the site ran on Gatsby. The site has since been rebuilt on &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;11ty (Eleventy)&lt;/a&gt; with Tailwind CSS, so the Gatsby endorsement below reflects the state of the stack in 2019 rather than a current recommendation.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;aside class=&quot;editorial-note&quot; role=&quot;note&quot; aria-label=&quot;Editor&#39;s note&quot;&gt;
&lt;p class=&quot;editorial-note__header&quot;&gt;&lt;strong&gt;Editor&#39;s note &amp;middot; June 2026&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;editorial-note__body&quot;&gt;
&lt;p&gt;Two external links in this post have been updated to their current canonical URLs: GitHub&#39;s documentation site moved from &lt;code&gt;help.github.com&lt;/code&gt; to &lt;a href=&quot;https://docs.github.com/&quot;&gt;docs.github.com&lt;/a&gt;, and Gatsby&#39;s main domain switched from &lt;code&gt;gatsbyjs.org&lt;/code&gt; to &lt;a href=&quot;https://www.gatsbyjs.com/&quot;&gt;gatsbyjs.com&lt;/a&gt; when Gatsby Cloud launched.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;There are lots of tools to build websites freely available to download and use online. You might want to go at it with just plain HTML, CSS, and some JavaScript. This is how I built my first personal website and unless you&#39;re trying to get fancy with frontend features or content, this might have worked well for you.&lt;/p&gt;
&lt;p&gt;Overtime, I got the itch to move my website development to something a little more robust in terms of tooling. Not so much because the content there was complex enough to merit a full-fledged frontend framework, but more so I could have a place to practice my web development skills with some modern frameworks, tools, and abstractions. The web development landscape moves so fast, I wanted to make sure I had my own sandbox to experiment and learn easily.&lt;/p&gt;
&lt;h3&gt;Static Site Generators&lt;/h3&gt;
&lt;p&gt;Since my site was basically just a static web page with some CSS and JS for responsiveness and styling, I didn&#39;t feel like I should reach for a full-featured framework like Angular or Ember. I wanted my site to be driven by simple content while I would host more specific content like videos and long-form publications on managed platforms like YouTube and Medium.&lt;/p&gt;
&lt;p&gt;I found that &lt;a href=&quot;https://jamstack.org/generators/&quot;&gt;static site generators&lt;/a&gt; fit my use-case perfectly. In short, I would be able to take advantage of the modern features of a frontend framework during development and publish plain HTML, CSS, and JS to serve to clients. Since I didn&#39;t expect to have any dynamic content on my site, there would be no restriction on what I could build. Moreover, hosting a static site is a lot simpler, as platforms like &lt;a href=&quot;https://pages.github.com/&quot;&gt;Github Pages&lt;/a&gt; provide easy ways to serve static content for free.&lt;/p&gt;
&lt;h3&gt;NuxtJS : Moving Beyond HTML/CSS/JS&lt;/h3&gt;
&lt;p&gt;While React was already dominating the web development landscape by this time, I was dabbling more in one of its mainstream competitors: VueJS. I have more or less come around to liking and even preferring React today, but back then I was initially attracted to Vue by its similarities to AngularJS. I had a lot of experience with Angular at that point and I wasn&#39;t quite ready to make the jump to the new hotness that was React.&lt;/p&gt;
&lt;p&gt;While researching some popular static site generation tools, I came across NextJS. It is developed and maintained by the Zeit team and provided a full featured static site generation solution. Just what I was looking for. The one tiny issue was that it leveraged React.&lt;/p&gt;
&lt;p&gt;After some more stubborn digging, I came across &lt;a href=&quot;https://nuxt.com/&quot;&gt;NuxtJS&lt;/a&gt;, which unashamedly advertised itself as NextJS with a fronted by Vue instead of React. I happily picked it up and was on my way to modern web development land.&lt;/p&gt;
&lt;p&gt;Once I was happy with an initial version, I generated my static assets and pushed it up to my &lt;a href=&quot;https://github.com/Nirespire/nirespire.github.io&quot;&gt;Github repo&lt;/a&gt;. Like I mentioned before, Github has excellent support for hosting static sites. Their &lt;a href=&quot;https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site&quot;&gt;documentation about Github pages&lt;/a&gt;, tight integration with repos, and the &lt;a href=&quot;https://www.npmjs.com/package/gh-pages&quot;&gt;&lt;code&gt;gh-pages&lt;/code&gt;&lt;/a&gt; tool makes it effortless to develop and host static sites.&lt;/p&gt;
&lt;p&gt;Website V2 DONE. As I expected, it was a LOT nicer to build having modern tools and features like hot-reloading and bundling available to me. I had the modern web sandbox I was looking for.&lt;/p&gt;
&lt;h3&gt;GatsbyJS : The New and Shiny&lt;/h3&gt;
&lt;p&gt;I first heard about GatsbyJS on the &lt;a href=&quot;https://syntax.fm/&quot;&gt;SyntaxFM&lt;/a&gt; podcast (which is great by the way, go subscribe). It was discussed in comparison to NextJS which I was already familiar with from my previous research. There were a lot of good things I heard about Gatsby, but nothing that had me wanting to switch my site over. Sure, it was a static site generator with modern web development tooling and features, but that&#39;s what I already had with Nuxt!&lt;/p&gt;
&lt;p&gt;Fast forward a few weeks and I&#39;m hearing some more buzz about Gatsby around the web and among other devs. There was a full-day Gatsby workshop for beginners happening at my workplace that I was interested in signing up. Normally I preferred diving into new frameworks on my own time, but I figured this was an easy jumpstart to something that was clearly picking up steam in the community. There had to be something there I was missing out on, right? After getting a quick intro to the framework, we did some hands on development with Gatsby, and that&#39;s when I finally saw what all the hype was about.&lt;/p&gt;
&lt;h4&gt;Plugins&lt;/h4&gt;
&lt;p&gt;What really made Gatsby stand out to me in terms of developer experience was the plugin system. At its core, you can build a complete Gatsby static site with plain-old React and CSS styles. To add to this, plugins are easy, plug and play node_modules you can import during development to make building your site far more efficient and manageable.&lt;/p&gt;
&lt;p&gt;Like I said before, the site I built was really quite simple, nothing more than a landing page with links to external sites with my other content. However, Gatsby plugins sparked some cool ideas for enhancements to what I already had. For example, instead of just providing a link to my profile on Medium, I could drop in the &lt;a href=&quot;https://www.gatsbyjs.com/plugins/gatsby-source-medium/&quot;&gt;gatsby-source-medium&lt;/a&gt; plugin with some minimal configuration and I could now have my site automatically display previews of my latest published content.&lt;/p&gt;
&lt;p&gt;Similarly, I never thought about how I didn&#39;t integrate Google Analytics into my site to track user traffic. While integrating Analytics is already easy enough, it doesn&#39;t get easier than &lt;code&gt;npm install&lt;/code&gt;ing &lt;a href=&quot;https://www.gatsbyjs.com/docs/adding-analytics/&quot;&gt;gatsby-plugin-google-analytics&lt;/a&gt; and dropping a tracking id into your Gatsby config. The framework takes care of the rest during site generation.&lt;/p&gt;
&lt;p&gt;Finally, the user experience of browsing through their plugin repository is top notch. Every one links to an info page with easy access to the relevant Github repos in case you need to dive some code or submit an issue.&lt;/p&gt;
&lt;h4&gt;Progressive Web App Features&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/progressive-web-apps/&quot;&gt;Progressive Web Apps&lt;/a&gt; or PWA&#39;s are a class of web applications that adhere to certain standards or performance and accessibility. In general, if you build your websites to the PWA standards, you will make it easier for everyone to use your website, regardless of their network or hardware capabilities.&lt;/p&gt;
&lt;p&gt;Faster load times and more responsive behavior are the main claims to fame in my opinion. Dan Abramov from the React team &lt;a href=&quot;https://x.com/dan_abramov/status/1083502444024340481&quot;&gt;called this out&lt;/a&gt; about the ReactJS site and its freaky fast performance.&lt;/p&gt;
&lt;h4&gt;Conversion: The Developer Experience&lt;/h4&gt;
&lt;p&gt;Although Vue and React have pretty different paradigms in terms of how they expect applications to be structured, the simplicity of my website allowed me to basically just copy paste over what I had. I started with a barebones &lt;a href=&quot;https://www.gatsbyjs.com/starters/gatsbyjs/gatsby-starter-blog/&quot;&gt;gatsby-starter-hello-world&lt;/a&gt; and started moving things over. The biggest manual work I had to do was convert my HTML markup into JSX, which was a step forward since it helped me modularize the markup quite a bit.&lt;/p&gt;
&lt;p&gt;Routing between pages is handled implicitly. If you drop a &lt;code&gt;home.jsx&lt;/code&gt; file into your &lt;code&gt;src/pages&lt;/code&gt; directory, Gatsby will build it into the &lt;code&gt;/home&lt;/code&gt; route automatically. CSS and other static assets like images and build in automatically from the &lt;code&gt;static&lt;/code&gt; directory, and Gatsby does a great job bundling and minifying everything behind the scenes for efficient delivery to the client. I only had one page to worry about, and this model was just like Nuxt, so there was no major things to learn here.&lt;/p&gt;
&lt;p&gt;Switching my site over to Gatsby basically out of the box provided me with a pretty significant boost in web performance as measured by Google&#39;s &lt;a href=&quot;https://developers.google.com/web/tools/lighthouse/&quot;&gt;Lighthouse&lt;/a&gt; analyzer. &lt;a href=&quot;https://x.com/Nirespire/status/1117481391527272454&quot;&gt;I tweeted my experience as such&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;More and more&lt;/h4&gt;
&lt;p&gt;Some things I&#39;m still exploring but know are pretty unique to Gatsby include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GraphQL support&lt;/strong&gt;: Basically anything data-related in your application can be accessed through a full GraphQL server running in your development environment. The Medium plugin I mentioned earlier is driven off this.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CMS Integration&lt;/strong&gt;: I&#39;d like to eventually move my site to a BYOF or Bring Your Own Frontend system where a managed platform could host and serve all my data and API needs while my Gatsby site could continue to run statically. &lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt; and &lt;a href=&quot;https://www.drupal.org/&quot;&gt;Drupal&lt;/a&gt; and a couple of these on my radar.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Suffice it to say, I have no regrets converting to Gatsby. I&#39;m pretty convinced the hype was real. Gatsby is here to stay as a remarkably solid choice for modern static and progressive web app construction.&lt;/p&gt;
&lt;p&gt;I&#39;m looking forward to improving my site with the suite of tools and plugins offered by Gatsby and well as the fresh developer experience of working with it as my static site framework.&lt;/p&gt;
&lt;p&gt;If you have any thoughts or suggestions, please let me know on &lt;a href=&quot;https://x.com/Nirespire&quot;&gt;X&lt;/a&gt;. Also keep an eye on my &lt;a href=&quot;https://sanjaynair.me/&quot;&gt;website&lt;/a&gt; for upcoming additions!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Why I Think Software Should be Rewritten Every Three Years</title>
    <link href="https://sanjaynair.me/blog/2019-06-11-why-i-think-software-should-be-rewritten-every-three-years/"/>
    <updated>2019-06-11T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2019-06-11-why-i-think-software-should-be-rewritten-every-three-years/</id>
    <content type="html">&lt;p&gt;One of the most common tropes of working as a software engineer I&#39;ve noticed is the constant lambasting of &lt;strong&gt;old code&lt;/strong&gt;. Anything older than a few years was never described by my peers as anything close to elegant, easy to read, maintainable, or generally pleasurable to work with.&lt;/p&gt;
&lt;p&gt;There are many existing posts out there (at least &lt;a href=&quot;https://medium.com/@way/rage-against-the-codebase-programmers-and-negativity-d7d6b968e5f3&quot;&gt;one I&#39;ve read&lt;/a&gt;) that outline how to emotionally deal with the inevitable headaches of old code. It came off as something to be coped with, not something that could be solved.&lt;/p&gt;
&lt;p&gt;This got me thinking about a few things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is the reduction of maintainability of a codebase over time inevitable?&lt;/li&gt;
&lt;li&gt;What causes this kind of code to rot in the real world?&lt;/li&gt;
&lt;li&gt;How do we fight it?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Codebase Maintainability Over Time&lt;/h3&gt;
&lt;p&gt;I recently read a &lt;a href=&quot;https://martinfowler.com/articles/is-quality-worth-cost.html&quot;&gt;post by Martin Fowler&lt;/a&gt; where writes about the tradeoff between the cost to produce and resulting quality of software being developed. He refers to a phenomenon where, over time, a codebase gets populated with increasing levels of &lt;strong&gt;cruft&lt;/strong&gt;, which he defined as: &amp;quot;the difference between the current code and how it would ideally be.&amp;quot; When you dive into a codebase, you probably want as little as possible getting in your way of understanding what that code is doing. Cruft is what you&#39;re seeing when you open up that 2000 line file, written by 10 people you&#39;ve never met, over a period of 5 years.&lt;/p&gt;
&lt;p&gt;Fowler argues that it&#39;s in the best interest of the engineers as well as business partners that code quality and minimization of cruft be at the forefront of thought when making changes to software. He states that taking the extra time to write quality code in the present has compound benefits for the future. Internal quality means it&#39;s easier to modify software, which means faster delivery of features.&lt;/p&gt;
&lt;p&gt;Your users don&#39;t care about software quality, they only care about the velocity of new features being delivered and their quality. Taking extra time now to deliver a feature with quality code now only helps deliver the next feature in less time. Conversely, taking less time to deliver a feature faster with less quality only hurts your ability to deliver the next feature faster due to the addition of more cruft.&lt;/p&gt;
&lt;p&gt;Yet the point he was making was somewhat softened when he noted:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;…even the finest teams will inevitably create some cruft as they work.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So maybe it&#39;s fair to say software quality is doomed to decline over time? Perhaps that decline might be slower or faster depending on the level of effort put into minimizing it. But it will happen.&lt;/p&gt;
&lt;h3&gt;Code Isn&#39;t the Only Thing That&#39;s Changing&lt;/h3&gt;
&lt;p&gt;When we think about the reasons why changing software becomes harder over time, we might only consider the increasing number of lines of code or bad code practices slowly creeping their way in. But there is a lot more changing, not only in the code, but &lt;em&gt;all around&lt;/em&gt; it. This only adds to the struggles holding teams back from keeping the software running and maintained.&lt;/p&gt;
&lt;h4&gt;Business requirements&lt;/h4&gt;
&lt;p&gt;It&#39;s the common trope you might be familiar with: &amp;quot;The requirements have changed…again!&amp;quot; As much as we&#39;d like to think we can either properly spec a piece of software&#39;s requirements ahead of time, or work with &amp;quot;agile&amp;quot; methods to keep your requirements at pace with changing feedback and expectations, ultimately the needs your software serves typically changes more with each passing iteration of development.&lt;/p&gt;
&lt;p&gt;I&#39;m no structural engineer or architect, but I consider the reasons why builders or city planners would decide to demolish and rebuild a building rather than continuously enhance it. Obviously, physical materials will degrade overtime unlike code. But what if the requirements of a building changed like the requirements of software? Suddenly the location of the structure could change between weeks, like the deployment environment of software. The patrons of the building could start to expect different things from it, like the changing expectations of software users. Where the building was designed to withstand blizzards, suddenly earthquakes are what&#39;s happening day to day. At what point do we say it&#39;s time to demolish and start over?&lt;/p&gt;
&lt;p&gt;This is probably a massive generalization when discussing software depending on the type of business or industry your software is serving. However, I still feel it valuable to acknowledge the correlation of how quickly your requirements change to how fundamentally irrelevant your codebase becomes over time.&lt;/p&gt;
&lt;h4&gt;Software dependencies&lt;/h4&gt;
&lt;p&gt;Most software is built with other software that&#39;s just as prone to change as anything else we&#39;re discussing here. Libraries, frameworks, design paradigms, and certainly entire programming languages come and go with the rapid pace of the software engineering landscape. The longer that a single piece of software stays stagnant in this landscape, the more likely it is to become fundamentally detached with it.&lt;/p&gt;
&lt;p&gt;This could mean that your software harbors critical security vulnerabilities patched in more modern iterations of its included frameworks or libraries (Apache Struts comes to mind). The developer experience might suffer from working with these dependencies due to waning support for tools. Solving the software problem becomes an issue of keeping the solution in bounds with the dependencies and tools at hand rather than considering all the possibilities for solving the problem most effectively and efficiently.&lt;/p&gt;
&lt;h4&gt;Team members and maintainers&lt;/h4&gt;
&lt;p&gt;It&#39;s increasingly common to see folks in the software engineering world to not stick around the same job for more than a couple of years. Employers are increasingly acknowledging the value of technical problem solvers with a wide breadth of experience and even encourage them to be flexible in their career paths with respect to their place of employment. This is clearly a positive for the individual, who has the increased agency to jump between companies and teams and contribute their widening breadth of knowledge to solving hard problems.&lt;/p&gt;
&lt;p&gt;What this trend results in is teams with increased turnover, meaning more pains to get people up to speed with existing systems. Conversely, this also leads to teams staffed with problem solvers that can pull from their previous experience and look at solving problems from diverse lenses. Why not allow these fresh minds to lay the foundation differently with a fresh set of eyes? We should not discount the clear win of having a fluid set of minds working the problem just because something that &amp;quot;works&amp;quot; is already in production.&lt;/p&gt;
&lt;p&gt;What happens when the codebase you&#39;re working with was started and worked on by people you have never met? What about when every person on the team inherited the code and had no say in its initial creation? This to me is another inevitable and difficult inflection point where teams need to take a hard look at why they shouldn&#39;t have the freedom to just start over.&lt;/p&gt;
&lt;h3&gt;A Clean Start&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2019-06-11-why-i-think-software-should-be-rewritten-every-three-years/1xpp9ITHW9tW79mxsqk3BOCw.gif&quot; alt=&quot;Let your code be reborn from the ashes anew&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Given all of my previous points, here&#39;s what I&#39;m proposing: Software, given enough time, will reach an inflection point where the cost to maintain the existing solution far exceeds the cost to rewrite it. Here are some potential reasons why:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Business requirements the software was originally built for have moved far enough away from the original requirements.&lt;/li&gt;
&lt;li&gt;The external dependencies of the software have changed beyond the point of simply upgrading or retrofitting.&lt;/li&gt;
&lt;li&gt;The people working on the software had no skin in the game when it was originally being created.&lt;/li&gt;
&lt;li&gt;The design or architecture does not directly cater to the current problem being solved.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you see any one of these factors becoming increasingly apparent over time, you need to make a decision as to when it&#39;s appropriate to start over.&lt;/p&gt;
&lt;p&gt;I picked the three year timeframe in the title of this piece as a rule-of-thumb based on my experience. It&#39;s around this point where someone working on a project of this age starts to encounter friction in one of the above categories. This could vary wildly between problem domains, but that&#39;s the number I thought was right for what I know.&lt;/p&gt;
&lt;h3&gt;Reaching a Steady State&lt;/h3&gt;
&lt;p&gt;After considering this you might say, &amp;quot;if you&#39;re rewriting everything every three years, then at some point you going to be doing nothing but rewriting stuff!&amp;quot;&lt;/p&gt;
&lt;p&gt;Certainly, the tradeoff between doing a rewrite and just continuing to change the existing codebase will cross at some point. As you see the variables around your software declining, like new feature requests, so should you see the need for a rewrite of the software becoming less necessary.&lt;/p&gt;
&lt;p&gt;As another general rule-of-thumb: &lt;strong&gt;Stop rewriting when external variability has declined to the point where the following are more or less at a steady state between periods where a rewrite is considered&lt;/strong&gt;. Some factors to consider after a three year time period might include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The same people/team are still working on the software.&lt;/li&gt;
&lt;li&gt;No new requirements are coming in that fit the profile of the existing software. If the requirements are different enough, you&#39;re probably going to write something new anyway.&lt;/li&gt;
&lt;li&gt;Any refactor or update to software libraries or frameworks provide no additional internal value to the developers or external value to the users or business.&lt;/li&gt;
&lt;li&gt;Rewriting your software it is direct conflict with the best interest of your users (I can&#39;t see anyone clambering for a full rewrite of airplane autopilot or nuclear reactor control system software every year).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&#39;m sure these are plenty of projects that are totally outside the realm of ever needing a complete rewrite. But be careful not to lump them in with other projects that don&#39;t meet these criteria simply because they &amp;quot;work in production now.&amp;quot;&lt;/p&gt;
&lt;h3&gt;Conclusions&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Change is the only constant in life&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;-Heraclitus&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Just as time inevitably passes, so do the factors around what ultimately made your software what it is. Requirements, tools, and people are in constant flux over time which inevitably leads to cruft in not only lines of code, but also in the relationships between your software, its users, and its maintainers.&lt;/p&gt;
&lt;p&gt;I want us to critically question the apparent inevitability of legacy code being a negative experience. Once we come to terms with the cause of this problem, I want us to confidently say we know how to combat it. We should not be afraid to start with a clean slate more often than staying safe in the status quo.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This is my first crack at an opinion piece, so I&#39;d love to hear any feedback including counterarguments or supporting experiences. Everything said here was my own opinion and not reflective of any person or entity I&#39;ve worked with. Please bring your own thoughts to this discussion here or on X &lt;a href=&quot;https://x.com/Nirespire&quot;&gt;@Nirespire&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Automating Dependency Upgrades with Dependabot and CI</title>
    <link href="https://sanjaynair.me/blog/2020-01-08-automating-dependency-upgrades-with-dependabot-and-ci/"/>
    <updated>2020-01-08T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2020-01-08-automating-dependency-upgrades-with-dependabot-and-ci/</id>
    <content type="html">&lt;aside class=&quot;editorial-note&quot; role=&quot;note&quot; aria-label=&quot;Editor&#39;s note&quot;&gt;
&lt;p class=&quot;editorial-note__header&quot;&gt;&lt;strong&gt;Editor&#39;s note &amp;middot; June 2026&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;editorial-note__body&quot;&gt;
&lt;p&gt;All of the GitHub help links in this post have been updated to their current canonical URLs. GitHub retired the &lt;code&gt;help.github.com&lt;/code&gt; domain in favor of &lt;a href=&quot;https://docs.github.com/&quot;&gt;docs.github.com&lt;/a&gt;, and the Dependabot security update, dependency graph, notifications, and branch protection articles have all moved to new paths under that domain.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;I&#39;m a big proponent of keeping software up to date. Especially in the modern day where it feels like new critical security vulnerabilities are popping up in software every other week.&lt;/p&gt;
&lt;p&gt;There&#39;s a whole industry, multiple academic fields, and career tracks just focused on this topic of software security. Smart people are always finding ways to make it easier for devs to implement best security practices when writing code.&lt;/p&gt;
&lt;p&gt;One of these many best practices is always keeping your dependencies up to date and actively upgrading them when known vulnerabilities are published. In the past, this was a mostly manual process. If a new security vulnerability was published, like a CVE, software maintainers would have to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Be aware the CVE was published&lt;/li&gt;
&lt;li&gt;See if it was related to any code they owned&lt;/li&gt;
&lt;li&gt;Find the places where it applied&lt;/li&gt;
&lt;li&gt;Upgrade where necessary&lt;/li&gt;
&lt;li&gt;Make sure the software still works correctly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let me show you how the above steps have been made easier for us with a tool recently acquired by Github called Dependabot and the principles of Continuous Integration.&lt;/p&gt;
&lt;h3&gt;Dependabot and Github&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.github.com/en/code-security/dependabot&quot;&gt;Dependabot&lt;/a&gt; is a product developed to provide automated dependency upgrades to software repositories. It was originally a paid product that was acquired and integrated into &lt;a href=&quot;http://github.com/&quot;&gt;Github.com&lt;/a&gt; in May of 2019. Since then, every public repo has had access to Dependabot&#39;s integrated features out of the box when creating repos on Github.&lt;/p&gt;
&lt;h3&gt;The Github Security Tab&lt;/h3&gt;
&lt;p&gt;The Security tab is the main way that Dependabot and other automated security features on the Github platform are brought to users in their code repos. These features include automated reports of new security vulnerabilities in the repo&#39;s dependencies.&lt;/p&gt;
&lt;p&gt;If you have your code hosted on Github in a repo that you have contribution rights to, head over to the Security tab and select the option to receive Automated Security Updates.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2020-01-08-automating-dependency-upgrades-with-dependabot-and-ci/1xXE6Mv5jjflMWpfiHrSDIPg.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Note that this feature has some restrictions as to &lt;a href=&quot;https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/configuring-dependabot-security-updates&quot;&gt;which types of repos&lt;/a&gt; it is enabled for and which programming languages / &lt;a href=&quot;https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/dependency-graph-supported-package-ecosystems&quot;&gt;package managers&lt;/a&gt; it supports. Most of the projects I work in are public repos that include NPM and Docker as package managers, which are both compatible.&lt;/p&gt;
&lt;p&gt;Below is an example of what an alert looks like once Dependabot receives a new CVE publication and identifies that it applies to your repo.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2020-01-08-automating-dependency-upgrades-with-dependabot-and-ci/1x_4dgK4ls18dixzyhAf8-rA.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Once you have this set up, you can even &lt;a href=&quot;https://docs.github.com/en/account-and-profile/managing-subscriptions-and-notifications-on-github/setting-up-notifications/configuring-notifications&quot;&gt;set up your notifications preferences&lt;/a&gt; to have Github email you when a vulnerability is detected on one of your repos or provide a weekly report of findings.&lt;/p&gt;
&lt;p&gt;As far as checking the boxes we mentioned above, for every supported repo you configure this for, here&#39;s what we&#39;ve now got covered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Be aware the CVE was published ✅&lt;/li&gt;
&lt;li&gt;See if it was related to any code they owned ✅&lt;/li&gt;
&lt;li&gt;Find the places where it applied ✅&lt;/li&gt;
&lt;li&gt;Upgrade where necessary&lt;/li&gt;
&lt;li&gt;Make sure the software still works correctly&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Automated Dependency Upgrades&lt;/h3&gt;
&lt;p&gt;When you click on the Security Alert, you get information about the relevant CVE publication as well as an option to have Dependabot automatically generate a Pull Request with the appropriate dependency upgrade.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2020-01-08-automating-dependency-upgrades-with-dependabot-and-ci/1xa8o-fT0m47cQxfO_Usjbyg.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This option will not always be there and you might have to make the fix manually yourself, but consider yourself being 90% of the way there by knowing the vulnerability is there and being handed the steps to fix it.&lt;/p&gt;
&lt;p&gt;That&#39;s another item done on our checklist:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Be aware the CVE was published ☑️&lt;/li&gt;
&lt;li&gt;See if it was related to any code they owned ☑️&lt;/li&gt;
&lt;li&gt;Find the places where it applied ☑️&lt;/li&gt;
&lt;li&gt;Upgrade where necessary ✅&lt;/li&gt;
&lt;li&gt;Make sure the software still works correctly&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Custom Configurations&lt;/h4&gt;
&lt;p&gt;Dependabot is &lt;a href=&quot;https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file&quot;&gt;highly configurable&lt;/a&gt; if you would like finer control over how it behaves. You can set things like what package management systems to cover, how frequently it should scan your repo, and even assign specific users to address any security issues with dependencies that are identified.&lt;/p&gt;
&lt;p&gt;Below is an example &lt;code&gt;.dependabot/config.yaml&lt;/code&gt; file I included in the repo for my &lt;a href=&quot;https://sanjaynair.me/&quot;&gt;personal website&lt;/a&gt;.&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/Nirespire/04838f40753f691feb73a26452ce86d4.js&quot;&gt;&lt;/script&gt;
&lt;h3&gt;Automated Testing and Continuous Integration&lt;/h3&gt;
&lt;p&gt;The last item on our automated dependency upgrade checklist is a way to make sure that upgrading our dependencies doesn&#39;t break our software. There&#39;s always some inherent risk with making upgrades since changing code could imply an unexpected change in functionality. However, this risk is well worth it compared to leaving security vulnerabilities in your dependencies. Moreover, this risk can be mitigated with a few extra best practices and automation steps.&lt;/p&gt;
&lt;p&gt;Firstly, if your software and codebase is complex enough, you should always include automated testing. If you&#39;re interested in what to include, check out my &lt;a href=&quot;https://sanjaynair.me/blog/2018-10-01-the-wide-world-of-software-testing/&quot;&gt;article on the different kinds of software testing&lt;/a&gt;. If you&#39;ve written good tests, then a passing test suite should be enough to say the dependency upgrade didn&#39;t break anything.&lt;/p&gt;
&lt;p&gt;Furthermore, you can adopt some principles of Continuous Integration (&lt;a href=&quot;https://sanjaynair.me/blog/2018-05-06-what-is-cicd/&quot;&gt;which I also describe in more detail in another article&lt;/a&gt;) and have your tests run automatically when a Pull Request is opened. That way, when Dependabot automatically opens a PR or you do it manually, your CI can run your test suite and the PR is only merged when it passes.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/features/actions&quot;&gt;Github Actions&lt;/a&gt; is a way to implement CI, also directly integrated into Github. There&#39;s a hole slew of ways you could implement running tests through Actions or even another CI tool, but here&#39;s a suggest list of high-level steps to implement in your CI pipeline:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trigger your CI when a PR is opened on your repo&lt;/li&gt;
&lt;li&gt;Run tests on branch the PR is for&lt;/li&gt;
&lt;li&gt;Publish the results of the tests to the PR on Github&lt;/li&gt;
&lt;li&gt;(Optional) &lt;a href=&quot;https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches&quot;&gt;Configure branch protection rules&lt;/a&gt; to block merging the PR until the CI check has passed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your codebase or app is just not that complex and manually testing it suffices, the above steps might not even be necessary when making dependency upgrades. For example, my personal website is just a single page static site with basically zero complex functionality. If it builds and renders, I consider my testing complete.&lt;/p&gt;
&lt;p&gt;With the above steps in place, we have now checked off our last item:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Be aware the CVE was published ☑️&lt;/li&gt;
&lt;li&gt;See if it was related to any code they owned ☑️&lt;/li&gt;
&lt;li&gt;Find the places where it applied ☑️&lt;/li&gt;
&lt;li&gt;Upgrade where necessary ☑️&lt;/li&gt;
&lt;li&gt;Make sure the software still works correctly ✅&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Keeping your software dependencies is easier now than I think it has ever been. I believe it is every developer&#39;s responsibility to be aware of best-practices and take advantage of the constantly improving tools we have freely available at our disposal.&lt;/p&gt;
&lt;p&gt;If you have any thoughts about this topic, please leave a comment or reach out on X &lt;a href=&quot;https://x.com/Nirespire&quot;&gt;@Nirespire&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Tracing and Observability</title>
    <link href="https://sanjaynair.me/blog/2020-02-25-tracing-and-observability/"/>
    <updated>2020-02-25T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2020-02-25-tracing-and-observability/</id>
    <content type="html">&lt;p&gt;Think back to the last time you checked the tracking information for a package you were expecting to receive. You might have followed a link in your email that gave you a breakdown of where and when your package was received and shipped out of various locations. You could make a mental map of what shipping facilities passed through around the world it and how long it spent there and on the road. From that information, you probably got a sense of what kind of journey your package took and why it took as long as it did to get to your doorstep.&lt;/p&gt;
&lt;p&gt;We can take this principle of tracking the path of a package across various stops and apply it to the flow of information between software systems. In the current paradigm of distributed microservices, where a simple request to load a webpage might bounce between a dozen different applications, it becomes valuable to &lt;strong&gt;observe&lt;/strong&gt; or &lt;strong&gt;trace&lt;/strong&gt; the path of data requests across applications and networks.&lt;/p&gt;
&lt;h3&gt;Client-Server Example&lt;/h3&gt;
&lt;p&gt;I like to bring the concept of open tracing down to the level of two applications in a client-server model. We can take the concepts here and expand on them to apply to any number of applications orchestrated together.&lt;/p&gt;
&lt;p&gt;Say, for example, we have a simple web server application that receives a request at the endpoint /hello and sends back a static string of text &amp;quot;hello&amp;quot; back to the client.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2020-02-25-tracing-and-observability/1xGg60-W1EKRbjqYrIwcPn6Q.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;From the perspective of the client, they send a request, wait some time for things like the network between itself and the server as well as time for the server to process the request. Within the server, there is only a single action that occurs, within the context of the same application. We can visualize this entire transaction in a &amp;quot;span&amp;quot;. This span has a begin and ending time as well as some detail or &amp;quot;tag&amp;quot; about the type of operation being performed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2020-02-25-tracing-and-observability/1xaNOI94aMiZau_5brcn558A.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Now the client knows about the request and response, including what was sent, when it was sent, what was received back, and when it was received back. The server knows something similar but from its own perspective of when a request was received and responded to.&lt;/p&gt;
&lt;p&gt;The missing piece here is that without us drawing out the scenario or manually associating these events between the two applications, there&#39;s no easy way to link them together and gain insights about this interaction.&lt;/p&gt;
&lt;h3&gt;Tracing Requests&lt;/h3&gt;
&lt;p&gt;In order to start creating a complete picture of the interaction between these two applications, we need an outside &amp;quot;&lt;strong&gt;observer&lt;/strong&gt;&amp;quot; to gather information about the client and server interactions. That observer can then look at the interactions holistically and gain better insights by looking at the complete picture.&lt;/p&gt;
&lt;p&gt;In this example, let&#39;s say that the client and server know about this observer and report every time they send or receive data. They will tell the observer about every relevant event in the exchange with the following information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Who they are&lt;/li&gt;
&lt;li&gt;Who they&#39;re interacting with&lt;/li&gt;
&lt;li&gt;If they&#39;re sending or receiving data&lt;/li&gt;
&lt;li&gt;What data they&#39;re sending or receiving&lt;/li&gt;
&lt;li&gt;A timestamp when that event occurred&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The interaction might follow as illustrated below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2020-02-25-tracing-and-observability/1x1YFvPksRP1DLE3q6Rwt2ow.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Here&#39;s the breakdown of actions that the Observer is recording:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Client sends a /hello request to Server at time0&lt;/li&gt;
&lt;li&gt;Server receives /hello request from Client at time1&lt;/li&gt;
&lt;li&gt;Server processes request and responds to Client with &amp;quot;hello&amp;quot; at time2&lt;/li&gt;
&lt;li&gt;Client receives &amp;quot;hello&amp;quot; from Server at time3&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;The observer is now able to correspond to the events of this two-party interaction as a contiguous group of information. Here are now some interesting insights we can gain from this simple integration between just two systems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Where was the most latency happening? Maybe it was in the network between the client and server, or maybe the server processing time.&lt;/li&gt;
&lt;li&gt;If the request failed, did it ever make it to the server or was it lost in the link between it and the client?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can even take it a step further and break the processing in the Server into multiple steps and report those to the Observer as well.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Client sends a /hello request to Server at time0&lt;/li&gt;
&lt;li&gt;Server receives /hello request from Client at time1&lt;br /&gt;
&lt;strong&gt;2.a. Server parses the request from the Client at time1a&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;2.b. Server runs the buildResponse() function to provide the appropriate response to the requester at time1b&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Server responds to Client with &amp;quot;hello&amp;quot; at time2&lt;/li&gt;
&lt;li&gt;Client receives &amp;quot;hello&amp;quot; from Server at time3&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now we can go even deeper and see how long certain processes are taking on the server or even exactly which process might have failed during an exchange.&lt;/p&gt;
&lt;h3&gt;Spans and Traces&lt;/h3&gt;
&lt;p&gt;Let&#39;s take the above example of information that the Observer is recording and add two more pieces of information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;Span ID&lt;/strong&gt; that an application generates every time it reports an event&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Trace ID&lt;/strong&gt; that each application will pass along if the data it receives contains it. If not available, a new one will be generated and reported.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the applications attach this metadata to the events they&#39;re sending to the Observer, now the data the Observer records will look something like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Client sends a /hello request to Server at time0 &lt;strong&gt;(TraceID: hellorequest1, SpanID: 1)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Server receives /hello request from Client at time1 &lt;strong&gt;(TraceID: hellorequest1, SpanID: 2)&lt;/strong&gt;&lt;br /&gt;
2.a. Server parses the request from the Client at time1a &lt;strong&gt;(TraceID: hellorequest1, SpanID: 3)&lt;/strong&gt;&lt;br /&gt;
2.b. Server runs the buildResponse() function to provide the appropriate response to the requester at time1b &lt;strong&gt;(TraceID: hellorequest1, SpanID: 4)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Server responds to Client with &amp;quot;hello&amp;quot; at time2 &lt;strong&gt;(TraceID: hellorequest1, SpanID: 5)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Client receives &amp;quot;hello&amp;quot; from Server at time3 &lt;strong&gt;(TraceID: hellorequest1, SpanID: 6)&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;The Observer can now use the Trace ID to group these series of events together and break it down into its individual parts using the Span IDs.&lt;/p&gt;
&lt;p&gt;Since this will probably clutter up the component diagram, this information can be summarized as a series of spans in time. Note the functions on the client to process the response are omitted, but you can surmise what the spans for those might look like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2020-02-25-tracing-and-observability/1xU2Xg9zQ4GscTAr9sHBdAdw.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The Span ID &amp;quot;hellorequest1&amp;quot; covers all the spans below it and logically groups the tracing information of the events happening within it like the client sending the request, the server receiving it, and the server processing to send the response back to the client.&lt;/p&gt;
&lt;p&gt;The Client generates a Trace ID when it initiates the interaction. From then on, each participant in the exchange knows to pass on the Trace ID if it is present. Each participant also know to generate a new Span ID every time data is moved from one logical context or operation to the next. Every event is reported to the Observer along with these IDs. In that way, each complete transaction can be logically grouped but also deconstructed into its individual pieces once assembled at the Observer.&lt;/p&gt;
&lt;h3&gt;Tracing Multiple Applications&lt;/h3&gt;
&lt;p&gt;Let&#39;s take our example with two applications and extend it to four applications.&lt;/p&gt;
&lt;p&gt;Let&#39;s say the exchange still starts with our Client application, but this time it&#39;s sending a /readinfo request to the Server. The Server can&#39;t process this request by itself, so it sends a request each to two other applications, let&#39;s call them the &lt;strong&gt;SecurityService&lt;/strong&gt; and &lt;strong&gt;InfoService&lt;/strong&gt;. When Server receives a /readinfo request, it has to first ask the SecurityService if the requester has the right permissions to read this info. If that is successful, it then calls the InfoService to pull the info, and finally sends it back to the requester.&lt;/p&gt;
&lt;p&gt;Let&#39;s draw this interaction out. We can label the order in which the operations happen and we can then infer the series of events being recorded by the Observer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2020-02-25-tracing-and-observability/1x6icOp7aWjJf87xPlGdkx_A.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Here&#39;s what the Observer recorded based on the events each application sent it. All the events are listed with the numbers from the diagram matching the numbers on the list. I&#39;m omitting timestamps and ID&#39;s to save some space, but you can fill in the blanks:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Client sends a /readinfo request to Server&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Server receives a /readinfo request&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Server sends an /access request to SecurityService&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;SecurityService receives an /access request&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;SecurityService responds to the /access request&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Server receives the /access response from SecurityService&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Server sends an /info request to InfoService&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;InfoService receives an /info request&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;InfoService responds to the /info request&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Server receives the /info response from InfoService&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Server responds to the /readinfo request from Client&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Client receives the /readinfo response&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Just by adding two players into the mix, the number of events being recorded has grown quite a bit. We can visualize the same list of events as spans to provide a better view of the execution path of the /readinfo request:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2020-02-25-tracing-and-observability/1xT5EAMjSAPDtQlej2I1bu8w.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Notice all the events are still grouped in the same TraceID, but we can see the span of each individual service passing the request between each other and working together to process the final result to the Client.&lt;/p&gt;
&lt;p&gt;We could extend the granularity of the spans further by including details about functions and subroutines running within each application.&lt;/p&gt;
&lt;h3&gt;Out of the Example and Into the Real World&lt;/h3&gt;
&lt;p&gt;The above concepts are simplified versions of terms and constructs formalized in the &lt;a href=&quot;https://opentelemetry.io/&quot;&gt;Opentracing Specification&lt;/a&gt; for microservices and distributed applications.&lt;/p&gt;
&lt;p&gt;There are many opensource libraries and software that implement the Opentracing specification. You can integrate these into your own applications to gain powerful insights into the interactions of your microservices.&lt;/p&gt;
&lt;p&gt;Once your application can communicate via Opentracing, you still need an Observer to record all the events being emitted from the applications. There are many systems that implementing the Opentracing spec. Zipkin is one of these popular distributed tracing systems that you can install and run yourself. It plays the part of the Observer from our examples and consumes tracing data from applications that adhere to the Opentracing standard to provide interactive visuals of your application traces.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/blog/2020-02-25-tracing-and-observability/0xp7vUaXbA6c6ak0uX.png&quot; alt=&quot;Source: https://zipkin.io/public/img/web-screenshot.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If you&#39;re like more information about Opentracing, you can check out their &lt;a href=&quot;https://opentelemetry.io/&quot;&gt;website&lt;/a&gt; which has specification docs as well as guides to get started with Opentracing.&lt;/p&gt;
&lt;p&gt;You can also play around with &lt;a href=&quot;https://zipkin.io/pages/quickstart.html&quot;&gt;zipkin&lt;/a&gt; which has library support for &lt;a href=&quot;https://zipkin.io/pages/tracers_instrumentation.html&quot;&gt;pretty much any programming language&lt;/a&gt; you&#39;re probably thinking of using.&lt;/p&gt;
&lt;p&gt;Let me know your thoughts about this article or Opentracing in general over on &lt;a href=&quot;https://x.com/Nirespire&quot;&gt;X&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Don&#39;t (always) use a Database</title>
    <link href="https://sanjaynair.me/blog/2020-12-28-dont-always-use-a-database/"/>
    <updated>2020-12-28T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2020-12-28-dont-always-use-a-database/</id>
    <content type="html">&lt;aside class=&quot;editorial-note&quot; role=&quot;note&quot; aria-label=&quot;Editor&#39;s note&quot;&gt;
&lt;p class=&quot;editorial-note__header&quot;&gt;&lt;strong&gt;Editor&#39;s note &amp;middot; June 2026&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;editorial-note__body&quot;&gt;
&lt;p&gt;The GitHub developer API link in this post has been updated to its current canonical URL. The standalone &lt;code&gt;developer.github.com&lt;/code&gt; site was folded into the main GitHub docs, so the REST and GraphQL API references now live under &lt;a href=&quot;https://docs.github.com/en/rest&quot;&gt;docs.github.com&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;I was recently having a design conversation with some engineers on my product team. We were discussing the implementation of a feature that dealt with saving user settings on a web app. When thinking about the concept of persistent storage, my brain automatically tended to go straight to the obvious tool that provided programmatic persistent storage: a database.&lt;/p&gt;
&lt;p&gt;Databases generally provide a flexible paradigm for storing different formats of data and standard APIs to read and write that data programmatically.&lt;/p&gt;
&lt;p&gt;However, the more we discussed and the more I thought about it, this was a case where storage locally on the browser was more than enough. We didn&#39;t care if the user could access their settings from multiple sessions or devices. It was just a few toggles that would typically be used within the same browser and specific to a single user. Why bother having to setup and maintain a database, adding complexity to the architecture and more cost of ownership?&lt;/p&gt;
&lt;p&gt;So problem solved, right? Well, yes, but the next question I asked myself after the fact was: what other places had I been defaulting to using a database where it really wasn&#39;t the best option?&lt;/p&gt;
&lt;p&gt;&amp;quot;Best&amp;quot; is very subjective and could mean a lot of things. My main consideration here is how cost effective (from a time and money perspective) is it to implement your desired feature using the given storage solution?&lt;/p&gt;
&lt;p&gt;Here are the two basic criteria I could infer when asking myself, could this service provide the same functionality as a database?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;There is a freely available method to store and retrieve some amount of data to and from the service&lt;/li&gt;
&lt;li&gt;There is a public API that can perform those functions&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The following is my basic list of services that don&#39;t present themselves as databases, but with a little imagination, can totally be used as a database.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Disclaimer: none of the below options are going to scale anywhere beyond demos or personal projects. Temper your expectations when you&#39;re basically repurposing the free-tier of popular online services for your custom storage usecase.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Google Sheets&lt;/h3&gt;
&lt;p&gt;If you have spent any amount of time browsing the Show section on Hacker news, you&#39;ve probably seen many versions of this one: using Google Sheets as your database backend. In case you didn&#39;t know, Google Sheets is Google&#39;s online spreadsheet tool you can use to author, share, and distribute Excel-like spreadsheets for various purposes. Whatever storage space your sheets take up gets added into your Google online storage total (which is an aggregation of various google storage services like Gmail, Drive, Photos, etc), of which you get a chuck of storage totally for free (15GB as of me writing this).&lt;/p&gt;
&lt;p&gt;Combine that with the available &lt;a href=&quot;https://developers.google.com/sheets/api&quot;&gt;Sheets API&lt;/a&gt;, and you can basically have yourself a free database backend. Rows on a spreadsheet basically equate to rows in your database.&lt;/p&gt;
&lt;h3&gt;Imgur&lt;/h3&gt;
&lt;p&gt;Storing media assets like images can be a resource-intensive task. You could get fancy and try to encode and compress your images into a traditional database, however many of the disadvantages of having to process raw bytes of data might outweigh the benefits.&lt;/p&gt;
&lt;p&gt;Imgur is a massive image hosting service that also provides a simple &lt;a href=&quot;https://apidocs.imgur.com/&quot;&gt;developer API&lt;/a&gt; to upload and retrieve images. There is a rate limit (50 images per hour as of me writing this) so don&#39;t expect this to scale up to real production workloads. But this, combined with a way to keep track of the IDs of your uploaded images, just might get you through your requirement.&lt;/p&gt;
&lt;h3&gt;Github&lt;/h3&gt;
&lt;p&gt;Now this one was interesting because it was a project I found that leveraged the &amp;quot;backend storage&amp;quot; potential of Github that inspired me to write this post in the first place. Github&#39;s obvious main draw is their freely available services to version control your source code repositories. While that is promising, I believe the real value might actually more so be residing in the various auxiliary services around your source code repos.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can create Issues on a repo that would typically indicate a feature request or bug report, but someone took it and turned it into a backend for a URL shortener!&lt;/li&gt;
&lt;li&gt;You can create Gists or small, miscellaneous code snippets that are simple enough to not merit an entire Git repo. Someone took that and turned it into persistent storage for &lt;a href=&quot;https://github.com/massif-press/compcon&quot;&gt;serialized tabletop RPG character data&lt;/a&gt;!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Beyond that, you have Wiki pages that provide document storage. You can create a Project board on a repo that can hold bucketed text data.&lt;/p&gt;
&lt;p&gt;All of this is of course backed by &lt;a href=&quot;https://docs.github.com/en/rest&quot;&gt;Github&#39;s ever-improving developer APIs&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;And Beyond…&lt;/h3&gt;
&lt;p&gt;I found all of these hacked &amp;quot;database&amp;quot; solutions while browsing people&#39;s random side projects on Github and reading articles on Hacker News. It helped me appreciate the opportunities we have to build on all the freely available services around the internet.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Working With Sanjay</title>
    <link href="https://sanjaynair.me/blog/2025-04-20-working-with-sanjay/"/>
    <updated>2025-04-20T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2025-04-20-working-with-sanjay/</id>
    <content type="html">&lt;p&gt;This document should serve as a concise artifact that describes my style of work and leadership. It should serve as a quick way to get up to speed with what to expect as a new colleague or member of my team.&lt;/p&gt;
&lt;p&gt;I am a strong believer in the merits of documenting, not just discussing, complex ideas for the purposes of clear and unambiguous communication. This document aims to provide an evergreen primary source of reference for my professional working style. The exercise of authoring and maintaining this document both helps me to introspect about myself as well as be transparent with those that would benefit from quickly understanding my motivations, strengths, quirks, and general style of work. The result for you reading this document and subsequently working with me should be less time spent having to figure me out as a colleague or leader and more time spent on solving interesting and difficult problems together.&lt;/p&gt;
&lt;p&gt;I expect that this document should change and evolve with my capabilities and values as a leader and professional. Moreover, I expect that the content and change history of this document should remain fully transparent and public for anyone to look up and reference at-will. Any individual who has worked with me and finds an opportunity to improve the document should be able to contribute their own proposed edits in an opensource model.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The format of this document is a combined adaptation of the blog post by &lt;a href=&quot;https://miguelcarranza.es/&quot;&gt;Miguel Carranza&lt;/a&gt; titled &lt;a href=&quot;https://miguelcarranza.es/working-with-miguel&quot;&gt;Working with Miguel&lt;/a&gt; and the &lt;a href=&quot;https://managerreadme.com/&quot;&gt;Manager README&lt;/a&gt; by &lt;a href=&quot;https://x.com/orenellenbogen&quot;&gt;Oren Ellenbogen&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Who is This Document For?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Members of my team directly reporting to me&lt;/li&gt;
&lt;li&gt;Members of my broader team not directly reporting to me&lt;/li&gt;
&lt;li&gt;My colleagues and coworkers&lt;/li&gt;
&lt;li&gt;Any leader who might want to use this as a reference for their own &amp;quot;Working With Me&amp;quot; document&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;My Mindset and Values&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;I am a very driven and self-motivated professional whose primary passion is people leadership on teams working on software and software-adjacent projects. Nothing brings me more satisfaction than solving hard problems in collaboration with other motivated individuals. I derive more joy from the wins of the members of the team than I do anything directly attributed to myself.&lt;/li&gt;
&lt;li&gt;I try not to let titles or organizational hierarchies get in the way of professional relationships or impede the accurate flow of information and ideas. If I am throwing a title around, it&#39;s probably in service of removing a blocker or defending a position for my team.&lt;/li&gt;
&lt;li&gt;I always enter a new professional relationship with the assumption that you have the best intentions and will put forward your best work and true self. I am an inherently optimistic and trusting person. My trust usually begins as a bucket more than half full. It is easy to fill it up but it is just as easy to drain it. More trust equals more autonomy in our professional relationship.&lt;/li&gt;
&lt;li&gt;I believe that every member of my team should have an intent and responsibility to deliver at the highest level, both for the bottom line of the organization, and the culture of our team.&lt;/li&gt;
&lt;li&gt;I believe in a culture of constant learning, improvement, and innovation. Learning also comes with teaching, and I expect those at a certain level of experience and seniority on my team should be a source of learning for their teammates.&lt;/li&gt;
&lt;li&gt;I believe mistakes are ok and will usually be forgiven unless they are left without follow-up or action to prevent and learn from.&lt;/li&gt;
&lt;li&gt;I do not hold much value in personally being “right”. I would rather be wrong as a step to the right answer or solution. I will always change my mind on something given opposing data.&lt;/li&gt;
&lt;li&gt;I enjoy being surrounded by people that are smarter and more experienced than I. This means I have the most opportunity to learn from my time with them.&lt;/li&gt;
&lt;li&gt;I value giving and receiving immediate honest feedback. I&#39;d rather hear about it or provide it 1 on 1 while the moment is fresh in our mental context than at a later, “designated” time.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;My Role&lt;/h2&gt;
&lt;p&gt;My current role is one that is fully remote with the following focuses:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consistent, predictable, and efficient delivery of business value through software&lt;/li&gt;
&lt;li&gt;Development and organizational alignment with a set of core business strategies&lt;/li&gt;
&lt;li&gt;Support and professional development of my team&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The majority of my work deals with supporting others with their delivery and a minority of my focus is on direct delivery of work products. I am commonly the middleman for the people leaders of individual contributors and senior leadership.&lt;/p&gt;
&lt;h2&gt;How We Will Work Together&lt;/h2&gt;
&lt;p&gt;This section is primarily for those directly reporting to me.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Regular check-ins: I favor near daily interactions, especially with those directly reporting to me and while I&#39;m working fully remotely. I like to keep a weekly cadence of more formal project check-ins with a meeting and corresponding shared artifact we will maintain together.&lt;/li&gt;
&lt;li&gt;1 on 1s: I consider setting up 1 on 1s with my direct reports to be my responsibility so expect those invites to come from me. I aim for weekly, 1 hour meetings. I will generally bring a prepared agenda which I aim to share ahead of time via shared notes (see below). You will generally always have the floor first for your agenda so try to come prepared with what you&#39;d like to discuss. Not every 1 on 1 will strictly be work related and I generally like to maintain an overall balance of serious and casual agendas for these.&lt;/li&gt;
&lt;li&gt;Shared notes and plans: I have a terrible memory due to my tendency to context switch a lot and have to rely on my own personal note-taking system to stay organized. I am a BIG fan of shared notes with direct reports for things like recurring meetings agendas or documenting ongoing, complex work threads. Slack Canvases are my current favorite for this, but I will adapt to whatever system you find most frictionless.&lt;/li&gt;
&lt;li&gt;Communication: I am most comfortable chatting over text DMs. My meeting time is generally fully booked, so outside of regular 1 on 1s, please try to get your comms to be over chat. We can always punch out to a meeting but if you&#39;re asking me “are you free to chat real quick” the answer 95% of the time will be “no.”&lt;/li&gt;
&lt;li&gt;Escalation: for immediate emergencies, favor speed over polish. If you&#39;re not sure if something is an emergency, always assume it is and let me know ASAP&lt;/li&gt;
&lt;li&gt;Team support: I am always open to joining and providing support in group chats, emails, and team meetings. If you invite or copy me, please make it clear if you want input or attendance, else I will assume these are being sent to me as informative FYIs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;My Communication Style&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;I currently work fully remote. I&#39;ve had to be very deliberate about the styles and modes of communications I employ to filter out noise and optimize the time I exchange information with my team.&lt;/li&gt;
&lt;li&gt;Most interactions I have will be over an asynchronous text medium like Slack or email. Get comfortable with typing a lot and clearly communicating via text if you want to keep in touch.&lt;/li&gt;
&lt;li&gt;I like to reserve face to face conversations for agendas that most benefit from them such as 1 on 1s, brainstorming, or complex decision making.&lt;/li&gt;
&lt;li&gt;If you send me a DM, the notification might get lost and I will forget to respond. Please do not hesitate to bump the relevant thread if you&#39;re feeling blocked or stuck due to my non-response. I will always appreciate the reminder.&lt;/li&gt;
&lt;li&gt;If you need to set up dedicated time with me, please consult my calendar availability first. If you&#39;re not able to find a suitable time, feel free to reach out and ask as my days can be back to back. I can usually shuffle things around as needed. Please include an agenda on the invite.&lt;/li&gt;
&lt;li&gt;If you copy me on an email, add me to a group chat, or include me on a meeting invite, please let me know what action you&#39;re expecting from me. If the inclusion is only informative or requires some input, action, or preparation from me.&lt;/li&gt;
&lt;li&gt;I like to think out loud. The basic act of communicating with you usually helps me work through problems and allows me to help you work through them better. The more you talk to me the more I&#39;m going to be thinking about the things that can help you.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Things I Like&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A proactive mindset. I expect that every conversation about a problem should come with some next steps or options.&lt;/li&gt;
&lt;li&gt;Working out in the open. I love to see things that are “work in progress” on the path to a finalized state. You don&#39;t need to come to me with a fully baked plan or even a starting point. This helps you receive early feedback from your team and makes it easy for me to jump in if you need my direct support.&lt;/li&gt;
&lt;li&gt;Concise communication. Get to the point. Tell me what you need or what the point of the conversation we&#39;re having is up front.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Things I do Not Like&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Not doing your homework. My team members must take advantage of all resources available to them ahead of bringing a problem to me. If I could find the information you&#39;re asking for faster than you asking me the question, I will call you out on it.&lt;/li&gt;
&lt;li&gt;Not following up on things that you&#39;ve been asked to do or have understood expectations for delivery. I may ask once for a status on something (see quirks below “I&#39;m a very impatient person”) regardless of your proactivity. If I ask twice, you should ask yourself what you didn&#39;t follow-up on and address it quickly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;My Strengths&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;aka. where I can probably help you the best&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Team recognition: Have a team or individual that went above and beyond or reached a major milestone? Pull me into a standup, have me sign a formal recognition you authored, ask for suggestions for how to tell our people they did a good job and that we appreciate them for it.&lt;/li&gt;
&lt;li&gt;Networking: are you working on a hard problem that requires some cross-functional collaboration? I can help you either find the information, suggest some ways how to find it, or directly connect you with someone who can help.&lt;/li&gt;
&lt;li&gt;Brainstorming: feeling like you&#39;re drowning in ambiguity and don&#39;t know where to start? Schedule some time and let&#39;s just talk through it.&lt;/li&gt;
&lt;li&gt;Being challenged: need something to push yourself out of your comfort zone and accelerate some personal growth? Just say the word. I&#39;m generally thrilled to share something off my plate. But I will expect nothing but top effort on these. Don&#39;t come with this request lightly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;My Quirks and Growth Opportunities&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;aka. where I will probably need your help the most&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;I can be a very verbose and wordy person. If I am ever unnecessarily dominating a conversation or talking around the point, please interrupt  me or call me out on it&lt;/li&gt;
&lt;li&gt;I tend to overcommit myself. Sometimes this impacts only me and I bury myself in obligations outside of what you might need from me. Other times it might directly impact you. Either way, I&#39;d like to hear the feedback if this happens.&lt;/li&gt;
&lt;li&gt;I have a pretty short attention span and am somewhat addicted to context switching. If you need my focused attention on something, it always helps to concisely set the context for me in a conversation and state what you need.&lt;/li&gt;
&lt;li&gt;I tend to be a people-pleaser and favor outcomes where all parties are happy. This can impede me from having direct and difficult conversations where there is a clear “winner” and “loser.”&lt;/li&gt;
&lt;li&gt;I&#39;m a very impatient person. I am always looking for the shortest path to resolution or quickest set of words to the point. If a thought or question pops into my head, I will voice it, sometimes without consideration for your mental context or status simply due to my impatience.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Coding with Copilot - Rewriting My Personal Site Using Generative AI</title>
    <link href="https://sanjaynair.me/blog/2025-05-09-coding-with-copilot/"/>
    <updated>2025-05-09T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2025-05-09-coding-with-copilot/</id>
    <content type="html">&lt;p&gt;This year, with the buzz of GenAI&#39;s burgeoning capabilities as a pair programmer looming large over my industry, I took the opportunity to find out whether the hype was real. I rebuilt my personal website from start to finish with GenAI and augmented coding assistance at the forefront of my approach. You can see the results for yourself (you might be reading this very post on the new site!), but the whole experience was nothing short of eye-opening. I can firmly say I’ve had my &amp;quot;ah-hah&amp;quot; moment with this new category of technology and came out of the experience a believer. I now know Generative AI–assisted software development is the future. Let me explain.&lt;/p&gt;
&lt;h2&gt;Why Rebuild?&lt;/h2&gt;
&lt;p&gt;I&#39;ve had a personal website for many years (again, you might be reading this post on it!). I use it for a few main purposes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Satisfying my need to have a space on the internet that&#39;s mine&lt;/li&gt;
&lt;li&gt;Having a sandbox for tinkering with new tech&lt;/li&gt;
&lt;li&gt;Having a purposeful outlet for keeping my technical skills sharp&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Up until the beginning of 2025, the previous version served the first purpose well, but the remaining two were woefully unaddressed. Specifically related to the third point: due to the increasingly administrative nature of my day job, I hadn&#39;t been able to exercise my web development skills in years. So I used the task of a full rewrite as a way to get back to fulfilling all three goals again.&lt;/p&gt;
&lt;p&gt;As the new year rolled in, I had a few concrete goals for the site:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Move off Gatsby as the frontend framework, since it had started to feel too heavyweight in terms of maintenance for a relatively simple site.&lt;/li&gt;
&lt;li&gt;Migrate my blog posts from Medium, which had previously been my go-to publishing platform—and use this as motivation to revive my writing habit, which had stalled after a decent hot streak about four years ago.
&lt;ul&gt;
&lt;li&gt;I also wanted an RSS feed for the blog that interested readers could subscribe to.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Refresh the layout and styling. Tailwind CSS had been on my radar as a solid and mature option—so I decided to finally give it a go.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I had been meaning to do this for months. But every time I sat down to make progress, I’d get bogged down with errors and obscure issues that killed my momentum and motivation.&lt;/p&gt;
&lt;h2&gt;Setting the Stage: Tools and Stack&lt;/h2&gt;
&lt;p&gt;I discovered the &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;11ty&lt;/a&gt; static site generator after stumbling on another beautifully crafted personal website and blog via &lt;a href=&quot;https://news.ycombinator.com/&quot;&gt;Hacker News&lt;/a&gt; in late 2024. I was immediately impressed by its out-of-the-box simplicity and minimalism—combined with powerful extensibility via plugins and configuration.&lt;/p&gt;
&lt;p&gt;I paired 11ty with &lt;a href=&quot;https://tailwindcss.com/&quot;&gt;Tailwind CSS&lt;/a&gt; as the styling framework and continued hosting via &lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt; on my custom domain.&lt;/p&gt;
&lt;p&gt;Then, of course, there was the question of AI assistance. Like many, I first experimented with ChatGPT in late 2023 when the GenAI boom was just taking off. While it had improved significantly a year later, I quickly grew tired of copy-pasting between my editor and the chat interface.&lt;/p&gt;
&lt;p&gt;Luckily, right as I started the project, GitHub released &lt;a href=&quot;https://github.blog/news-insights/product-news/github-copilot-agent-mode-activated/&quot;&gt;Copilot Agent Mode&lt;/a&gt;, which was already integrated into my long-time IDE of choice: VSCode. With 50 chats included in the free tier, the decision was easy—and I was ready to get started.&lt;/p&gt;
&lt;h2&gt;Laying the Foundation: AI by my side&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Zero to...something, VERY fast&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I was (and still am) building my prompt-writing skills, so I started with something simple that I figured a mature-enough LLM could handle: a scaffolding task. I knew that LLMs generally perform better with upfront context, so I carefully detailed my objectives:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
I&#39;m building a personal website. I&#39;d like to build it using the 11ty static site generation framework and TailwindCSS for styling. It will be statically hosted on GitHub and served via GitHub Pages on a custom domain. The site will mainly be comprised of a homepage with a profile picture, title header, and small mission statement. Under that will be a short list of links. The site will also include a personal blog of posts authored in markdown format. Each post should include tags and a reading time estimate. The style of the site should be minimal, with dark greys and blues as primary colors and orange as the accent color. The font used should be Nebula Sans. Please generate all the necessary files and folders as a starting point for this project based on the specification, along with a list of next steps to build on the starter code, including how to deploy the website.

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The response gave me this structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
my-website/  
├── package.json  
├── .eleventy.js  
├── tailwind.config.js  
├── postcss.config.js  
├── src/  
│ ├── index.njk  
│ ├── blog/  
│ │ └── sample-post.md  
│ └── assets/  
│ ├── css/  
│ │ └── styles.css  
│ └── images/  
│ └── profile.jpg (add your profile picture here)  
└── README.md

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That was the first big &amp;quot;ah-hah&amp;quot; moment. I had a functional starting point in under five minutes. I had previously struggled to get even this basic scaffold set up on my own—mostly due to Tailwind’s finicky integration with 11ty. The model opted for a prior major version of Tailwind, which made the setup smoother—something I hadn&#39;t figured out despite all my Googling and GitHub spelunking. Being able to finally focus on features instead of debugging boilerplate was thrilling.&lt;/p&gt;
&lt;p&gt;I could’ve stopped there and continued coding as usual, but I was determined to see how far the Copilot Agent could go.&lt;/p&gt;
&lt;p&gt;I worked through changing the layout, navigation, and styling, and added features like the &lt;a href=&quot;https://sanjaynair.me/feed.xml&quot;&gt;RSS feed&lt;/a&gt;. From idea to prompt to working code, I saw a surprisingly high success rate. While not perfect, the model was usually able to fix its own errors when I fed it logs or observed behavior.&lt;/p&gt;
&lt;p&gt;Eventually, I had it generate a basic GitHub Actions workflow to deploy to GitHub Pages—and just like that, the new site was live.&lt;/p&gt;
&lt;h2&gt;Where AI Fell Short&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Clear requirements = smooth results. Ambiguity = chaos.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sometimes, the LLM went completely off the rails and broke the codebase so badly I had to stop and roll back everything. The common pattern? &lt;strong&gt;Ambiguous requirements.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If I provided a vague prompt, the model didn’t take the MVP path—it tried to do &lt;em&gt;everything&lt;/em&gt; all at once.&lt;/p&gt;
&lt;p&gt;Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I asked it to “improve the SEO for the site.” The agent went on a spree: rebuilding metadata, changing layouts, making 35+ file edits—none of which I asked for. I had to stop it and revise the prompt with constraints like &amp;quot;only add meta tags&amp;quot; or &amp;quot;do not change layout.&amp;quot;&lt;/li&gt;
&lt;li&gt;I prompted it to add basic functional testing but didn’t specify pages or scenarios. It chose &lt;a href=&quot;https://playwright.dev/&quot;&gt;Playwright&lt;/a&gt;—a great tool—but scaffolded a broken setup and couldn’t fix the errors it caused. I had to guide it through corrections and eventually forced it to stick to the basics.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Unexpected Wins&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Bridging the gap from &amp;quot;this is a cool idea&amp;quot; to &amp;quot;I know it can be coded but I don&#39;t know how&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One of my goals was migrating blog posts from Medium. I started by exporting them as HTML files using Medium’s built-in tool. Then I asked the agent to convert them into Markdown and add them to my new blog.&lt;/p&gt;
&lt;p&gt;The conversion quality dropped as the number of files increased, but unexpectedly, the LLM &lt;strong&gt;generated relevant tags&lt;/strong&gt; for each post—something that didn’t exist in the Medium versions.&lt;/p&gt;
&lt;p&gt;This led to another big win: my site now has a &lt;a href=&quot;https://sanjaynair.me/tags/&quot;&gt;tag cloud&lt;/a&gt;. It visualizes all post tags with sizing based on frequency, and clicking one filters to relevant posts. I was able to clearly articulate the concept and desired templating, and the model generated working code &lt;strong&gt;in a single iteration&lt;/strong&gt;. What would’ve taken hours manually took minutes with GenAI. Easily my second-biggest &amp;quot;ah-hah&amp;quot; moment.&lt;/p&gt;
&lt;h2&gt;Lessons Learned&lt;/h2&gt;
&lt;p&gt;To keep it short and sweet:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can’t move faster from nothing to MVP than with GenAI by your side.&lt;/li&gt;
&lt;li&gt;Be specific. Add constraints. Ambiguity leads to hallucination and runaway iterations.&lt;/li&gt;
&lt;li&gt;The biggest value is when the LLM bridges your mental gap from idea to implementation—&lt;strong&gt;especially when you know what’s possible but not how to code it.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;My experience with GenAI pair programming was transformative. I can’t imagine going back to coding without it. The ability to turn an idea into a working feature in minutes feels like a superpower.&lt;/p&gt;
&lt;p&gt;My to-do list is now full of ideas I’m excited to tackle, because I’m no longer intimidated by how hard something might be to implement.&lt;/p&gt;
&lt;p&gt;To anyone still skeptical: jump in. Start with a problem you care about and give GenAI a chance to amaze you. You might just have your own &amp;quot;ah-hah&amp;quot; moment.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Enjoyed this write-up? Share it with a friend who’s curious about AI tools.”&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  <entry>
    <title>Minecraft DevOps - Foundational Cloud Skills With a Fun Payoff</title>
    <link href="https://sanjaynair.me/blog/2025-06-23-minecraft-devops/"/>
    <updated>2025-06-23T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2025-06-23-minecraft-devops/</id>
    <content type="html">&lt;p&gt;I have been self-hosting a fleet of Minecraft servers on and off since around 2022. Through the process, I&#39;ve been able to build and maintain a broad array of Cloud DevOps skill-sets. I have been leading a portfolio of Cloud Platform Engineering teams for the better part of 3 years. The position of leader didn&#39;t afford me much, if any, time to be hands-on with the core technologies that my team of highly skilled and specialized engineers leverages daily to get their work done. Minecraft and it&#39;s built-in offering to self-host multiplayer servers provided the perfect excuse for me to dump some time and a few bucks into a public Cloud service to host my own multiplayer server for my friends. Through the process of hosting my own Minecraft server, I was able to build decent competence in DevOps skill-sets. I was also able to get back to some of the core software engineering and web development skills to support this gaming hobby for me and my friends.&lt;/p&gt;
&lt;p&gt;I have been playing Minecraft since college. I purchased the game back around 2011, past when the original fan-base had established itself, but well into when it was locked into its mainstream phase. I spent many hours playing with my friends and classmates on the shared server hosted by the university&#39;s Minecraft club without really thinking twice about where or how the server was running. Over a decade later, with a computer science degree and multiple years of working on enterprise technology, I gained the knowledge and experience to tackle the subject right when it was something I was interested in doing outside of work. At the time, I was playing with a few friends on a free, private Minecraft multiplayer server hosted on a website that seemed to be primarily funded via ads. It was clear that the instance we were playing on was running in a shared environment with very few resources allocated per instance. My friends and I eventually got fed up with the limitations of the service and the ensuring hit that the performance issues had on our experience. One of my friends, who happened to get their hands on a retired datacenter server rack, decided to be the first to take the plunge and self-host a server for us.&lt;/p&gt;
&lt;p&gt;Unfortunately, this setup started to show its limitations pretty early. My friend didn&#39;t have the greatest internet connection and we constantly suffered from connectivity issues during our play sessions. He also did not keep the server running continuously due to how loud it was and not having a place to tuck it away at his house. That meant if he wasn&#39;t able to physically access the machine to turn it back on, we were out of luck on being able to play together on our Minecraft world.&lt;/p&gt;
&lt;p&gt;I decided to take it upon myself to create the new and improved iteration of the Minecraft server for us.&lt;/p&gt;
&lt;p&gt;The initial requirements, if you want to call them that, were simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A private Minecraft server accessible by only our friend group&lt;/li&gt;
&lt;li&gt;Enough resources allocated to the server where we could all play on together and grow the world map significantly without causing server performance issues&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I hadn&#39;t had a chance to apply my DevOps skills on AWS up to then, so I decided to select it as my Cloud provider for the project.&lt;/p&gt;
&lt;p&gt;I spun up a modest t2-micro instance and got to work getting the server spun up. I did some initial tinkering to figure out how to get the Minecraft server process working on the VM. From there, I spent a little more time understanding how to create firewall rules that only allowed our specific IPs to access the server. Finally I did some simple systemd configuration to automatically start the Minecraft server on boot. Just like that, I had an MVP Minecraft server up and running on AWS.&lt;/p&gt;
&lt;p&gt;I created a couple of Lambda functions to handle starting and stopping the instances and exposed them via HTTP GET API Gateway endpoints and provided those to my friends.&lt;/p&gt;
&lt;p&gt;With just this MVP setup, I was surprised at the amount of general knowledge I acquired through the process. That, alongside the satisfaction of seeing the direct results of my efforts and being able to enjoy it alongside my friends, was a very fulfilling experience. I was by no means an expert or even moderately proficient at DevOps on AWS, however down the critical path of getting the MVP up and running, I was able to gain basic practical knowledge about&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;EC2 machine types and VM provisioning process&lt;/li&gt;
&lt;li&gt;EC2 Security Groups and firewall configuration&lt;/li&gt;
&lt;li&gt;systemd services&lt;/li&gt;
&lt;li&gt;S3 bucket configuration and integration with EC2&lt;/li&gt;
&lt;li&gt;IAM roles and policy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As we continued to use the hosted server process, I was able to iterate over the offering via ideas I had for how I wanted to improve the experience and requests for new features that my friends asked for. Some of these included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Adding a custom server domain with dynamic DNS that updated the CNAME on boot since, without a reserved IP, the server would have a new IP on each boot. This way, instead of having to connect to a new IP each time, we could set the domain once and let the dynamic DNS handle reconfiguring where it pointed each time we booted the server via a crontab configuration.&lt;/li&gt;
&lt;li&gt;Adding a Cloudwatch alarm that automatically shut the server off if it was running for over a certain number of hours per day to prevent unnecessary cost in the case someone forgot to shut it off after a session&lt;/li&gt;
&lt;li&gt;Adding a Lambda function that would initiate a Minecraft world backup, upload to S3, and make it available to download&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was even able to branch out into my core software engineering and web development skills. I built a simple web portal where server status (running or stopped) could be displayed and controls to start and stop the server were available in a UI interface instead of directing having to hit an API endpoint. I was able to host the site for free using one of many hosting services for which their free tier was most than sufficient for my needs.&lt;/p&gt;
&lt;p&gt;You can see a diagram of what I have working today below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/minecraftdevops.jpg&quot; alt=&quot;Minecraft DevOps Architecture Diagram&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I got the whole architecture implemented in Infrastructure as Code via a combination of Terraform and Ansible scripts. My friends and I liked to spin up new server worlds when a new version of Minecraft was released or if we wanted to experiment with mods. Via automation, I was able to bring the total time of getting a brand new server setup from scratch, fully integrated into our admin portal with all the mentioned automation, down to about 15 minutes.&lt;/p&gt;
&lt;p&gt;I initially considered going down the Kubernetes path for the infrastructure, but in retrospect I&#39;m glad I didn&#39;t. I didn&#39;t want the required maintenance and upkeep of the infrastructure to outweigh the amount of time I could spend actually using it and enjoying it playing Minecraft. This was one of the key objectives of the project that I didn&#39;t know then but I can articulate now. Raw Kubernetes has a high cost of entry and requires decently large efforts to upkeep. More managed solutions weren&#39;t cost effective for my use-case where I was only interested in spending a maximum of a few dozen dollars a month.&lt;/p&gt;
&lt;p&gt;My friends and I don&#39;t play Minecraft nearly as much as we did as our lives all got busy. But I wanted to share a little about the experience I had exercising my Cloud DevOps skills in this little project that was a pretty fun crossover between my professional and personal lives.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>GenAI Augmentation for Technology Leaders</title>
    <link href="https://sanjaynair.me/blog/2025-07-10-genai-for-leaders/"/>
    <updated>2025-07-10T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2025-07-10-genai-for-leaders/</id>
    <content type="html">&lt;p&gt;I constantly encourage my teams to leverage Generative AI (GenAI) in their daily work. It&#39;s a powerful way to offload manual toil, allowing them to focus their mental energy on higher-level creative tasks and shrink the gap between an idea and its realization.&lt;/p&gt;
&lt;p&gt;There are countless GenAI techniques geared toward individual contributors who spend most of their time building, configuring, deploying, or maintaining systems. However, as a leader, my day-to-day looks quite different. I dedicate very little time to individual contribution tasks. The vast majority of my time is spent collaborating, planning, aligning, tracking, and, generally, addressing the challenges faced by the people interacting with technology. This means I need a more novel approach to discovering how GenAI can benefit me and my peers.&lt;/p&gt;
&lt;p&gt;That said, I truly believe in this technology&#39;s transformative potential. I also believe in practicing what I preach. Over the past six months—which is when I truly integrated GenAI into my regular work toolkit—I&#39;ve discovered several use cases particularly well-suited to GenAI augmentation.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I&#39;m excluding scenarios that are now ubiquitous and often built directly into email and video chat software. Examples include rewording emails for conciseness or tone, and automatic meeting transcription and note-taking. While these uses of GenAI are incredibly beneficial, they&#39;re not particularly interesting to discuss at this point.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Reviewing contracts&lt;/h2&gt;
&lt;p&gt;Several times a quarter, I receive contracts outlining work engagements with collaborating partners for my team or project. These documents can range from a few pages of boilerplate text requiring minimal attention to dozens of unique, complex pages. The agreement&#39;s context might also include specific details that, if not highlighted amidst dense paragraphs, could significantly impact the initiative. I have nearly zero legal experience, and while I work with legal partners who can review agreements from a purely fiduciary perspective, only I possess the context necessary to connect the dots to the underlying tactical and financial outcomes. Using a GenAI tool to summarize key points and discuss the agreement in the voice of a legal professional has saved me tremendous time and effort across multiple contract reviews.&lt;/p&gt;
&lt;h2&gt;Team working agreements&lt;/h2&gt;
&lt;p&gt;I believe all engineering teams should maintain a &lt;strong&gt;team working agreement&lt;/strong&gt;. The best way to draft an initial version is to adapt one from a similar team within your organization. If that&#39;s not possible, a GenAI tool is easily the most effective way to generate a solid first draft quickly. When doing so, be sure to provide appropriate context, such as team size, locality (in-person, hybrid, remote, number of time zones, etc.), core working hours, tech stack, planning cadence (yearly, quarterly, etc.), and agile process (Kanban, Scrum, etc.), if applicable.&lt;/p&gt;
&lt;h2&gt;Summarizing weekly team accomplishments&lt;/h2&gt;
&lt;p&gt;Each week, our leadership team must summarize and roll up accomplishments or blockers from the previous week. Witnessing firsthand the improved quality of updates from my leaders who leverage GenAI for this task has been astounding. A key enabler here is the gradual improvement in tools that can connect to engineering backlogs, gleaning insights about completed tasks while integrating context from other sources like team correspondence via email or Slack, and internal documentation. I&#39;ve even received direct feedback that using GenAI for this weekly task highlighted details a leader would have otherwise missed unless they meticulously reviewed every Jira ticket and Slack thread from the past five business days.&lt;/p&gt;
&lt;h2&gt;Authoring BPMs from incidents&lt;/h2&gt;
&lt;p&gt;When systems break and involve numerous people and systems, it can be daunting to reconvene after the dust settles and organize the past chaos into a coherent &lt;strong&gt;Blameless Postmortem&lt;/strong&gt; document. Now that virtually every virtual meeting can be fully transcribed and combined with a Slack channel summary almost instantly, adding context to perform these tasks in the voice of an Incident Manager and generating the output in an enterprise-ready BPM structure becomes trivial. I&#39;ve actually found this technique more useful for incidents I &lt;em&gt;wasn&#39;t&lt;/em&gt; directly involved in. Being on the call and hearing all the context firsthand reduces the augmentation&#39;s boost. However, if I&#39;m on the outside looking in, I can piece together key insights like business impact and &amp;quot;no-repeat&amp;quot; suggestions with a few well-crafted prompts. This is invaluable for systems outside my direct scope of responsibility but perhaps a critical dependency, or even when someone casually asks me what happened with a system that was degraded last week.&lt;/p&gt;
&lt;h2&gt;Codebase analysis&lt;/h2&gt;
&lt;p&gt;While I don&#39;t spend as much time in the code as I used to, as a leader, I&#39;m deeply invested in key aspects of the code my team creates and maintains. I trust my smart team members to uphold proper coding standards, but in some cases, I use GenAI tools as a forensic aid to understand where code content might be contributing to unwanted friction or negatively impacting key outcomes for my teams. There&#39;s no shortage of static code analysis tools that already do this effectively. However, similar to my example of contract analysis, the real novelty of using GenAI here is its conversational interface. Instead of simply viewing a static code analysis &lt;em&gt;report&lt;/em&gt; that assigns a one-dimensional letter grade to codebase &amp;quot;quality,&amp;quot; I can &lt;strong&gt;have a conversation about the codebase&lt;/strong&gt;. I can inquire about the multifaceted elements that contribute to its overall quality from the perspective of where I observe or hear friction within the broader human and technology systems.&lt;/p&gt;
&lt;h2&gt;Prototyping&lt;/h2&gt;
&lt;p&gt;This might be the use case most likely to be scoffed at by senior engineers. For those who are immersed in code daily, I understand that the gap between an idea and working code is far smaller than it is for a leader who only gets to write a few lines of code in their free time a couple of times a month. To that senior engineer, I say: I&#39;ve been there and completely understand. But now, with my coding reflexes dulled over multiple years outside individual contribution, there&#39;s nothing more satisfying than translating an idea I conceptually &lt;em&gt;know&lt;/em&gt; how to code into a working prototype in a few minutes instead of a few frustrating hours. I most commonly use rapid prototyping when explaining a design concept; rather than whiteboarding it, I can quickly whip up a low-fidelity working version in about the same amount of time.&lt;/p&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;I might do a second edition of this &amp;quot;use-case log&amp;quot; in another six months, as further experimentation yields additional valuable scenarios from the engineering leader&#39;s perspective. Please engage if you&#39;re interested.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  <entry>
    <title>My Professional Productivity System</title>
    <link href="https://sanjaynair.me/blog/2025-08-14-professional-productivity-system/"/>
    <updated>2025-08-14T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2025-08-14-professional-productivity-system/</id>
    <content type="html">&lt;p&gt;I&#39;ve spent the better part of the past decade as a technology professional, moving up and across multiple roles of software engineering and leadership. Through the years, I&#39;ve built up and refined a personal set of organizational tools and processes that I feel has grown with me through my career and continues to drive consistent, positive outcomes for me.&lt;/p&gt;
&lt;h2&gt;Core Strategies&lt;/h2&gt;
&lt;p&gt;My professional organizational system is founded in a few core tools that are used in specific processes for highly targeted objectives.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Low friction in and out of the system (i.e add an item to the todo and identify what to do next)&lt;/li&gt;
&lt;li&gt;Quick setup and zero maintenance&lt;/li&gt;
&lt;li&gt;Maximizing delegation of mental load&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These objectives weren&#39;t something I started the process with, rather they naturally emerged as I built my processes around the core things I found necessary to be successful and scale my productivity as my scope of responsibility grew.&lt;/p&gt;
&lt;h2&gt;Tools&lt;/h2&gt;
&lt;p&gt;The shortlist of tools and processes that I will expand on below goes as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TODO List&lt;/strong&gt; that is synced across all devices with low friction in and out and basic additions like scheduled task recurrence and &amp;quot;follow-up&amp;quot; statuses&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Email flagging&lt;/strong&gt; for follow-up action&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Slack chat&lt;/strong&gt; reminders and TODO list integration&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Written Notes&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visual Notes&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Calendar&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;TODO List&lt;/h3&gt;
&lt;p&gt;Let&#39;s start with the backbone of my productivity system. If it&#39;s not on the todo list, there&#39;s no guarantee it&#39;s getting done. I&#39;ve managed to build a pretty strong habit of putting things into my todo list the moment a task becomes my responsibility, no matter how insignificant or quick I feel it might be. If you&#39;re ever having a conversation with me and an action item hits my plate, it&#39;s very common for me to pause and vocalize as I add an item to my todo list before continuing the conversation. The top priority &amp;quot;features&amp;quot; of my todo list include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quick accessibility to the task inbox anywhere anytime so I can document tasks as they come to me in a single action (Alt-tab to another window and hotkey press or two taps on my phone)&lt;/li&gt;
&lt;li&gt;Automatic syncing across all my commonly used devices (primarily my work laptop and personal phone)&lt;/li&gt;
&lt;li&gt;Option to add notes and subtasks on entries (sometimes the task needs additional context to effectively recall and act on)&lt;/li&gt;
&lt;li&gt;Option to mark a task as needing a &amp;quot;follow-up&amp;quot; and filter on those tasks (In the case that I&#39;m waiting on a dependency or delegated it to someone else but am still accountable for it)&lt;/li&gt;
&lt;li&gt;Ability to have tasks that repeat, on a weekly or monthly basis&lt;/li&gt;
&lt;li&gt;Ability to set priority order and deadlines for tasks&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Email&lt;/h3&gt;
&lt;p&gt;Moving on to what some might consider the necessary evil that I&#39;ve had to wrangle into my process. While many organizations might have shirked off email as a primary means of asynchronous communication, it remains a core necessity for smooth cross functional communication for my work. The volume of emails I receive daily has increased linearly with my scope of responsibility while the percentage of emails I actually need to spend focused time on reading or responding to has steadily shrunk. I&#39;m also a stickler of maintaining my inbox at zero unreads. This leaves me in a scenario where I&#39;m able to scan through my unread emails in a fairly short amount of time but I need to set aside a small subset of emails for later action.&lt;/p&gt;
&lt;p&gt;I leverage the &lt;a href=&quot;https://support.microsoft.com/en-us/office/flag-email-messages-for-follow-up-9d0f175f-f3e9-406d-bbf7-9c57e1f781cc&quot;&gt;&amp;quot;flag email&amp;quot;&lt;/a&gt; function as a way to mark these emails that I have read and identified as requiring a follow-up of some kind. Filtering on these marked emails presents me with another neatly organized todo list of sorts where the default order of priority is in reverse chronological order. I typically don&#39;t let this list of flagged emails grow to more than a handful of entries and generally I like to close out actions for flagged emails within the same work week.&lt;/p&gt;
&lt;h3&gt;Slack&lt;/h3&gt;
&lt;p&gt;Working remotely, a majority of my communications and related organization happens via my primary, asynchronous chat software: Slack. Luckily for me, there is a growing suite of productivity tools that integrate easily within Slack. I find myself spending more time in the software and looking for every opportunity to consolidate another one of my productivity tools into it. This, like email and my calendar, is primarily driven by the network effect that most of my coworkers are also on Slack.&lt;/p&gt;
&lt;p&gt;Like my email inbox, I aim to have zero unread messages in Slack to a fault. This necessitates a couple of techniques to ensure that something I read that requires an action doesn&#39;t get forgotten. First and simplest is the &lt;a href=&quot;https://slack.com/help/articles/208423427-Set-a-reminder#h_01J8FMHE6ASNXBQ189T8DMF602&quot;&gt;Reminder&lt;/a&gt;. I most commonly will use the &amp;quot;remind me in 3 hours&amp;quot; feature if I can&#39;t get to a reply immediately but expect I could later that day. If someone can wait till tomorrow or the following week, I set the reminder with the conveniently available options accordingly. In the case that I need to review all the items I&#39;ve set reminders for, I just go to the &amp;quot;Later&amp;quot; tab in my Slack sidebar as another list of todos to review as needed. For scenarios where the follow-up action might be more complex or take more focused time, I use the &amp;quot;Send to List&amp;quot; feature where the list in question is my TODO list mentioned above.&lt;/p&gt;
&lt;h3&gt;Written Notes&lt;/h3&gt;
&lt;p&gt;My private written notes are, for the most part, a minimally organized spread of markdown documents that I author and index via my current note-taking app of choice: &lt;a href=&quot;https://obsidian.md/&quot;&gt;Obsidian&lt;/a&gt; (coincidentally it is where I&#39;m writing this post, as it is also my primary tool for digital writing).&lt;/p&gt;
&lt;p&gt;This is the part of my productivity system that I&#39;ve spent the least amount of time refining since its usually where I spend the least amount of time focusing or referring back to during my work week. This might be a side-effect of my working style being relatively shallow in its day-to-day cadence, focused mainly on information and decision making I&#39;m able to manage mentally or via delegation. Yet without the repository of critical information available for quick additions and recall, there would be a significant gap in my overall system and would add enough mental overhead to cause other parts of my system to begin to fall short.&lt;/p&gt;
&lt;p&gt;Most of my notes live at the root level of my Obsidian vault. There are only a few top-level folders I use with no secondary level of organization to any of them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 on 1s: A single note per individual I have recurring 1 on 1s with. These get used most with my direct reports and reporting manager, with whom I meet at least once a week&lt;/li&gt;
&lt;li&gt;Weekly status updates: dated entries with aggregated and summarized updates from all the teams and projects I manage&lt;/li&gt;
&lt;li&gt;Recurring meeting agendas: for tracking topics of discussion for meetings I have on a weekly or monthly cadence&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For public note taking, I have been increasing my use of &lt;a href=&quot;https://slack.com/features/canvas&quot;&gt;Slack Canvases&lt;/a&gt; for written documents that serve a more collaborate purpose. It similarly supports native markdown syntax and integrates seamlessly with the rest of the Slack ecosystem of features. The lack of any sort of hierarchy or grouping function hints at the limited scalability of this feature over long periods of time. I am weary that the process of exporting notes out of a set of Canvases will probably be frictionful, so I try to keep evergreen notes that I expect to refer back to in the long term in Obsidian and isolate Slack Canvas notes to only those who&#39;s purpose is primarily for sharing and asynchronous collaboration.&lt;/p&gt;
&lt;h3&gt;Visual Notes&lt;/h3&gt;
&lt;p&gt;In some cases, visual notetaking is a better fit for the topic I&#39;m trying to articulate for myself or share with others. I&#39;m a big proponent of the &amp;quot;boxes and arrows&amp;quot; method to translate a concept that is best captured visually rather than in spoken or written words.&lt;/p&gt;
&lt;p&gt;I maintain a single &amp;quot;public whiteboard canvas&amp;quot; in &lt;a href=&quot;https://miro.com/&quot;&gt;Miro&lt;/a&gt; split up into multiple, independent, simply-titled &lt;a href=&quot;https://help.miro.com/hc/en-us/articles/360018261813-Frames&quot;&gt;Frames&lt;/a&gt; where the content of each frame is analogous to a moment where I might have grabbed a marker and scribbled an aforementioned set of boxes and arrows on a whiteboard. The main difference and sometimes advantage of this exercise happening in an easily sharable and digitized space first is that I don&#39;t have to worry about taking a poorly lit smartphone picture of the whiteboard at the conclusion of the discussion where the only shareable artifact is the photo, then copied and pasted ad-hoc when needing to be recalled.&lt;/p&gt;
&lt;p&gt;I also have a private version of this infinite canvas where I can do similar exercises but for scenarios where the topic might be private only to me or sharable to a select set of individuals.&lt;/p&gt;
&lt;p&gt;I&#39;m trying to find a method to effectively index all of these individual whiteboard frames and bring them into the quickly searchable context of my other written notes which I can already fuzzy search through via Obsidian&#39;s command pallet in a few keystrokes. I&#39;m aware of Obsidian&#39;s &lt;a href=&quot;https://obsidian.md/canvas&quot;&gt;Canvas&lt;/a&gt; feature which might serve the purpose but I need to explore further to determine how the use case of sharing with coworkers would work.&lt;/p&gt;
&lt;h3&gt;Calendar&lt;/h3&gt;
&lt;p&gt;My calendar is primarily used to determine when my time is occupied with meetings as an opposite tool to my todo list. My days are generally organized into either &amp;quot;meeting time&amp;quot; or &amp;quot;task time&amp;quot; which I further subdivide into periods of long focused work, short task time, or breaks depending how my day or week is playing out. I haven&#39;t found much value in scheduling my day further than with respect to the time that I explicitly need to coordinate a meeting with one or more other people, most commonly my coworkers.&lt;/p&gt;
&lt;p&gt;If I&#39;m scheduling meeting time with my coworkers, which is the majority of my scheduled meeting time, then it falls to my trusty Outlook calendar, which I&#39;ve used for years for no other reason than it&#39;s what my coworkers are using. If the meeting time has something to do with my personal life, then I&#39;m reaching for my Google calendar.&lt;/p&gt;
&lt;p&gt;The day is usually peppered with enough unexpected interruptions or meetings that extend past scheduled time to where this ability to flex the rough edges of the schedule naturally became one of the things I needed the other parts of my process to accommodate for. If I have a block of time that isn&#39;t for a meeting, I can simply switch over to one of my todo lists and pick off whatever task is highest priority that I judge I can complete or make significant progress in the time I have. If nothing jumps out from the todo list or my brain is simply indicating that this time would be better spent &lt;em&gt;not&lt;/em&gt; doing anything specifically productive, then its time for a break.&lt;/p&gt;
&lt;h2&gt;What&#39;s Next&lt;/h2&gt;
&lt;p&gt;I&#39;ve become comfortable with the reality that everything I&#39;ve mentioned above is far from some &amp;quot;ultimate&amp;quot; productivity system I&#39;d see myself using for the rest of my career and life. This is a snapshot of what is working for me today, and with it I have a few things I would still like to make a bit smoother in my process to serve my core objectives.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(As mentioned above) Indexing and cataloging my visual notes so they are easily searchable in a single context along with my other written notes&lt;/li&gt;
&lt;li&gt;Moving my todo list into a native text-based format with basic automation to support the critical integrations and features critical to my process integration (&lt;a href=&quot;https://www.al3rez.com/todo-txt-journey&quot;&gt;todo.txt&lt;/a&gt; is an interesting foundation for this idea)&lt;/li&gt;
&lt;li&gt;Bringing my private and public written notes into a single system without sacrificing the outcomes of frictionless collaboration and continued easy indexing&lt;/li&gt;
&lt;li&gt;Explore ways to integrate LLMs into the corpus of all these tools and begin to create more advanced automations to continue to offload menial mental load to the system and free up brain space for higher order thinking&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>&#39;Isms - Tidbits of Wisdom I keep Returning To</title>
    <link href="https://sanjaynair.me/blog/2025-09-23-titbits-of-wisdom-1/"/>
    <updated>2025-09-23T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2025-09-23-titbits-of-wisdom-1/</id>
    <content type="html">&lt;p&gt;I spend lots of time speaking with friends and other technology professionals about a wide variety of topics from career advice, technology hype cycles, how to lead people, and finding success in our personal endeavors. Over hundreds of these discussions, I find myself returning to some of the same tidbits of wisdom that I reference with a short phrase or label. These ideas have been passed down to me or created from bits of my learnings and experience and synthesized into a concise concept in my own words. I don&#39;t claim to be the first person to have come up with these concepts, and I won&#39;t be the last, but I have personally gleaned a lot of value in internalizing them and continue to find opportunities to share them with others in casual discussion or mentoring contexts. This post is my attempt to document these tidbits of wisdom in an easily shareable format. I hope that you might read something here that resonates with your experiences, or some of that wisdom might be passed on to you.&lt;/p&gt;
&lt;h2&gt;They Have to Feel the Burn Themselves&lt;/h2&gt;
&lt;p&gt;We&#39;ve all likely experienced something that caused such an acute sense of fear and stress that our primal survival instincts forces us into behaviors that do everything to try and prevent that scenario from occurring again. In professional life, those events might seem mundane and are nowhere near the life threatening perils humans evolved to protect against. But the power of fear and stress as a learning tool sometimes cannot be outmatched.&lt;/p&gt;
&lt;p&gt;The most common context I return back to this phrase for usually revolves around technology professionals not having the proper appreciation for the discipline required to run production systems that have wide and significant impacts. That could be understanding why proper testing of new features or components is by far a better use of time and energy compared to debugging under the stress of production impact. Its the difference in understanding why its not ok to leave the issue alone till tomorrow and risk irreparable harm to your product brand instead of hunkering down and grinding through till it&#39;s fixed now.&lt;/p&gt;
&lt;p&gt;The people I speak with that are frustrated when others don&#39;t share their urgent perspective on an imminent bad scenario are usually also those who have been on the receiving end of that burn. They remember the fear and stress and want nothing more than to avoid for themselves and their peers. I do believe there&#39;s merit in trying to teach via anecdote rather than resolving to throw newbies into the deep end to let them sink or swim. Unfortunately, sometimes they have to feel the burn themselves to truly understand and internalize the lesson.&lt;/p&gt;
&lt;h2&gt;The Career Identity Crisis&lt;/h2&gt;
&lt;p&gt;The &amp;quot;career identity crisis&amp;quot; is the point at which one must decide to pursue a path deeper into their chosen discipline or fork into an adjacent one to make forward or upward progress. In my chosen career path when I had the title of Staff Software Engineer, the decision was one of Principal Engineer, which demanded further specialization into software and systems engineering, or Engineering Manager, which took a path focused on leading technology teams. This fork in career path could be extended to any industry that separates the roles grouped into what might be labeled &amp;quot;individual contributor&amp;quot; from those of &amp;quot;middle management&amp;quot; and above.&lt;/p&gt;
&lt;p&gt;I received advice early in my career that it didn&#39;t serve my interests to simply accept that I would enjoy and find success in either role. A trusted mentor advised that I needed to form an opinion on which one to specifically pursue, and by extension which to &lt;em&gt;not&lt;/em&gt; pursue. In fact, they made it clear that I &lt;em&gt;had&lt;/em&gt; to pick. Without deciding, those supporting my career growth would not know how to provide me with corresponding opportunities for each respective discipline. I experienced a sort of identity crisis grappling with this decision. Fortunately, I came out of the dilemma resolved and very happy with my decision. My personal experience helped me form this piece of wisdom that I&#39;ve been able to recognize in others and share with them.&lt;/p&gt;
&lt;p&gt;For those that at this fork in the road, I give the same advice I received myself. You &lt;em&gt;have&lt;/em&gt; to decide. For the leaders that are responsible for growing those individuals into these respective roles, I encourage them to take advantage of the reality of the situation. Be plain about the need to decide, but curate distinctly different opportunities aligned with the different paths past the fork and label them as such. Make it clear which &amp;quot;type&amp;quot; of project or challenge you&#39;re offering and encourage the individual to be open to enjoying or not liking the experience. For example, I would give a staff engineer unsure of moving up to a Manager or Principal role different projects that I label as more &amp;quot;Managery&amp;quot; or &amp;quot;Principaly&amp;quot;. A &amp;quot;Managery&amp;quot; task might be coming up with a career growth plan for a junior engineer or helping mediate an interpersonal conflict. A &amp;quot;Principaly&amp;quot; task might be designing and getting architectural approval for a new system design or integration of a new technology into a product. Let the varied opportunities inform their opinion and your curated labeling determine which path yields the best fit for them. Embrace the fork in the road knowing you can take a tour down each path before committing to the route.&lt;/p&gt;
&lt;h2&gt;Recognition has an expiration date&lt;/h2&gt;
&lt;p&gt;Showing gratitude feels like a cheat code for people leaders. It doesn&#39;t cost anything, and if done correctly it might be the most effective way to motivate and bring forth happiness. Regardless of the form of gratitude, whether a simple &amp;quot;Thank you&amp;quot; and &amp;quot;good job&amp;quot;, or something formal like the presentation of an award, I&#39;ve found that the magnitude of effect is directly proportional to the length of time between the act and recognition. A simple &amp;quot;thank you&amp;quot; right after the action generally has a stronger impact that any gesture after enough time has passed. As time progresses, the memory starts to fade, many other events begin to supersede the original, and a sense of the gratitude starts to seem like a lazy afterthought. However, I also believe that &amp;quot;better late than never&amp;quot; is a valid perspective on this scenario as well.&lt;/p&gt;
&lt;p&gt;Take both extremes into consideration: let the urgency of the impending expiration date prompt you to action, but don&#39;t use it as a reason to give up even if you feel like too much time has passed.&lt;/p&gt;
&lt;h2&gt;Starting with a ball of clay&lt;/h2&gt;
&lt;p&gt;My style of working on complex problems is like how I approach writing: I slap down a simple draft as quickly as possible and do multiple iterative revisions until the quality of work is satisfactory. The emergence of Generative AI tools and their ability to play the role of brainstorming or thought partnership is how this &#39;ism formed. GenAI is extremely good at authoring a first draft from a rough concept. I compare the result to slapping an unformed ball of clay onto the pottery wheel. It is nowhere near a finished product. In fact it is barely on the first step to being one. But sometimes getting the first draft down can feel like the most difficult part of the process. Once you have it in front of you as a boost to your mental momentum, you can rest assured that somewhere inside the unformed and unremarkable material, the finished product does exist. The thing bridging the gap is the human process of removing, adding, shaping, forming, and detailing it.&lt;/p&gt;
&lt;p&gt;You might flip the analogy in the other direction and compare knowledge work as an additive process, where a small kernel is added on to and progressively built up into the final product. Either way, I use this &#39;ism as a way to encourage people to not be intimidated by the idea of perfection and just get started. Use the tools at your disposal to get that ball of clay in front of you as fast as possible, &lt;em&gt;then&lt;/em&gt; spend most of your time and energy sculpting it into the final product.&lt;/p&gt;
&lt;h2&gt;Pressure release&lt;/h2&gt;
&lt;p&gt;The work I engage in most commonly in my day-to-day is a constant battle of priorities and context switching. I have to decide, up to multiple times within a single hour, what is the most valuable task is to put mental energy into. Moreover, my personal priorities are not always perfectly aligned with those of my peers, stakeholders, team, and leadership. Commonly, I feel a lingering sense that a specific thread I am accountable for is building in pressure, whether external or internal, and usually driven by a sense of ambiguity, perception of being stalled, or general lack of confidence. Irrespective of where this topic sits in priority or how complex the task is, the longer that the core issue is left unaddressed, the larger it seems to loom over everything else.&lt;/p&gt;
&lt;p&gt;I use the analogy of a pressure vessel that requires a release, for no other reason than to remove the background anxiety of its existence and increasing danger of the inevitable explosion. Venting just a bit of steam from the chamber gives mental space for other things, even if the action was largely symbolic. Sometimes it&#39;s worth it in the short team to release some pressure for the sake of the bigger picture.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If any of these tidbits of wisdom resonate with you, I&#39;d love to hear about it from you. If I gather enough new ones, I&#39;ll consider authoring a &amp;quot;part 2&amp;quot;.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  <entry>
    <title>Coding with Copilot Part 2 - Agent Edition</title>
    <link href="https://sanjaynair.me/blog/2025-10-28-coding-with-copilot-pt2/"/>
    <updated>2025-10-28T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2025-10-28-coding-with-copilot-pt2/</id>
    <content type="html">&lt;p&gt;I recently read a &lt;a href=&quot;https://ben.page/claude-code-web&quot;&gt;blog post&lt;/a&gt; lauding the experience of using &lt;a href=&quot;https://claude.ai/code&quot;&gt;Claude Code for Web&lt;/a&gt;. Specifically there was quote in the post that goes as follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I’ve been using it as a “to-do list that does itself” — when I think of something small that I want to tweak, across a variety of projects (work, work-related side project, side project, open source project) I just throw it into a thread. Then I come back, sometimes later in the day and sometimes days later, to see what Claude did and to finish things up.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I read this and thought &amp;quot;This is EXACTLY how I use AI for coding today&amp;quot; and it prompted me to start this post.  In this post, I&#39;ll share how coding agents have fundamentally changed not just my productivity, but my entire approach to personal project management. Consider this a follow-up to my previous post, outlining my current workflow for getting the most out of the latest and greatest AI tools available for software engineering.&lt;/p&gt;
&lt;p&gt;It&#39;s been almost 6 months since I started practicing AI-assisted coding and &lt;a href=&quot;https://sanjaynair.me/blog/2025-05-09-coding-with-copilot/&quot;&gt;wrote about my very positive experience with it&lt;/a&gt;. At the time I had just started with a basic setup including Github Copilot in VSCode with Claude Sonnet 3.5 as the driving model.&lt;/p&gt;
&lt;p&gt;Using Github Copilot alongside my standard setup in VSCode to work on coding projects (primarily this website) was a significant jump in my overall productivity and ability to deliver working software via augmentation. However, it didn&#39;t fundamentally change the overall workflow or cadence of how I came up with ideas, tracked them, worked on them, and eventually (maybe) shipped a finished version of them. Having AI in the passenger seat chopped the time to work on and ship the feature, however there were plenty of times that an idea just languished on my &amp;quot;coding projects todo list&amp;quot; until I got even 30 minutes to sit and focus on a coding session.&lt;/p&gt;
&lt;p&gt;Enter coding agents. My first exposure to this paradigm came when Jules was modestly &lt;a href=&quot;https://blog.google/technology/google-labs/jules/&quot;&gt;announced&lt;/a&gt; at Google IO 2025. I&#39;m not deeply familiar with the history of &amp;quot;who came first&amp;quot;, as far as I know Google Labs was the first to ship an asynchronous coding agent as a free, albeit &amp;quot;experimental,&amp;quot; product. The user experience was incredibly simple and in a few clicks I had the agent hooked up the repo for my personal website and I was off to sending it prompts to work on for me.&lt;/p&gt;
&lt;p&gt;After a few sessions with it, I could confidently say it worked 100% of the time...about 80% of the time. But I&#39;m more than satisfied with that kind of hit rate on translating a few lines of plain English into working code. From there I threw it a few random tasks that I otherwise would have just thrown to Copilot but was simple enough to open up a browser, submit the prompt, and move on to something else without having to keep an editor open or monitor the agent&#39;s coding progress.&lt;/p&gt;
&lt;p&gt;After a few months of light usage was when the paradigm shift happened. I thought up a new enhancement I&#39;d like to have added to the site. I reflectively reached for my todo list to add it, but paused when I realized I could just pull up Jules in my browser and send it the todo instead. And so I did.  I typed out my todo item in a few sentences, clicked submit, and watched Jules spin up and get to work. Suddenly , I felt like I was leveled up. I had just created a &amp;quot;todo list and does itself&amp;quot;.&lt;/p&gt;
&lt;p&gt;The next &amp;quot;ah-hah&amp;quot; moment happened after I received this lovely email from Mozilla about the sunsetting of Pocket.&lt;br /&gt;
&lt;img src=&quot;https://sanjaynair.me/assets/images/pocketretirementemail.png&quot; alt=&quot;Pocket retirement email&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I used Pocket to bookmark links to interesting things I found online and built a Github Actions-based integration that hooked into the pocket API and populated the Daily Reads section of my website homepage with links I specifically tagged to share. With pocket going away in the next few months, I had the task ahead of me to quickly find an alternative else some core website functionality would break.&lt;/p&gt;
&lt;p&gt;So I gave it to my self-doing todo list: Jules. I started with the following prompt&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Propose 3 plans to convert the pocket integration to other services that can be used to save and retrieve links via an api to populate the latest reads section&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After some research and consideration via some other AI tools, including chats with ChatGPT and Gemini, I landed on Raindrop as my choice for replacement. And so I instructed Jules in the same task context (yes I included the typo from the original prompt I sent on purpose):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;make the code changes to covert the site features that rely on pocket to raindrop io as outlined&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Jules did it on the first try, nearly flawlessly. A full refactor to a completely new bookmark manager system and API integration, seamlessly swapped into my existing Github Actions integrations with the only real update I had to make was swapping out an API key. You can see the full Pull Request &lt;a href=&quot;https://github.com/Nirespire/nirespire.github.io-2025/pull/11&quot;&gt;here&lt;/a&gt;. In total, Jules edited 8 files with around 100 lines updated. Unlike most other PRs opened by Jules, this one required zero fixes or additional edits after my review. This will probably remain the example that cemented my optimism for this being the next step in how AI will continue to change the game for Software Engineers.&lt;/p&gt;
&lt;p&gt;Since then I&#39;ve tried other hosted agentic coding products like &lt;a href=&quot;https://openai.com/index/openai-codex/&quot;&gt;Open AI&#39;s Codex&lt;/a&gt; and the recently released &lt;a href=&quot;https://www.anthropic.com/news/claude-code-on-the-web&quot;&gt;Claude Code for Web&lt;/a&gt;. Even though I find Claude&#39;s models to be the best at coding via Github Copilot or Claude Code, nothing I&#39;ve used has matched the level of polish, quality, and accuracy that Jules has achieved for me thus far. I&#39;m far from a power user, clocking maybe 1 or 2 hours of coding time a week, but from my experience its usually the product that can get it right quick and early that ends up holding its own.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/meandmyagents.png&quot; alt=&quot;Me and my agents&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As with most things, its not all rainbows and sunshine. As I mentioned, Jules gets it right about 80% of the time on good days. Even then, most PRs it opens requires at least a couple of passes of reviews from me and usually some final polish and tweaks via a local coding session with Copilot. In some cases the feature is simply too complex for Jules to handle and it will ship a completely broken PR that I end up just trashing and starting from scratch. Even with these pitfalls, my overall productivity is up another 2x. Tasks that would have taken 2 hours with no AI, went down to less than 1 hour with Copilot, and have in some cases gone down to minutes with Jules. My trusty todo list has literally been outclassed.&lt;/p&gt;
&lt;p&gt;As I continue dabbling in these tools on weekends and free evenings, I&#39;m looking forward to the next paradigm shift that is inevitably on the way that will let me do even more with less.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>My System to Keep a Reading Habit</title>
    <link href="https://sanjaynair.me/blog/2025-11-30-reading-system/"/>
    <updated>2025-11-30T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2025-11-30-reading-system/</id>
    <content type="html">&lt;p&gt;I get asked how I stay informed as a technology professional when the industry seems to be moving faster than it ever has and the demands of staying informed to keep up have never been higher. In this post, I&#39;ll summarize what works for me so that it might inform you if you&#39;re curious and supplement your practice if you&#39;re looking to get better at it.&lt;/p&gt;
&lt;p&gt;Reading is how I like to stay informed about the world as well as a hobby that gives me an opportunity to intermittently distance myself from my mostly digitally-driven life. At the time of writing, I&#39;m one day away from a 365-day streak of reading at least one page of some kind of content every single day and &lt;a href=&quot;https://www.goodreads.com/Nirespire&quot;&gt;I&#39;ve read 40 books this year so far&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Reading for Information and Education&lt;/h2&gt;
&lt;p&gt;Here&#39;s the system I use to stay informed for targeted professional purposes. This section could also be considered the more &amp;quot;official&amp;quot; or &amp;quot;formal&amp;quot; side of my reading habit. I consider reading about topics related to my job and current world events to be enjoyable, however they&#39;re not a fully recreational set of activities or topics and lean practically towards my overall growth and development as a professional.&lt;/p&gt;
&lt;p&gt;Below is the bookmarks folder I simply label as &amp;quot;Daily Reads&amp;quot;. I (try to) go through these links daily or weekly depending on the publishing schedule.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/readinglistbookmarks.png&quot; alt=&quot;Reading List Bookmarks&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://news.ycombinator.com/&quot;&gt;Hacker News&lt;/a&gt; (daily) - HN is well known in the tech community as a sort of &amp;quot;front page&amp;quot; for the industry. It has a frontpage algorithm driven by reader engagement on posted links where the active userbase is strongly populated with the who&#39;s who of the tech and startup communities. This one has been at the top of my list for years and has consistently delivered a surprisingly diverse set of content not just focused on technology startups. The dialogue in the comments can skew a bit on the &amp;quot;snobby&amp;quot; side, I&#39;ll say—however the equally high intellectual and contextual rigor given to the conversation is pretty unique for internet forums at large. I&#39;ve consistently seen popular links posted here on a particular day being ported to other publications a day or two later.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://tldr.tech/&quot;&gt;TLDR Newsletter&lt;/a&gt; (weekdays) - This one was pushed to me via targeted advertising on social media. I think of it as my &amp;quot;Hacker News supplement&amp;quot;. The content is primarily tech focused and I can usually find at least one link that I already saw the previous day on Hacker News. But all in all, there have been at least one or two unique finds worth reading each day here to keep it on my daily reading rotation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://news.kagi.com/&quot;&gt;Kagi News&lt;/a&gt; (daily) - This is my break out of just reading about technology every day. There&#39;s a lot going on in the world each day and if I&#39;d like to consider myself informed in a balanced way, I reached for a more comprehensive news source. I landed on Kagi News (then named Kite News) after rotating through the more &amp;quot;traditional&amp;quot; news publications including The New York Times, The Wall Street Journal, and other rising internet news publications including Ground News. The fact is, I am still experimenting here. I&#39;m still trying to settle on a news source that I personally feel finds a healthy balance between reporting on the sensational mainstream, USA-centric news while including the underrepresented but equally important global news.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://softwareleadweekly.com/&quot;&gt;Software Lead Weekly&lt;/a&gt; (weekly on Fridays) - Rounding out the bunch is the focused curation into content centered around leadership and, more specifically, leadership in software and technology. Oren has built what I think is a valuable resource for technology leaders and consistently curates quality reading content from which I always glean something that helps me in my job and even my life (The progressive webapp version of the website is also really well done).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The list is driven by a few core objectives/strategies that inform what I&#39;m trying to get out of the content:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The amount of total daily content should be easily read through, at least at a top level, in around 30 minutes. That would include deep reads of one to two links per source. The list could change and grow but generally if I&#39;m having to read through more than five sources, my habit is probably going to fall off.&lt;/li&gt;
&lt;li&gt;The content should inform me about my top 3 interests: current events, technology, and leadership. I&#39;d like to receive these topics in a balanced way such that I&#39;m not tunnel-visioned into just the topics that interest me but rather all those that give me the best, most informative perspective.&lt;/li&gt;
&lt;li&gt;The content should be accessible in a deliberate way and not just pushed to me via an algorithm that prioritizes engagement over everything. If I&#39;m not making some deliberate decision on what content I&#39;m consuming, when, and how, it means that I&#39;m delegating my outcome of being informed to something whose objectives are not aligned to my own.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Reading for Fun&lt;/h2&gt;
&lt;p&gt;This part of my reading habit has no objective to be directly practical or beneficial towards my growth as a professional. I reserve my reading list of novels, short stories, and other literature purely for things I want to read or that I find interesting or fun. Generally, I&#39;ll end up finding some learning or indirect benefit from these activities, but my going-in stance is pure indulgence and recreation.&lt;/p&gt;
&lt;p&gt;My consistent reading habit and respectable number of completed novels this year has been enabled by a few strategies I&#39;ve developed over just this year:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Always give myself multiple choices of what book I could be reading at any given time&lt;/li&gt;
&lt;li&gt;Take advantage of all formats of books available to me (physical, e-book, audiobook)&lt;/li&gt;
&lt;li&gt;Have easily accessible options on my phone as an alternative activity to scrolling a dopamine drip algorithmic feed&lt;/li&gt;
&lt;li&gt;Give myself permission to &lt;a href=&quot;https://www.goodreads.com/review/list/57544153-sanjay?shelf=did-not-finish&quot;&gt;ditch and not finish books that I didn&#39;t find interesting or engaging&lt;/a&gt;&lt;br /&gt;
To put these strategies into practice, at all times &lt;a href=&quot;https://www.goodreads.com/review/list/57544153-sanjay?shelf=currently-reading&quot;&gt;I&#39;m in-progress on&lt;/a&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;An Audiobook on Audible - A Pro Tip on this one: I use a &amp;quot;hidden&amp;quot; subscription option under the Premium Plus offering that gives one audiobook credit every &lt;em&gt;other&lt;/em&gt; month since I found that one every month was too much and a waste of money for me&lt;/li&gt;
&lt;li&gt;An Audiobook on Spotify - &lt;a href=&quot;https://www.spotify.com/us/duo/&quot;&gt;Premium Duo plan&lt;/a&gt; provides 15 hours of audiobook listening&lt;/li&gt;
&lt;li&gt;An e-book on Kindle (Paperwhite and mobile app) - usually borrowed from my local library via &lt;a href=&quot;https://libbyapp.com/&quot;&gt;Libby&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A physical book&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Having multiple books and formats to reach for makes it so it&#39;s incredibly easy to always get some reading done each day. Removing this mental friction and giving myself options to switch between different books has been key for me to building a consistent reading habit. If I happen to be around my physical book, I try to pick it up with the target of reading a page and generally end up reading more than that. If I&#39;m driving, I pop an audiobook on. Even ten minutes a day stacks up to a lot of progress over a month. In pretty much any other scenario, I have my phone and an e-book is a couple of taps away just like any other app I&#39;d otherwise fill my idle time and attention with.&lt;/p&gt;
&lt;p&gt;To wrap up my thoughts: I came to this current reading system and gleaned its results through deliberate and consistent experimentation over most of this year. While scrolling algorithmic, curated feeds optimized to catch and hold my attention might have made me &lt;em&gt;feel&lt;/em&gt; like I was reading more - it did not fulfill my desire to be more informed and mentally engaged with new information at a pace that my mind could meaningfully digest. That, balanced with the activity of reading for no other purpose than fun completes the objective of my overall system.&lt;/p&gt;
&lt;p&gt;I hope this was insightful and informative for you, reader!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The post was authored with editorial (Claude Opus 4.5) and visual (Gemini 3 Pro) support from Generative AI. All words are my own.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  <entry>
    <title>Healthy Tension</title>
    <link href="https://sanjaynair.me/blog/2025-12-31-healthy-tension/"/>
    <updated>2025-12-31T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2025-12-31-healthy-tension/</id>
    <content type="html">&lt;p&gt;Every leadership decision about team composition is a strategic bet. You can prioritize short-term execution or long-term capability building, but rarely both equally. An important skill of leadership is building teams, or the ability to decide how to bring together a set of people to effectively solve a problem or achieve an objective. This skill can be applied at the smallest scale with just a single person selected for a targeted purpose, such as a team lead assigning a team member to a task.&lt;/p&gt;
&lt;p&gt;This exercise in decision making can be scaled up multiple levels to larger and larger scopes of teams, where at some point the leader is no longer making decisions about assigning individuals to tasks, but rather organizing teams or groups of teams around a strategic priority. When you start to have to consider this scope of leadership in building teams and organizations to solve problems, a key trait that begins to emerge is what I&#39;ve dubbed &lt;strong&gt;healthy tension&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Healthy tension&lt;/strong&gt;, at its core, is as follows: &lt;em&gt;the organizational dynamic that emerges from the decision of a leader by aligning a group of people or teams around a common set of goals while deliberately placing their strategy, tactical approaches, values, and/or priorities at odds with each other.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When building teams, the most intuitive trait to prioritize is strong collaboration and good chemistry. As a leader, you would prefer that your team, simply put, gets along. However, even in the smallest of scales (think a &amp;quot;1 pizza team&amp;quot;: small enough to feed with a single pizza order, typically 6-8 people), what you don&#39;t want is a notion of &amp;quot;groupthink&amp;quot;. Strong teams are built on a foundation of shared purpose but diverse approach and opinion. The best and most effective teams find ways to promote individual thought while working through disagreement in healthy and productive ways towards a common goal.&lt;/p&gt;
&lt;p&gt;To better describe this idea, I&#39;d like to describe a hypothetical organizational structure where a focused effort to have teams at odds with one another could be the right if not the best structure to achieve an objective.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A senior leader in charge of a factory responsible for producing &amp;quot;widgets&amp;quot; has been tasked by their shareholders and board to increase overall operating profits and reduce the amount of lost revenue due to defective product exiting the production line and having to either be trashed or returned by customers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The leader has a decision to make. How to split up their team to effectively achieve the objectives laid out to them. The leader decides to organize their factory from the existing pool of employees into the following teams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Production team&lt;/strong&gt; is responsible for the operation and functioning of the line are given the priorities to produce product as quickly and accurate to spec as possible. They are measured on number of product created to spec with any not created to spec not counting to the total. The spec is provided by the R&amp;amp;D team.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Maintenance team&lt;/strong&gt; is responsible for the upkeep of the production line machinery. They are measured on the overall availability and uptime of the machinery as well as how quickly they are able to perform repairs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The R&amp;amp;D team&lt;/strong&gt; is responsible for authoring the spec used by the Engineering team and built by the production machinery. Their priority is to do research to create the most innovative designs and push the boundaries of Widget capabilities to maintain competitiveness in the market.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Accounting team&lt;/strong&gt; is responsible for ensuring all operations are costing as little as possible without compromising on any of the other objectives.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now consider the healthy tension present with this organizational structure.&lt;/p&gt;
&lt;p&gt;The Production team:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Needs the R&amp;amp;D team to simplify their designs to make them easier to produce&lt;/li&gt;
&lt;li&gt;Needs the Maintenance team to speed up their repairs so the line can be down for less time&lt;/li&gt;
&lt;li&gt;Needs the accounting team to find a better balance on cost saving measures that don&#39;t impact the overall productivity of the line&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Maintenance team:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Needs the Production team to manage the pace of their work to not to require increased maintenance and repairs due to the high stress on the equipment caused by the high pace of production and ultimately leads to more issues, repairs needed, and downtime.&lt;/li&gt;
&lt;li&gt;Needs the R&amp;amp;D team to consider the practical requirements of their &amp;quot;cutting edge&amp;quot; designs on the corresponding bespoke and hard to maintain production line equipment it requires.&lt;/li&gt;
&lt;li&gt;Need the accounting team to consider the cost of their services, while indirect, just as critical to the overall organization&#39;s objective lest the production line be constantly broken and limping along without proper maintenance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The R&amp;amp;D team:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Need the Production and Maintenance teams to adapt to new designs quicker so that the company can iterate on the shipping the latest Widget and capture market share as quickly as possible&lt;/li&gt;
&lt;li&gt;Needs the accounting team to stop cutting the research budget as a long-term priority in favor of the  shorter term priorities of Production and Maintenance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This might at first seems like the most dysfunctional organization this poor, misinformed leader could have ever put together. But healthy tension in an organization can only be effective with a set of core values and strong team culture holding it together. A critical, uncompromising responsibility of the senior leader establishing the healthy tensions is also to set a culture of collaboration and shared success (and failure).&lt;/p&gt;
&lt;p&gt;The teams in our fictional production company are also built with the following precedents and instilled with the following expectations along with their priorities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each independent group has to go into each challenge with the best intentions for their partner teams. They have to understand that one of their core deliverables is &lt;strong&gt;collective success&lt;/strong&gt;. Success that comes at another group&#39;s expense isn&#39;t success at all. Therefore, they must find ways to collaborate and work out differences in opinion in productive rather than combative ways.&lt;/li&gt;
&lt;li&gt;Each group is expected to come up with solutions in collaboration with their partner teams and not simply escalate disagreements to upper management unless it requires an explicit decision outside or across the scope of either group.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now consider the benefits that emerge with the described objective, org structure, team priorities, shared core values, and expectations:&lt;/p&gt;
&lt;p&gt;The Production team&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Provides feedback to the R&amp;amp;D team on how to include adjustments to their upcoming design based on the practicality of production for the current iteration that finds a healthy balance between innovation and efficiency of production&lt;/li&gt;
&lt;li&gt;Partners with the Maintenance team to create processes to manage the pace of the production line within tolerances of the equipment to minimize issues and subsequent repairs.&lt;/li&gt;
&lt;li&gt;Incorporates suggestions from the accounting team for production methods that increase cost efficiency without meaningfully compromising on overall production throughput&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Maintenance team&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consults with the R&amp;amp;D team on more modern and innovative techniques to perform maintenance and repairs more efficiently&lt;/li&gt;
&lt;li&gt;Provide the accounting team with measurable metrics on the return on investment for a robust maintenance process and routine&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The R&amp;amp;D team&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Researches new technologies and develops new processes for all other teams that the accounting team could directly relate back to return on investments and cost savings&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaynair.me/assets/images/healthy-tension-diagram.png&quot; alt=&quot;Generated by Nano Banana Pro 3&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If you have spent any time in a large, multi-disciplinary professional environment, you can likely map these fictional teams directly to roles in your own organization. The specific scope and resulting healthy tensions might vary, but I think its highly likely you could discern what your organization&#39;s version of this healthy tension might be.&lt;/p&gt;
&lt;p&gt;In my opinion, the real strength of this dynamic is its inherent self-sufficiency. Assuming there is a set of core values that each member of the organization holds themselves to, the overall effectiveness of the organization scales proportionally to the collective strength of the independent teams. The higher the healthy tension, the higher the possibility and degree of success. As leaders, I believe we should all consider looking at our organizations, large or small, through this lens of healthy tensions and determine how to best configure it to be in balance and serving a collective objective. What tensions exist in your organization today that, if acknowledged and channeled productively, could drive better outcomes?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The post was authored with editorial support (Claude Opus 4.5) and image generation (Nano Banana 3 Pro) from Generative AI. All words are my own.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  <entry>
    <title>Human Debt</title>
    <link href="https://sanjaynair.me/blog/2026-01-20-human-debt/"/>
    <updated>2026-01-20T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2026-01-20-human-debt/</id>
    <content type="html">&lt;p&gt;Software engineers understand technical debt. It is the accumulated cost of trading off quality for speed or the short term for the long term that must eventually be repaid. Leaders have their own version of this ledger. I call it &lt;strong&gt;human debt&lt;/strong&gt;: the relational cost incurred when you must sacrifice goodwill or trust to serve a higher priority.&lt;/p&gt;
&lt;p&gt;Software engineers often have to make decisions around how to manage technical debt. They might consider large decisions such as bringing in a new and unproven component into their architecture down to the smallest consideration where every new line of code in the codebase is considered additional toil.&lt;/p&gt;
&lt;p&gt;People leaders have to consider the currency of professional relationships as a key component of how effectively they are able to do their jobs. Similarly to the software engineer, who is optimizing for the highest quality within the tightest constraints such as time or cost, the people leader must optimize for tactical delivery or strategic victory potentially at the cost of favor or trust amongst their peers, subordinates, and superiors. In some cases, they must incur this &lt;strong&gt;human debt&lt;/strong&gt; to effectively meet their goals or enable an objective for their teams and organization.&lt;/p&gt;
&lt;h2&gt;The Uncomfortable Reality&lt;/h2&gt;
&lt;p&gt;The consideration of deliberately damaging a professional relationship to further another objective isn&#39;t commonly discussed (as far as I&#39;ve read). It is, however, something I&#39;ve discussed many times with other leaders and peers. Just as shipping inefficient or buggy code for the sake of speed, for example, it is sometimes the difficult but correct decision a leader must make for the greater good of their priorities.&lt;/p&gt;
&lt;p&gt;This creates tension between the prevailing leadership advice that is: build strong relationships, your people are your top priority, take care of your people and the rest will take care of itself. The nuance comes from when the &amp;quot;rubber meets the road&amp;quot;, and you as the leader have to apply this advice in practice. You navigate a complex web of professional and interpersonal politics, biases, prejudices, grudges, favoritism, and selfishness. Prioritizing the people you work with sometimes means sacrificing the goodwill of some for the sake of others.&lt;/p&gt;
&lt;h2&gt;When Human Debt Becomes Necessary&lt;/h2&gt;
&lt;p&gt;There are some scenarios I will frame up based on my own personal experience as a leader that come to mind on this topic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Moving a team member off a project they stood up and have a significant personal investment in to one of higher priority or one that requires their unique expertise. This leaves them feeling unsupported and unheard for not being able to see their project through till its conclusion and enjoying the victory lap.&lt;/li&gt;
&lt;li&gt;Taking one side of a conflicting pair of proposals between two favored peers based on your own judgement of minimizing risk and maximizing the chance of success over innovation or experimentation with new technologies. The person behind the rejected proposal feels like they didn&#39;t get a fair shot or your decision was based on illogical bias towards the other individual.&lt;/li&gt;
&lt;li&gt;Reallocating headcount off a leader&#39;s team that is just as saturated with work as the others but whose priorities are at lower risk of failing or causing significant harm to the business&#39; bottom line. The impacted leader feels like they are being unjustifiably punished or put at a disadvantage compared to their peers when being held accountable for their delivery.&lt;/li&gt;
&lt;li&gt;Overriding someone&#39;s architectural decision that provides significant improvements to key value metrics but significantly deviates from organizational standards and introduces risks to toil management and overall supportability. Those involved in the forward-looking design see their research and hard work into the new design thrown away and feel like their contributions are not valued.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These examples are general enough where you might find similarities with what you&#39;ve experienced. They all represent decisions made with the best of intentions but deliberately required a sacrifice of goodwill or interpersonal currency.&lt;/p&gt;
&lt;h2&gt;Key Considerations&lt;/h2&gt;
&lt;p&gt;There are a few considerations I weigh when facing these scenarios:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;What would a &amp;quot;good&amp;quot; leader do when presented with this as an option? Would they ever consider this an option at all? I say absolutely, yes. The ability to identify the right places to apply this tradeoff while never irreversibly damaging a relationship is what separates the good leaders from the great leaders. They build bonds that can withstand the strikes of single decisions. The great leaders construct visions that those around them are rallied around, above individual decisions that may or may not favor them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When considering &amp;quot;people&amp;quot;, it is not a singular construct in reality. Leaders spend considerable amounts of time and effort managing the fact that they typically work with people with potentially conflicting assignments, motivations, priorities, ideals, and personal values. It would be reductive to consider human debt from a singular perspective when in some cases the primary, &amp;quot;noble&amp;quot; objective is one directly at odds with one or more of these &amp;quot;people.&amp;quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Is Human Debt inevitable? Is the decision to sacrifice a part of a professional relationship something every leader will have to face given enough time and experience? Again I say, absolutely, yes. With enough time and experience, great leaders hit these scenarios enough times, fail, and pick themselves up again the next time to understand the balanced formula for success. Eventually, they find the healthy equilibrium.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Can Human Debt be paid off? Humans are not deterministic, transactional things like codebases or software systems. Resolving the consequences of a decision that antagonized someone might be minor enough to do, or significant enough to be considered irrevocable. Some burned bridges are just impossible to rebuild. Great leaders apply these decisions deliberately with full understanding of the greater effect of their actions.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;As leaders of people, our problems don&#39;t always have perfect solutions. People are not deterministic like code, and even with software you&#39;re always balancing tradeoffs in the moment and between the short and long term. If we spent all our time just nourishing our professional relationships, we&#39;d come to be known as the friendly boss that gets nothing done. If we took every opportunity to push everyone away, well we&#39;d probably just be known as the resident jerk...who got nothing done.&lt;/p&gt;
&lt;p&gt;We all have to accumulate some amount of human debt, the spending of the goodwill we work hard to build and nurture in our professional relationships. It is the legal tender in the marketplace of solving hard problems. The greatest leaders are the ones that understand how to balance the savings and spending of this currency. Just remember to be frugal with your spending and know that a strong habit of building savings has always been sound advice.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The post was authored with editorial support (Claude Opus 4.5) and image generation (Nano Banana 3 Pro) from Generative AI. All words are my own.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  <entry>
    <title>A Practical Introduction to Generative AI Terminology</title>
    <link href="https://sanjaynair.me/blog/2026-06-14-practical-intro-to-genai-terms/"/>
    <updated>2026-06-14T00:00:00Z</updated>
    <id>https://sanjaynair.me/blog/2026-06-14-practical-intro-to-genai-terms/</id>
    <content type="html">&lt;p&gt;AI buzzwords are everywhere. Terms are thrown around in dialogue that feel like they&#39;ve existed for decades but have only emerged in the past year or two. I&#39;ve experienced a broad disparity between two groups of people: those I would consider &amp;quot;AI power users,&amp;quot; regularly on the bleeding edge of every new innovation, and those who have only dabbled in the subject and wouldn&#39;t be able to grasp whatever &amp;quot;agentic&amp;quot; thing everyone is raving about. I do my best to be aware of the wave of AI hype and keep myself informed of all the lingo. If you&#39;re feeling like you&#39;re behind, or have no idea what &amp;quot;an agentic workflow integrating with an MCP server using the latest model from Anthropic with the larger context window&amp;quot; is, read on.&lt;/p&gt;
&lt;p&gt;I&#39;d like to provide short explainers of a few terms related to the GenAI tools that have sprung up within just the last 12 months. I will approach this from first principles, so that anyone feeling behind on the discourse can quickly catch up. We will cover the following terms: LLM, Hallucination, Context Window, System Prompt, Agent, MCP, Tool, and Skill.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A lot of what is presented as fact or best-practice was accurate as far as I know at the time of writing. These statements might get stale within a year or a month, it&#39;s truly hard to say with the pace of change.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Large Language Model&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Large Language Models or LLMs&lt;/strong&gt; are the foundation of the latest wave of AI hype and the core of what powers most of the modern AI technology mentioned below. You can &lt;a href=&quot;https://en.wikipedia.org/wiki/Large_language_model&quot;&gt;read up&lt;/a&gt; on the theory and science behind LLMs as well as the years of research that went into taking them from concept to product. There are even some who &lt;a href=&quot;https://www.freethink.com/robots-ai/arc-prize-agi&quot;&gt;argue that LLMs are fundamentally the wrong path&lt;/a&gt; to take humanity into a new golden age of AI and technology. At their core, they are computationally massive systems trained to predict what comes next given an input, specifically, what &lt;strong&gt;token&lt;/strong&gt; (a unit of text, roughly a word or word fragment) follows said input. That basic premise, scaled up with massive computational power and training data sourced from the internet, manifests in higher-level abstractions like the chat interfaces you&#39;ve likely already used.&lt;/p&gt;
&lt;p&gt;Models like &lt;a href=&quot;https://chatgpt.com/&quot;&gt;ChatGPT&lt;/a&gt;, &lt;a href=&quot;https://claude.ai/&quot;&gt;Claude&lt;/a&gt;, and &lt;a href=&quot;https://gemini.google.com/app&quot;&gt;Gemini&lt;/a&gt; are typically referenced as &amp;quot;frontier models&amp;quot; and stand at the cutting edge of generative AI capabilities. There are &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_large_language_models&quot;&gt;dozens of other models available&lt;/a&gt;, spanning various specializations and scales, with some being fully open source.&lt;/p&gt;
&lt;h2&gt;Hallucination&lt;/h2&gt;
&lt;p&gt;One of the most important characteristics of LLMs to understand, one that shapes all the techniques built on top of them, is that they are fundamentally &lt;strong&gt;non-deterministic&lt;/strong&gt;. Said another way, they&#39;re probabilistic, meaning if you provide the same input twice given exactly the same context, there is no guarantee the output will be the same. You know that disclaimer tucked into basically every LLM chat tool you might use? &lt;em&gt;&amp;quot;&lt;em&gt;Insert LLM name here&lt;/em&gt; can make mistakes.&amp;quot;&lt;/em&gt; This disclaimer warns of &lt;strong&gt;hallucination&lt;/strong&gt;, which refers to a model generating confident but factually incorrect or fabricated information. This stems from the model&#39;s probabilistic nature. It has no inherent ability to understand its inputs or access ground truth about the world. If you&#39;d like a demonstration, just try asking a model like Claude Sonnet 4.6 &lt;a href=&quot;https://techcrunch.com/2024/08/27/why-ai-cant-spell-strawberry/&quot;&gt;how many R&#39;s are in the word strawberry&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Context Window&lt;/h2&gt;
&lt;p&gt;LLMs have what is called a &lt;strong&gt;context window&lt;/strong&gt;, which is a measure, in tokens, of how much text the model can consider at once when generating a response. Modern LLMs commonly have context windows of hundreds of thousands of tokens up to millions.&lt;/p&gt;
&lt;p&gt;One might assume that a model with a 1 million token context window would deliver consistent output quality all the way up to that limit. However, modern LLMs suffer from what&#39;s colloquially known as &lt;strong&gt;context rot&lt;/strong&gt;. Once a model&#39;s context window reaches around 80% of its limit, the model&#39;s output quality takes a significant drop. Because LLMs are functionally probabilistic &amp;quot;next word&amp;quot; guessers, every time a new input gets sent in, it is really just appended to the end of the ongoing session and that &lt;em&gt;entire&lt;/em&gt; session is then sent back into the model for the following output to be generated.&lt;/p&gt;
&lt;p&gt;When operating over the course of an extended session with an LLM, it&#39;s recommended to periodically either start a fresh session when the utilized context window is approaching around 80%, or perform what is known as &lt;strong&gt;compacting&lt;/strong&gt; the session. This basically feeds the entire session history back into a fresh session with the model to be summarized and used as a more token-efficient representation of the context built up in the session up to that point.&lt;/p&gt;
&lt;h2&gt;System Prompt&lt;/h2&gt;
&lt;p&gt;Products built on LLMs will typically use what&#39;s called a &lt;strong&gt;System Prompt&lt;/strong&gt;, which is a set of instructions automatically inserted before your input, giving the model guiding principles and constraints to follow when generating responses. You can browse &lt;a href=&quot;https://platform.claude.ai/docs/en/release-notes/system-prompts&quot;&gt;Anthropic&#39;s published system prompts for Claude&lt;/a&gt; for a real-world example.&lt;/p&gt;
&lt;h2&gt;Agent&lt;/h2&gt;
&lt;p&gt;The simplest implementation of an LLM is one of basic text input and output. This was the first iteration of ChatGPT that was released and provides more-or-less a direct experience of what LLMs provide as a technology. Prompt in, generated content out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agents&lt;/strong&gt; distinguish themselves from basic LLM interactions in two key ways: First, they can &lt;strong&gt;execute multiple steps&lt;/strong&gt; before producing a final output, including follow-up clarification and iterative planning. Second, they can &lt;strong&gt;interface with external systems&lt;/strong&gt; via APIs, Tools, and MCP servers (explained below), allowing them to act on the world rather than just respond to it. Because of this inherent flexibility and underlying power of LLMs, all varieties of Agents have sprung up from those that can code autonomously all the way to ones that can provide automated customer service over the phone.&lt;/p&gt;
&lt;h2&gt;Model Context Protocol (MCP)&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://modelcontextprotocol.io/docs/getting-started/intro&quot;&gt;Model Context Protocol&lt;/a&gt; or MCP was created by Anthropic, the creators of the Claude series of frontier models, and provides an open source specification by which LLMs can integrate with external systems. Much like &lt;a href=&quot;https://en.wikipedia.org/wiki/REST&quot;&gt;REST&lt;/a&gt; provides a standard by which systems can publish an HTTP-based API for applications to consume, MCP provides a specification by which servers can expose an interface tailored for LLM clients.&lt;/p&gt;
&lt;p&gt;Though competing specifications like &lt;a href=&quot;https://a2a-protocol.org/latest/&quot;&gt;Agent-2-Agent&lt;/a&gt; exist, and despite significant scrutiny from &lt;a href=&quot;https://github.com/modelcontextprotocol/modelcontextprotocol/issues/630&quot;&gt;multiple&lt;/a&gt; &lt;a href=&quot;https://github.com/modelcontextprotocol/modelcontextprotocol/discussions/1751&quot;&gt;cybersecurity&lt;/a&gt; &lt;a href=&quot;https://github.com/modelcontextprotocol/modelcontextprotocol/discussions/1750&quot;&gt;researchers&lt;/a&gt;, MCP remains a widely adopted specification with broad product support.&lt;/p&gt;
&lt;h2&gt;Tool&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;Tool&lt;/strong&gt; is how an Agent interacts outside of its own process boundary. It is a discrete, callable function that an Agent can invoke to interact with something outside its own context like reading a file, querying an API, or running a terminal command. For example, a minimal description of what a &amp;quot;Coding Agent&amp;quot; is can be summarized into 3 parts: 1. an LLM that provides the engine of the agent, 2. a set of tools that can read files, create files, and edit files, and 3. a system prompt that describes to the LLM its purpose and scope as a coding agent.&lt;/p&gt;
&lt;p&gt;Unlike MCP, which is a broad and general protocol, individual Tools are narrowly scoped to a specific capability: a single API endpoint, a file operation, or a shell command. This has advantages such as allowing &lt;a href=&quot;https://www.anthropic.com/engineering/advanced-tool-use&quot;&gt;certain models to be more selective&lt;/a&gt; about which tools they pull into their working context for a given task. Tools can also provide a more robust security context within which a model is given permissions to operate and thereby reduce the risk of unwanted actions being executed.&lt;/p&gt;
&lt;h2&gt;Skill&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Skills&lt;/strong&gt; are an &lt;a href=&quot;https://agentskills.io/home&quot;&gt;open specification&lt;/a&gt; from Anthropic that encode specific agent capabilities in a Markdown file, augmenting what an Agent can do beyond its default behavior. Skills allow for repeatable tasks to be defined and quickly invoked. Typically, a Skill describes a particular task, the Tools and integrations needed to accomplish it, how to use those integrations, and the step-by-step process to complete it.&lt;/p&gt;
&lt;p&gt;One of my favorite skills is also one of the simplest: &lt;a href=&quot;https://www.skills.sh/mattpocock/skills/grill-me&quot;&gt;/grill-me&lt;/a&gt;. The Skill&#39;s author, &lt;a href=&quot;https://www.skills.sh/mattpocock&quot;&gt;Matt Pocock&lt;/a&gt;, describes it best in its opening lines, which also happen to make up about 3/4 of its total content:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Interview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer.
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;I have found these concepts cover enough of the fundamentals to navigate the discussion and innovation swirling around Generative AI. I hope you find them useful. If so, please consider passing it along to someone who&#39;s been quietly wondering what all the noise is about.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The post was authored with editorial support (Claude Sonnet 4.6) and image generation (Gemini 3.1 Pro) from Generative AI. All words are my own.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
</feed>
