Blog

I do occasionally share my thoughts and learnings on Medium.

Medium Articles

At the crossroads

April 23, 2025

It is not the strongest of the species that survives, nor the most intelligent that survives. It is the one that is the most adaptable to change.- Charles Darwin Where are we? If you were building software for the past “x” number of years like me, I hope you are at a cross road( or figured already where you are heading to) like me? then i think its high time we re-evaluate where we should be going? This is a blog where i think we should be going, not necessarily by any yardstick are my words objectively right, but rather its a small attempt to express what i feel at this moment and if you have something else in mind do reach-out, comment or whatever you prefer Evolution of LLM Of course anybody’s hot topic of the day, will it replace my job? will it take over the world? am i living in the matrix? the tension is real, the anxiety is real, but what exactly should we be concerned about? If you are thinking it could replace our job, no sugar-coating, sooner or later we will perish, because its not the smartest nor the most intelligent that survive, rather its always the one most adaptable to change, https://www.forbes.com/sites/quickerbettertech/2025/01/26/business-tech-news-zuckerberg-says-ai-will-replace-mid-level-engineers-soon Not just models but everything is ever evolving, when i started to design websites, we used to build basic webpages for businesses and quote some not so cheap money, but with next.js and vercel, you can bootstrap a website and host it in a matter of minutes. and talking about LLM applications, I have been using cursor.ai, and its been some months since i actually wrote basic test-cases, bootstrapped applications from start or any of the grunt work I used to do, I have not even used code-snippets in a long time( used to be thing back then) I used to write meeting notes for major meetings, but once i started using fellow, there is no more going back when fellow could do all those things much better than i ever could I am not going to go on about the countless other Models and softwares using those models, what i want to say is the evolution is real and its the same evolution that took the jobs away from coal workers, that took the jobs away from countless factory workers, that made the swords and shields obsolete. brace it or ignore it, up to you, but its going to come to you one way or another ;) What should we be doing? First things first — embrace the change, everything that you are doing comfortable and are repetitive — immediately use an agent that excels doing it, in other words, no more grunt work, AI excels at things that have a pattern — identify the pattern in your work. Be better at understanding the “AI world”, if you are like me and are not math-heavy, try diving into books that are more into building applications that use AI, understand whats happening under the hood, 1 day at a time. Get out of your comfort zone — its high time we get out of our comfort zone, and that means, upscale on your skills, at the moment i am trying to get better at my system design skills and skills to build LLM based application. Use every LLM based applications thats out there, be it cursor.ai( highly recommend), chatgpt, use it or better develop applications based on the models to tailor your needs, in addition to making your lives easier, this gives you a clear picture of where you are standing with your skillsets, if the application is doing a good job, its time you need to upscale. Final Words we are yet to see the full potential, but if there is any better time to get out of your comfort zone, its probably now. cheers 🥂

Integration Testing

March 10, 2022

