Skip to main content

Writing

Thoughts & Articles

I write about frontend engineering, system design, and building things on the web. Published on Medium.

View all on Medium

Latest posts — 6 articles

I’m a Full-Stack Developer in 2030. Here’s What Nobody Warned Me About.
artificial-intelligencesoftware-engineeringtech-layoff

I’m a Full-Stack Developer in 2030. Here’s What Nobody Warned Me About.

Still Here ? “Barely”. Notes from a developer who survived the 2030.The AI didn’t steal my job. It did something much worse. I’m writing this at 11pm on a Tuesday. There’s an AI agent running in my terminal right now, finishing a feature I started this morning. I gave it a prompt. Described what I needed. It’s doing the rest. This is my job in 2030. And before you say “that sounds amazing” — let me tell you what it actually feels like from the inside. The Year Everything Changed (And Nobody Said It Out Loud) In 2025, I was a decent full-stack developer. React, Node.js, a bit of cloud stuff, comfortable with system design. The kind of engineer any startup would hire and be happy with in a week. I made good money. I felt useful. The future felt stable. Then agentic coding tools crossed a line. Not the “Copilot finishes your function” kind of line. The real kind. The kind where a junior developer with the right AI setup ships a full feature in 4 hours — something that used to take the entire team a sprint. I remember the exact Slack message from my manager in late 2026: “Hey team — we’re doing a strategic review. We’re finding AI-assisted developers are completing work at 3–4x the previous rate. We’ll share more next week. Nothing to worry about.” There was a lot to worry about. The next week, three engineers were let go. Two more the week after. The company didn’t replace them. It didn’t need to. The Compression Nobody Saw Coming Everyone expected junior devs to get hit first. They did. But that wasn’t the real story. The real story was the compression of the entire career ladder. Think about a dev team in 2024. Juniors, mids, seniors, leads, architects. Each level was a career rung. You climbed slowly. Seniors mentored mids. Mids mentored juniors. The ecosystem made sense. AI ate the bottom first. Then the middle. Then turned to look at the seniors. Suddenly, one senior engineer with good prompt instincts could do the output of an entire team. Companies didn’t need a team. They needed one person who was good at talking to machines. So they kept one person. And let the rest go. Here’s the part that really stings: salaries didn’t go up for that one person either. Because now there were suddenly a lot of “that one person” available, all competing for fewer roles. Supply went up. Demand collapsed. Individual leverage evaporated almost overnight. A 2024 job posting: “Full-Stack Engineer. 3+ years experience. $140K–$180K.” The same job posting in 2029: “Full-Stack Engineer (AI-Native). Comfortable delegating 80%+ of implementation to agents. 3+ years experience. $95K–$115K.” Same requirements. 35% less money. More expected of you. the machines didn’t take your job. they took your leverage. and that ‘s somehow worse. | vishalvoidWhat My Days Actually Look Like Now I know you want the real version. Not the LinkedIn version. Here it is. 9:00 AM — Read what the agent built overnight based on yesterday’s spec. Check if it makes sense. It usually almost does. Fix the 20% that’s broken or wrong. 10:30 AM — Write a detailed spec for the next feature. This is most of my job now. The quality of my prompt determines the quality of the output. I’m basically a technical writer who can read diffs. 12:00 PM — Lunch. Eat alone. The office has 8 people now. It used to have 40. 1:00 PM — Code review. I catch bugs the agent introduced — hallucinated APIs, tests that pass but don’t test the actual behavior, edge cases it never considered because it optimized for the happy path. 3:00 PM — Meeting with the (remaining) product team. Half the ideas we brainstorm get killed because an AI startup already built a competitor that does it for free. 5:00 PM — Try to learn something new. The landscape moves too fast. By the time you’re good at a new tool, there’s a better one. 11:00 PM — Write this. Wonder how long before an AI does this too. I don’t want to know the answer. The Part Nobody Talks About: The Grief I spent years getting good at this. Late nights learning system design. DSA practice sessions I hated but did anyway. Slow, grinding progress from junior to mid to someone who actually knew what they were doing. Years of that. And in about 36 months, most of that skill became… not worthless, but devalued in a way that’s genuinely hard to stomach. My friend Ravi was a backend engineer at a fintech. Six years of experience. Solid. Good at what he did. Laid off in 2027. Applied for 200 jobs. Got interviews at 15. Got offers at 2 — both at 60% of his old salary. He took one. He doesn’t talk about work the way he used to. Multiply Ravi by a few hundred thousand developers across every major tech city and you’ll understand why things feel different now. Why co-working spaces are quieter. Why the startup energy that used to crackle in Bangalore and Berlin and San Francisco feels muted. The money is still there. VC is still pouring into AI infrastructure. Valuations are insane. It’s just — the people are gone. The Skills That Didn’t Die (What I Wish Someone Told Me in 2025) Not everyone got crushed equally. Some people adapted genuinely well, and I’ve watched it happen up close. The developers who survived — and I mean thrived, not just clung on — stopped thinking of code as their craft. They started thinking of outcomes as their craft. They asked different questions: What does the user actually need? What’s the simplest architecture that doesn’t collapse in 6 months? What did the AI miss because it was optimizing for the happy path? Are we building the right thing at all? The ones who struggled — and I was one of them — loved the act of writing code. The craft. The debugging. Sitting with a hard problem and working through it. That love became a liability. Because machines are now better at the craft than most of us. That’s just true. What they’re worse at is caring. Caring about whether this actually solves a real user problem. Caring whether this system will make sense to a human in two years. Caring whether we’re building the right thing in the first place. The developers still working are part-engineer, part-product manager, part-writer of very precise instructions for very powerful tools. The job changed. Most people’s identity didn’t. That gap is where careers went to die. Salary of an AI developer in 2030.Am I Still a Developer? Genuinely unsure. I write code sometimes. Mostly I review code machines wrote. I design systems. I talk to users. I understand the gap between what someone said they want and what they actually need. But the image I had of myself — someone who sits with a hard technical problem, who takes pride in clean architecture and readable code — that identity is under pressure in 2030. I’ve started calling myself a “systems thinker” on my CV. It’s honest. It’s also a cope. If You’re Reading This in 2025 or 2026 The time to adapt is now. Not when the layoff hits. The gap between “good at coding” and “indispensable to an AI-native team” is wide and widening fast. Cross it deliberately. Here’s what’s actually working for people right now: Learn how to direct agents, not just write code. Prompt quality is the new code quality. Develop product instincts. Understand what users need, not just what they asked for. Get comfortable with ambiguity at the system level. Architecture decisions are still deeply human. Talk to users directly. Empathy is still not a feature the models ship with. Build a public presence. When the market tightens, visibility is leverage. The craft isn’t dead. The craft-only career is. If You’re Reading This in 2030 Hi. You know exactly what I’m talking about. The adjustment is hard. The grief is real. And the fact that you’re still showing up, still figuring it out, still trying to stay useful in a world that keeps moving the goalposts — that matters more than it probably feels like it does right now. The agent in my terminal just finished the feature. It looks pretty good, actually. I’ll review it in the morning. Goodnight from 2030. Still here. Barely. Written by a human, at 11pm, without AI assistance. The irony is not lost on me.~ read more at https://vishalvoid.com

VKS
8 min read
How to Use Indexing in PostgreSQL to Make Your Queries 100x Faster
indexingvishalvoidpostgresql

How to Use Indexing in PostgreSQL to Make Your Queries 100x Faster

Indexing in Postgres.PostgreSQL is one of the most powerful open-source relational databases, but as your dataset grows, queries can become slower. Indexing is a critical optimization technique that helps retrieve data efficiently, reducing query execution time significantly. In this guide, we will explore how indexing works in PostgreSQL with a practical example, using a blogging platform dataset. We’ll measure query performance before and after indexing to understand its impact. Setting Up PostgreSQL Locally Before diving into indexing, let’s set up a PostgreSQL database locally. Use Docker to spin up a PostgreSQL instance: docker run -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword -d postgres Next, connect to the PostgreSQL container: docker exec -it <container_id> /bin/bashpsql -U postgres Creating a Sample Dataset Let’s create a simple blogging platform schema with users and posts tables: CREATE TABLE users ( user_id SERIAL PRIMARY KEY, email VARCHAR(255) UNIQUE NOT NULL, password VARCHAR(255) NOT NULL, name VARCHAR(255)); CREATE TABLE posts ( post_id SERIAL PRIMARY KEY, user_id INTEGER NOT NULL, title VARCHAR(255) NOT NULL, description TEXT, image VARCHAR(255), FOREIGN KEY (user_id) REFERENCES users(user_id)); Now, insert a large dataset to simulate a real-world scenario: DO $$DECLARE returned_user_id INT;BEGIN -- Insert 5 users FOR i IN 1..5 LOOP INSERT INTO users (email, password, name) VALUES ('user'||i||'@example.com', 'pass'||i, 'User '||i) RETURNING user_id INTO returned_user_id; FOR j IN 1..500000 LOOP INSERT INTO posts (user_id, title, description) VALUES (returned_user_id, 'Title '||j, 'Description for post '||j); END LOOP; END LOOP;END $$; This script inserts 5 users and 2.5 million posts, making it a good dataset to test indexing. Measuring Query Performance Without Indexing Now, let’s fetch posts of a specific user and measure execution time: EXPLAIN ANALYZE SELECT * FROM posts WHERE user_id=1 LIMIT 5; Expected Output: Seq Scan on posts (cost=0.00..234567.89 rows=100000 width=123) (actual time=1234.56 ms) The sequential scan (Seq Scan) means PostgreSQL scans the entire posts table to find relevant rows. This takes a long time because no index exists. Adding an Index to Optimize Queries Let’s create an index on user_id to speed up search queries: CREATE INDEX idx_user_id ON posts (user_id); Now, run the same query again: EXPLAIN ANALYZE SELECT * FROM posts WHERE user_id=1 LIMIT 5; Expected Output (With Indexing): Index Scan using idx_user_id on posts (cost=0.42..12345.67 rows=100000 width=123) (actual time=12.34 ms) The execution time drastically reduces from seconds to milliseconds! 🚀 How Indexing Works (Simplified) Indexes work like a book’s index page — instead of scanning the whole book, you quickly find what you need using references. Without Indexing: PostgreSQL scans every row in the table (sequential scan), which is slow for large datasets. With Indexing: A B-tree index is used to store references to table rows efficiently, making searches log(n) time complexity instead of O(n). Visualizing Indexing Without Indexing: [ Data Table ] → Full Table Scan → Slow With Indexing: [ Index B-Tree ] → Direct Lookup → Fast 🚀 Conclusion Indexing significantly improves query performance. It works by storing sorted references to actual data. Use indexing for fields frequently used in WHERE clauses. Too many indexes can slow down INSERT and UPDATE operations, so use them wisely.