Intro This is a continuation of the Unit-testing article. The integration testing in addition to the working of a unit is also focused on the behaviour of the unit. the external dependencies( which are mostly environment-specific) should be stubbed and the test should be able to predict the behaviour of these stubs using spies, also the behaviour of the method to be tested, when the stubbed method provides us different output This is not a general how-to document, rather this is what I did and the reasoning behind why we did some things and why we should not do some things. All the examples are based on NestJs, as Nest by default uses jest, assertion, mocks are based on jest library( v26.4.2). Happy testing !! Stubs Mostly anything which depends on an external entity should be stubbed. These include but are not limited to: any standard protocol call to any other entity Database calls file system operations any function which does new Date() ( maybe we should not use new Date() inside every function, rather pass it as a parameter?) This is a must-bookmark repo if you are using NestJs https://github.com/jmcdo29/testing-nestjs Methods without any external dependency which are not part of the testing function need not be stubbed. eg: const calculateAvgSpy = jest.spyOn(service,‘calculateAvg’).mockResolvedValueOnce({ avg: 123.23 }); the above example stubs the calculateAvgSpy method on service Service and tells jest that, this method always returns 123.23 The pain of stubbing Stubbing is fun when the methods are fewer methods to stub, but it’s an absolute nightmare when it’s a method with many external dependencies. also, when you are mocking return values, it’s also important to note that return values are in the correct format etc. Its highly recommended to seperate out your stubs, sample function input, outputs, mock values etc.( or be very quick in bookmarking ;) ) Why do we hate Global modules? From testing perspective global modules are unnecessary dependency, because simple, there is no absolute global module, even if logger is a global module, I have come across modules that do not need any logging, why do they need logger in their imported module list 🤷‍♀ Global modules mean, we need to stub these modules and add the dependency to every service/module we are testing. Stubbing Global Node.js modules Methods that have new Date() as part of the output, is hard to test because of obvious reasons( maybe why we shouldn’t do that, instead pass date as input?) if you have, then we should stub these as well. here is how to on stubbing new Date() let today = ‘1991–08–21’; beforeAll(() => { jest.useFakeTimers(‘modern’); jest.setSystemTime(new Date(today));}); In the above snippet, today is 1991–08–21 and we override new Date with it. if you want to stub some other global functions, stub global jest.spyOn(global, ‘Map’).mockImplementation(() => currentDate); Testing the behaviour of methods Refactoring is irresponsible and very difficult if we don’t have tests supporting the expected behaviour of a method. We test and assert the behaviour of method, mainly if the input is x, what all methods will be called, and how many times? The converse of point number 1. edge cases — what if the external methods(database calls) returns an empty responses? Following is a very simple example of integration testing. Function to be tested: async function updateCustomer(input){ if(!input){ throw new Error('input is empty') } await dbCall.updateCustomerWithNewDetails(input); return 'ok';} Integration tests: it("updateCustomer | Throw correct error if input is empty", async () => { let input = { name: 'arjun' }; getUserDetailsSpy = jest.spyOn(dbCall, 'updateCustomer').mockResolvedValueOnce({ success: true }); try{ await service.updateCustomer(input); throw new Error('should have thrown an error but didnt') }catch(err){ let actualError = err.message; let expectedError = 'input is empty'; expect(actualError).toEqual(expectedError); } }); it("updateCustomer | updateCustomerWithNewDetails( should be called with the right parameter", async () => { let input = { name: 'arjun' }; getUserDetailsSpy = jest.spyOn(dbCall, 'updateCustomer').mockResolvedValueOnce({ success: true }); await service.updateCustomer(input); expect(getUserDetailsSpy).toHaveBeenCalledTimes(1); expect(getUserDetailsSpy).toHaveBeenNthCalledWith(1, input);}); Lastly, if you are having a continuous integration strategy in place, every build should pass the test cases written. We didn't spend all these time for nothing. Whatever be your deployment strategy, make sure no code goes to production without a tick mark for all the test cases. 🙂

Beginners guide to Unit testing

September 21, 2021