VKS
3 min read
TypeScript’s Massive Go Update: The Game-Changer That Makes It 10x Faster
gosoftware-developmenttypescript

TypeScript’s Massive Go Update: The Game-Changer That Makes It 10x Faster

https://medium.com/media/baea89651bc61a49edd90aab9290a96c/hrefFor years, TypeScript has been the go-to language for developers looking to bring static typing and better tooling to JavaScript. It has powered countless large-scale applications, but one common gripe has always been performance — slow compilation times, high memory usage, and sluggish editor responsiveness, especially on massive codebases. Now, Microsoft has completely rewritten the TypeScript compiler in Go, and the results are nothing short of extraordinary — a 10x speed boost, lower memory consumption, and an overall smoother development experience. Let’s break down why this update is a game-changer for developers. Why Move TypeScript to Go? TypeScript has always been written in JavaScript (and later in TypeScript itself). While this approach made it easy to integrate with the existing JavaScript ecosystem, it had its downsides: • Compilation Speed: The TypeScript compiler (tsc) could be painfully slow, especially on large projects. • Memory Consumption: Running a compiler in JavaScript inherently demands more memory than a natively compiled language. • Developer Experience: The slowness of tsc affected real-time editor features like autocomplete, type checking, and navigation, making development sluggish. To solve these issues, Microsoft rewrote the entire TypeScript compiler and tooling in Go, a highly efficient, statically typed language known for its speed and concurrency capabilities. How Much Faster Is It? Microsoft’s benchmarks show that the Go-based TypeScript compiler is up to 10x faster than the previous JavaScript-based version. Here’s why: • Native Execution: Go compiles down to native code, eliminating the overhead of running the compiler in JavaScript. • Concurrency: Go’s built-in concurrency model allows TypeScript to process multiple files in parallel, drastically reducing build times. • Lower Overhead: Go is far more memory-efficient than JavaScript, which means faster performance, especially for large-scale projects. Real-World Impact for Developers For developers working on enterprise-scale applications, this means: ✔ Faster builds — No more waiting several minutes for TypeScript to compile. ✔ More responsive editors — Autocomplete, type checking, and navigation happen almost instantly. ✔ Lower memory usage — Making TypeScript development smoother on less powerful machines. What Else Is Changing? Apart from raw speed improvements, the new TypeScript compiler also brings several architectural changes: 1. Improved Language Server Performance The TypeScript Language Server, which powers features like IntelliSense in VS Code, now runs significantly faster. Developers will experience near-instant feedback when working with TypeScript. 2. Better Tooling & LSP Support With this update, TypeScript improves its integration with the Language Server Protocol (LSP), making it work more efficiently with modern development tools. 3. More Efficient Type Checking TypeScript’s type inference and checking system has been optimized, meaning less unnecessary computation and a snappier experience overall. When Can You Start Using It? The transition to Go is being phased in gradually: • TypeScript 5.8 (released in early 2025) already includes some of these improvements. • TypeScript 5.9 is expected to refine the experience even further. • The full Go-based compiler is set to be the default in TypeScript 7.0. Developers can start testing it right now by using preview builds and checking Microsoft’s official documentation. The Future of TypeScript Is Faster Than Ever This shift marks a major milestone in TypeScript’s evolution. By moving to Go, Microsoft is ensuring that developers no longer have to choose between the benefits of TypeScript and fast build times. The impact of this update will be huge — whether you’re building a massive enterprise application or just want a snappier dev experience, the new TypeScript compiler is set to change the way we write JavaScript forever. Are you excited about this update? Share your thoughts in the comments! Sources: • Visual Studio Magazine • Microsoft TypeScript Blog

VKS
4 min read
Top 10 Must-Know TypeScript Decorators for Developers
top-10decoratorsannotation-for-typescript

Top 10 Must-Know TypeScript Decorators for Developers

TypeScript decorators are powerful tools that allow developers to extend functionality in a clean and reusable way. Whether you’re measuring execution time, implementing throttling, or ensuring methods execute only once, decorators can significantly enhance your workflow. In this blog, we’ll explore ten essential decorators for everyday TypeScript development. 10 Must Know TypeScript DecoratorsInstallation To get started, install the helpful-decorators package: npm install helpful-decorators or yarn add helpful-decorators 1. @delay - Add a Delay to a Method If you need to introduce a delay before executing a function, use @delay. import { delay } from 'helpful-decorators'; class Test { @delay(1000) method() { console.log("Executed after 1 second"); }} 2. @debounce - Prevent Rapid Function Execution Debouncing ensures that a function is called only after a specified delay from the last call. import { debounce } from 'helpful-decorators'; class Test { @debounce(1000) method() { console.log("Executed after 1 second of inactivity"); }} 3. @throttle - Control Execution Frequency Throttle ensures that a function executes at most once in a specified time interval. import { throttle } from 'helpful-decorators'; class Test { @throttle(1000) method() { console.log("Executed at most once per second"); }} 4. @once - Ensure a Method Runs Only Once This decorator prevents a method from executing more than once. import { once } from 'helpful-decorators'; class Test { @once method() { console.log("This will run only once"); }} 5. @measure - Measure Execution Time This is useful for profiling performance. import { measure } from 'helpful-decorators'; class Test { @measure doSomething() { console.log("Measuring execution time"); }} 6. @Mixin - Achieve Multiple Inheritance Allows multiple inheritance in TypeScript. import { Mixin } from 'helpful-decorators'; class Disposable {}class Activatable {} @Mixin([Disposable, Activatable])class Test {} 7. @memo - Cache Function Results Caches results to optimize performance. import { memo } from 'helpful-decorators'; class Test { @memo() method() { return "Memoized Result"; }} 8. @bind - Automatically Bind Methods Ensures this retains the correct context. import { bind } from 'helpful-decorators'; class AppComponent { constructor() { document.body.addEventListener('click', this.onClick); } @bind onClick(event) { console.log(event); }} 9. @SortBy - Sort Arrays Automatically Sorts arrays based on a specific property or type. import { SortBy } from 'helpful-decorators'; class Test { @SortBy('name', { isDescending: false, type: 'string' }) names = [ { name: 'b' }, { name: 'a' }, { name: 'c' } ];} 10. @Log - Log Method Calls (Custom Decorator Example) This decorator logs function calls for debugging. function Log(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { console.log(`Method ${propertyKey} called with args:`, args); return originalMethod.apply(this, args); }; return descriptor;} class Test { @Log sayHello(name: string) { return `Hello, ${name}`; }} Conclusion Using decorators in TypeScript helps simplify complex logic, improves readability, and enhances maintainability. These ten decorators can significantly improve your daily workflow, whether you’re dealing with performance optimization, event handling, or debugging. Happy coding!