Why Unit test? When writing code that is critical for the business, how does a developer make sure their code has handled all the edge cases? How does a developer build confidence about their code? How to make sure someone else refactoring a function doesn’t break the existing functionality? or doesn’t introduce any new bug? The answer is unit-test. Purpose of Unit test Unit test as the name suggests makes sure that a particular unit works perfectly. No matter what the edge cases, the unit will not fail. If we consider a large function that has multiple units that work perfectly well. then changes of the function having bugs are minimal. Scope The Scope of this article covers only nestjs unit-testing( using jest), but the underlying concepts and methods are mostly always the same. Basic Example let’s start with a very simple example, the addition. below is a service file that takes care of the sum of two numbers: import { Injectable } from '@nestjs/common'; @Injectable()export class TestService { sum( a:number, b:number ): number{ if(a <0 || b <0){ throw new Error('it should be > 0'); } return a + b; }} Every suite of tests for a unit should cover at least the following scenarios happy scenario — the unit should return the expected result negative scenario — if passed an input that is not supposed to be passed, the unit should throw the correct error, instead of an unexpected error. test.service.spec.ts import { Test, TestingModule } from '@nestjs/testing';import { TestService } from './test.service'; describe('TestService', () => { let service: TestService; let a,b; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [TestService], }).compile(); a = 100; b = 200; service = module.get<TestService>(TestService); }); it('should be defined', () => { expect(service).toBeDefined(); }); it("sum | it should give me right output", () => { let actualOutput = service.sum(a, b); let expectedOutput = 300; expect(actualOutput).toEqual(expectedOutput); }); it("sum | it should return a number", () => { let actualOutput = service.sum(a, b); expect(typeof actualOutput).toEqual("number"); }); it("sum | if i pass NaN then i will get NaN", () => { a = NaN; let actualOutput = service.sum(a, b); expect(actualOutput).toBeNaN() }); it("sum | if a| b < 0, i should get an error", () => { a = -1; try{ service.sum(a, b); throw new Error('it should have failed, but didnt'); }catch(err){ expect(err.message).toEqual("it should be > 0"); } }); }); Examination of the test cases if we examine this, describe(‘TestService’, () => { Defines the main context, depending on how you have configured, it can have multiple contexts. it("sum | it should give me right output", () => { let actualOutput = service.sum(a, b); let expectedOutput = 300; expect(actualOutput).toEqual(expectedOutput); }); each it block has an assertion statement, which basically defines the behaviour of this test. in the it we can define the behaviour of the test. A good practice is to follow the below-naming convention. <function name> | <expected behaviour of the test> expect(actualOutput).toEqual(expectedOutput); is the assertion statement ( https://nodejs.org/api/assert.html ) we can use any assertion language, (https://jestjs.io/docs/expect) All the test cases in the example are self-explanatory, we’ll examine one more test case it("sum | if a| b < 0, i should get an error", () => { a = -1; try{ service.sum(a, b); throw new Error('it should have failed, but didnt'); }catch(err){ expect(err.message).toEqual("it should be > 0"); } }); in the above test case, we can see that our function should be throwing an error, and it should not be any error, it should be an expected error as well, hence we use the catch block to assert expect(err.message).toEqual(“it should be > 0”); also if there is no error, that is also not expected behaviour. hence we throw an error to fail the test case throw new Error(‘it should have failed, but didnt’); NOTE: When generating a service, nest automatically creates a test fie, convention is that test files should end with *.spec.ts when creating a test module, we should also import any dependency the module has const module: TestingModule = await Test.createTestingModule({ providers: [TestService], }).compile();

Why I moved to VSCode From Sublime

November 14, 2020

TLDR: VSCode is super awesome. I was using Sublime for almost 5 years before moving to VSCode and I loved sublime. This was cool, was super fast, I had a lot of snippets, I knew a lot of shortcuts to make people think I was an ace, Lot of packages, and loved how it made me feel. Then VSCode came into the picture, and I started reading all the “VSCode vs Sublime” blogs, most of them told Sublime is for advanced programmers whereas VSCode is for beginner to intermediate. This somehow boosted my programmer ego. Yeah, every programmer has an ego. “I know more stuff than you”, “I have seen more challenges than you”, “I use vim dude, I am super cool”, you can see multiple examples in your company or your career. But as age goes, you come to realize that you know less and less and you cant learn everything by yourself. https://www.amazon.in/Pragmatic-Programmer-Journeyman-Master-Old/dp/020161622X is one super cool book to check your ego in control. lolAll thanks to my ex-boss who recommended me this book, who somehow thought that this guys overconfidence need to be put in control.Coming back to the topic, I continued using sublime, the problem was I was spending more time on fixing packages, configuring packages, fixing issues in some package than actually coding. This made me very frustrated. Please od understand that I feel contributors make any open-source software great, but I personally feel that your primary focus in your work hours is to solve the company’s problem, not some other problem because your company is paying you to do the former not the latter. Fast forward → VSCodeEverything in VSCode is made to just code, not to waste our time on fixing packages that can speed up our coding: they have an interactive setting, not the JSON to actually focus on finding an attribute and editing. They have all the basic stuff installed in VSCode, be it Typescript Support, TSLint, Git, JShint. The code navigation is super cool. Merge conflicts are no more tedious but rather fun to do. Integrated terminal →no more loading terminal to just run a REPL or to check whether the code is working. oh yeah I am not going to focus more on their pros and cons because there is a number of blogs who have covered these in much more detail and elegantly. attaching one for your reference.https://medium.com/better-programming/how-to-use-vscode-like-a-pro-e120c428f45f Thats that. cheers 😄

Arjun Sunil