VKS
3 min read
Solving “SwaggerUIBundle is not defined” Error in Express with Swagger.
swaggerswagger-uidocumentation-tool

Solving “SwaggerUIBundle is not defined” Error in Express with Swagger.

Let me walk through how to solve the common “Uncaught ReferenceError: SwaggerUIBundle is not defined at window.onload” error that coours when setting up Swagger documentation in an Express application, especially in a Turborepo Environment. Understanding the Problem. The main issue was that swagger-ui-express wasn’t properly serving the UI files, likely due to conflicts with the bundler (Webpack in this Turborepo setup). This resulted in a blank page with the error: “Uncaught ReferenceError: SwaggerUIBundle is not defined at window.onload”. Solution Approach — Serve Swagger UI Locally Instread of relying on “Swagger-ui-express”, I decided to : Download Swagger UI files directly to the project. Serve them as static files. Configure them to use our generated swagger specification. Let me show you the implementation: Step 1: Download Swagger UI Files At first I will download the Swagger CSS, SwaggerUIBundle and other required files. for that : Run the following commands in your project terminal to fetch the required Swagger UI files: # Remove duplicate public folders if they exist rm -rf /Users/vishal/Developer/PMS/PMS/apps/http/src/public# Ensure the correct public folder existsmkdir -p /Users/vishal/Developer/PMS/PMS/apps/http/public/swagger-ui# Download Swagger UI files to the correct locationcd /Users/vishal/Developer/PMS/PMS/apps/http/public/swagger-ui# Download required Swagger UI filescurl -O https://cdn.jsdelivr.net/npm/swagger-ui-dist/swagger-ui.csscurl -O https://cdn.jsdelivr.net/npm/swagger-ui-dist/swagger-ui-bundle.jscurl -O https://cdn.jsdelivr.net/npm/swagger-ui-dist/swagger-ui-standalone-preset.jscurl -O https://cdn.jsdelivr.net/npm/swagger-ui-dist/favicon-32x32.pngcurl -O https://cdn.jsdelivr.net/npm/swagger-ui-dist/favicon-16x16.png Step 2: Configure Express to Serve Swagger UI Modify your index.ts file to serve Swagger UI from the local files instead of using swagger-ui-express. index.ts import dotenv from 'dotenv';dotenv.config();import express from 'express';import cookieParser from 'cookie-parser';import path from 'path';import { router } from './routes/v1';import { config } from './config/config';import { setupSwagger } from './config/swagger';const app = express();app.use(express.json());app.use(cookieParser());// Serve static files from the public directoryapp.use(express.static(path.join(__dirname, 'public')));// Serve Swagger UI filesapp.use('/swagger-ui', express.static(path.join(__dirname, '../public/swagger-ui')));// Setup SwaggersetupSwagger(app);// API routesapp.use('/api/v1', router);app.listen(config.get('port'), () => { console.log(`Server is running on port ${config.get('port')}`); console.log(`Swagger documentation available at http://localhost:${config.get('port')}/api-docs`);}); Step 3: Generate Swagger Documentation Modify your swagger.ts file to generate and serve the Swagger JSON file. swagger.ts import { Express } from 'express';import swaggerJsdoc from 'swagger-jsdoc';const options = { definition: { openapi: '3.0.0', info: { title: 'PMS API Documentation', version: '1.0.0', description: 'Project Management System API Documentation', }, servers: [ { url: 'http://localhost:3000/api/v1', }, ], components: { securitySchemes: { bearerAuth: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT', }, }, }, security: [ { bearerAuth: [], }, ], }, apis: ['./src/routes/**/*.ts'],};const swaggerSpec = swaggerJsdoc(options);export const setupSwagger = (app: Express) => { // Serve swagger.json app.get('/api-docs/swagger.json', (_, res) => { res.setHeader('Content-Type', 'application/json'); res.send(swaggerSpec); }); // Redirect /api-docs to the Swagger UI app.get('/api-docs', (_, res) => { res.redirect('/swagger-ui/'); });}; Step 4: Verify Your Swagger Documentation Start your Express server: npm start 2. Open your browser and visit: http://localhost:3000/api-docs 3. This should redirect you to http://localhost:3000/swagger-ui/, where your API documentation will be displayed. also running the previous commands should should generate a swagger-output.json file in the root project directory. Important : for proper generation of swagger-documentation openapi-spec for every route is must. 2. Serve them as static files 3. Configure them to use our generated swagger specification

VKS
3 min read
Are You a Beginner in Programming ? Start Here
beginnertipsdeveloper

Are You a Beginner in Programming ? Start Here

Are You a Beginner in Programming ? Start Here suggestion from a beginner to another beginner. Episode 1 of 8 Are you new to the tech space? Do Big words like AI, ML, and IoT sound like a foreign language? Does that idea of coding terrify you? Fear not, my friend! You’re not alone. Jumping into the tech world can be super-duper scary, especially if you’re not a techy-wiz. But guess what? It’s not as tough as building a rocket ship to the moon. If you’re doing that, well, good luck! As someone who has been in the tech industry for a while now, let me share some tips and tricks that I wish I knew when I was starting out. First things first, don’t be afraid to ask questions. Seriously, no one knows everything, and everyone has had to start somewhere. If you’re not sure what something means, ask! It’s better to ask a ‘silly’ question than to pretend you know what you’re talking about and end up in a confusing mess. For example, when I first started out, I thought AI stood for ‘Artificial Idiocy’ because I had no idea what it actually meant. Needless to say, I was quickly corrected by my friends, but it was a good learning moment. Another thing to keep in mind is that the tech industry moves fast. Really fast. What’s cool and cutting-edge today may be obsolete tomorrow. So, don’t get too attached to any particular technology or framework. Stay open-minded and willing to learn new things. As the great Albert Einstein once said, ‘Intellectual growth should commence at birth and cease only at death.’ So, keep learning and growing. But, don’t forget to take breaks and have fun too! The tech industry can be a bit… intense, at times. So, take a breather and do something that you enjoy. Whether it’s playing video games, hiking, or binge-watching your favorite TV show, make sure to take care of yourself.And, finally, remember that you’re not alone. There’s a whole community of people out there who are willing to help and support you. From online forums and meetups to Slack channels and Twitter, there are plenty of ways to connect with like-minded folks. So, don’t be afraid to reach out and say hi! Who knows, you may just make some lifelong friends along the way. In conclusion, the tech space can be intimidating, but it doesn’t have to be. With an open mind, a willingness to learn, and a sense of humor, you’ll be well on your way to success. Just remember to ask questions, take breaks, and connect with others. And, most importantly, have fun! Now, if you’ll excuse me, I’m off to refactor some code. Happy coding! Source: Visit website for further updates and continuation of this blog.Source : https://vishalvoid.com (my personal portfolio)

VKS
3 min read

Final Arc · Connect

Let's build together

Pick the channel that fits best — every link stays in sync with my latest work.

Prefer a direct line?

Email lands straight in my inbox. Resume is always up to date.