RSSAmplifier

Blog

Lorbic

Recent content on Lorbic

lorbic.comRSS feed ↗99 posts

Latest posts

How Go Channels Actually Work

A single unbuffered channel send without an active receiver is enough to silently lock up a production worker pool, leaking memory until your service gets killed by the OS kernel. On the surface, Go channels look simple: they synchronize concurrent execution without manual mutex management. But under heavy load, a minor oversight in channel sizing or worker coordination blocks the scheduler, leaks…

Part 6: Simulating a Living Facility: Room Derivation, Sunlight Spillover, and Positional SFX

Generating a raw matrix of integer tiles gives you a map layout, but it doesn’t give you a living environment. When I loaded my first level into Derelict Facility , the engine had no concept of what a “Laboratory” or a “Reactor Room” was. It just saw a flat array of walls and floors. If a player flipped a power terminal inside a room, I had no clean way to know which…

Designing a Distributed Job Scheduler in Go: Partitioning, Locking, and Backpressure

Linux crontab is one of the most elegant pieces of software ever written for single-host automation. It is simple, clear, and has kept Unix systems running reliably since 1975. The problem starts when we take a single-host tool and deploy it across a multi-node cloud setup. In Relay , a multi-tenant AI API gateway system design, background jobs power core operations: every top of the hour, a job…

Part 5: From Terminal Cells to Sprite Maps: Font Fallbacks and Auto-Tiling

Building a terminal-based engine in pure ASCII looks cool for about five minutes. Then you try rendering a complex facility map with corners, T-junctions, and status icons, and raw character cells start feeling incredibly limiting. Two specific problems hit me immediately when I tried switching to Raylib for graphics. First, drawing wall tiles manually by hand in level files meant placing 16…

Part 4: Refactoring to SoA ECS: Bitmasks and Flat Component Arrays

When I started building Derelict Facility , my initial instinct for game actors was standard Object-Oriented design: create an Entity struct, add pointers for position, sprite, and stats, and store them in a slice ( []*Entity ). It worked fine for five entities. But as soon as I added automated doors, save terminals, and active power grids across a 1000-tile map, keeping track of separate heap…

Designing a Usage-Based Billing Pipeline for SaaS

In How Multi-Tenant SaaS Actually Works , I left one major promise unfulfilled at the end: “Billing is an entire system design on its own. The billing pipeline gets its own post.”

Couchbase Index Best Practices and Query Performance Tuning

Most Couchbase performance tickets I have seen end the same way: someone adds more nodes, the dashboard looks a little better for a week, and the same query shows up in the slow log a month later. The node count was never the problem. The index was. This is a working reference, not an essay. I already wrote the reflective version of what indexing in Couchbase teaches you about systems in general.…

API Design for Backend Systems

A few weeks ago I designed Relay , a multi-tenant AI API gateway, as a system design exercise. That post covered the database, the auth, the billing. It did not cover the thing every one of those systems is sitting behind: the API itself. Here is the question that post left open. When someone builds GET /v1/requests to list a tenant’s API call history, what should that endpoint actually look…

Cache-Driven Development: Saving Your Database From Itself

There is a moment in every backend engineer’s life when their database starts refusing connections. Picture 2 a.m. on a Tuesday. The app is operating under normal traffic, nothing unusual. But the database connection pool is saturated. Queries are timing out. The monitoring dashboard shows 50,000 database operations per second, far beyond what the system should be handling. When someone…

Designing a Distributed Rate Limiter with Redis

There is a class of bugs that only happen at midnight. Your API has a rate limit: 1000 requests per minute. A client hits 999 at 11:59:59 PM, then fires another 999 at 12:00:00 AM. Two windows, two clean counters, all 1998 requests allowed. Your database gets a spike it was never designed to handle, and you spend the next hour wondering how your rate limiter let this through. It did let it…

How Multi-Tenant SaaS Actually Works

For the past month I have been reading about multi-tenant SaaS architecture. Not as an academic exercise. I kept running into the same questions on every project I looked at: where exactly does tenant data go, how do you stop one customer’s bug from becoming every customer’s problem, how does billing actually work at the database level. The blog posts I found were either too abstract…

Nobody Will Read This

There is a funny truth in software engineering: almost nobody reads the docs. We spend hours writing careful comments in our code. We build personal websites. We write plain text files and push them to live servers. But if we check the stats, we know the truth. The audience is basically zero. So why do we do it? My day is full of loud noise. It is filled with heavy backend logic, endless tasks,…

What is DRY? (And Other Things We Say at 3 AM)

There is a famous programmer joke that always gets me: “What is DRY? Well, at the risk of repeating myself…” It is funny, but it also hurts a little because it is so true. We all know the rule: Don’t Repeat Yourself (DRY). We learn it from day one. You write a piece of code once, put it in a clean function, and never type it again. But let’s be honest. It is the…

So, We Are Writing Efficient Software Again

I wanted to upgrade the RAM in my PC. Nothing fancy. I bought 32GB in 2024 and I wanted to double it. I opened a tab, checked the price, and closed the tab. Then I sat quietly for a moment. The same 32GB kit I bought in 2024 now costs more than double. DDR5 prices have gone up roughly 400% since mid-2025 [1]. DDR4 is not much better. A kit that cost $60–$90 in late 2025 now sells for $150–$180…

Constructing Concurrent Inverted Indexes in Go

I spent a Saturday afternoon benchmarking a concurrent inverted index and discovered that a single sync.RWMutex starts to break down at roughly 4 concurrent readers. The degradation is not linear. It is not graceful. It is a cliff. The inverted index is one of the oldest data structures in information retrieval. It maps terms to the documents that contain them, forming the backbone of every search…

A Love Letter to the L1 Cache

I recently spent four hours staring at a benchmark that didn’t make sense. It started while working on Derelict Facility , my grid-based game engine in Go. I was trying to tighten the main update loop, specifically the part that iterates over every entity on the map each frame. I pulled out a small benchmark to isolate the cost, and something looked wrong. I had two Go structs. They held the…

Wireless ADB When Your Network Fights You

Wireless ADB keeps timing out if you run a VPN or something like Cloudflare WARP. The issue is that these tools route all traffic through a tunnel and block direct peer-to-peer connections on your local network. The fix is a one-time USB handshake to tell the device to listen on TCP before you go wireless. Step 1: USB handshake Connect your device via USB (USB debugging must be on). Then run:

Privacy & Terms

This is a personal blog. I’m not a company and I don’t have a legal team. Here is how this site actually works. Your data I don’t collect it, I don’t sell it, and I don’t want it. If you leave a comment or send me an email, I get your name and email address. I use it to reply to you. Nothing else. If you subscribe to the newsletter, your email goes to my mailing list…

Why Explaining Technical Difficulty is Hard

“Can we just add a real-time visitor counter to the homepage? It’s just a query, right”? Every engineer has heard some variation of this. On the surface, the logic is sound. You have data, you have a UI, and you want to connect them. In the world of business requirements, this is a solved problem. You write a line of code, and the feature exists. But your database doesn’t…

Just About Go Time

Time is an illusion. Or more accurately, time is a political consensus poorly masquerading as physics. If you’ve ever seen Dylan Beattie’s “Plain Text” talk , you know that humans have spent centuries making data storage as complicated as possible. But text encoding has nothing on time zones. As engineers, we like to pretend that time.Now() returns an objective truth. It…

Building a Poor Document Store inside PostgreSQL

The marketing for “schemaless” architecture was brilliant. It promised speed, agility, and a life free from the tyranny of ALTER TABLE migrations. When PostgreSQL introduced JSONB in version 9.4, many developers saw it as a green light to treat Postgres like MongoDB. I’ve seen this pattern in dozens of codebases. It starts with a single metadata column, but within months, the entire…

Bitmask Golf

Initialising diagnostic probes... How to play Use the bitwise operators to transform the Current bit pattern into the Target pattern. Every operation costs 1 “Clock Cycle”. Try to hit the Par (the optimal number of moves).

Dependency Defuser

Initialising diagnostic probes... How to play Place one Agent (👑) in each row, column, and colored subnet. Agents cannot touch each other, even diagonally. Click once for Agent, twice for Blocker (✕), and thrice to clear.

PostgreSQL Migrations in Go: Production Schema Patterns with Goose

Application code is stateless. You can tear down a container and spin up a new one in milliseconds without losing data. Databases are stateful. When you deploy new application logic that requires a new column, an index, or a table, you must transition the physical storage schema from state A to state B without destroying the underlying data or locking the system. This process is a database…

Migrating Cloudflare to Terraform

A while back, I was tinkering in the Cloudflare dashboard and accidentally fat-fingered a DNS configuration. I didn’t realize the impact immediately, but I ended up taking down lorbic.com for an hour. When I scrambled to fix it, I hit a wall: there was no “undo” button. There was no Git history to tell me what the record used to point to, and no review to catch the mistake before…

Internet Graveyard

Filter by Era/Domain: All Records Frameworks Hardware Infrastructure Protocols & Standards Services Social Google Reader 2005 - 2013 Services Cause of Death Strategic shift towards Google ; lack of direct monetization. Proved that RSS was for power users, not the masses.

Critical Rendering Path Optimization: 8 Proven Strategies to Boost Web Performance

TL;DR: The Critical Rendering Path (CRP) is how browsers convert code into pixels. Optimizing it means reducing bottlenecks at five stages: Network, Parsing, Tree Building, Layout, and Paint. Use this guide to reduce First Contentful Paint by 40-60%, improve Lighthouse scores, and master the eight optimization strategies that separate fast sites from slow ones. To master web performance, stop…

A Tale of Web Vitals

TL;DR: I achieved 95+ Lighthouse scores by removing abstractions and automating browser fundamentals. This guide details how to solve LCP network discovery , main thread congestion , and third-party accessibility traps using Hugo pipelines and vanilla JavaScript. “Why is the LCP 4.2 seconds? It’s just a static site”. I was staring at a Lighthouse report that felt like an insult.…

Why Your Goroutines Need a Speed Limit: Bounded Concurrency in Go

TL;DR: Spawning go func() without a limiter is a recipe for system collapse. This guide details how to use Semaphores and Worker Pools to prioritize predictable stability over absolute speed, protecting downstream dependencies from the thundering herd. It’s a rite of passage for every Go developer. You receive a list of 10,000 URLs to fetch or 50,000 rows to process. You wrap the workload in…

Part 3: Casting Shadows Without Trigonometry: The Beauty of Integer Math

At the end of generating a procedural map for the Derelict Facility engine, I had a sprawling interconnected maze of rooms and corridors. But there was a devastating problem: I could see everything. The entire map was rendered at once. It looked like a top-down blueprint, not a dark, atmospheric facility. I needed to implement Fog of War. I needed to treat the player character like a lighthouse in…

Part 2: Decoupling the Renderer: Terminal to Raylib in One Interface

The biggest architectural mistake you can make when building a game engine is letting the game know how it is being drawn. When I started building the Derelict Facility engine, the output target was a raw ANSI terminal. The engine calculated A* paths, resolved line-of-sight, and then spewed escape codes ( \033[31m ) to os.Stdout . Eventually, I hit the physical limits of terminal emulators:…

Part 1: Data-Oriented Design in Go: Why [][]Tile Destroyed My Game Engine

Most game development stories start the same way: install Unity, drag some sprites onto a canvas, and press Play. I wanted to understand the metal. I set out to build Derelict Facility , a systems-level game engine from scratch in pure Go. No SDL, no OpenGL wrappers, no Ebiten. The goal wasn’t just to ship a game; the goal was to learn the memory layouts and I/O pipelines that modern engines…

A Deep Dive into Apache Parquet with ClickHouse

TIL how ClickHouse works with Parquet beyond just reading files. Part 1: https://clickhouse.com/blog/apache-parquet-clickhouse-local-querying-writing You can query and even write Parquet files directly using ClickHouse, without fully importing them first. This changes how you think about data movement and storage. Part 2:…

10 years of lorbic.com architecture

This post tracks four architectural rewrites of my personal site over ten years: moving from managed platforms (Blogger) to dynamic backends (Django), static site generators (Jekyll/Hugo), and finally to a custom, zero-dependency architecture built for absolute control and performance. Technical Context For an engineer, a personal site is the only project where you have absolute authority over the…

My Reading List

All Analytics Backend Database Design DevOps General Hacking Hardcore Linux Design Knitting Bullshit by Kate Davies Kate Davies' blog.

Kubernetes on WSL2 and the macOS tunnel

TL;DR: I run k3s on a Windows gaming PC via WSL2 to master Kubernetes networking without cloud costs. This guide details a secure access model using SSH and kubectl port-forward to bypass NAT boundaries and maintain technical sovereignty. This guide omits Kubernetes feature tutorials. Instead, it details how to architect an environment where Kubernetes can exist without auxiliary hardware, idle…

ClickHouse data masking with regex

If you’re running a production observability stack, you’ve already leaked PII. An engineer forgot to redact an email in a log line, or a JWT token ended up in a stack trace. In most databases, the only fix is to DELETE the data—killing your metrics along with the sensitive info. But ClickHouse has a more elegant approach: Data Masking Policies . By defining a policy at the role level,…

Understanding CPU Caches in Go

When you’re building Go services that handle millions of operations per second, the hardware beneath your abstractions starts to matter. Specifically, the CPU cache hierarchy, and whether your data fits in it. The Hardware Context: It’s Not Just “RAM” Your server has 32GB or 64GB of RAM, but the CPU avoids touching it whenever possible. Instead, it works through a chain of…

Typography in ten minutes

This blog teaches almost all about typography. Read more: https://practicaltypography.com/

ClickHouse vs. Postgres: When to Move Your Logs Out of a Relational DB

Postgres is the most reliable tool in my stack. It handles users, configurations, and complex relations without breaking a sweat. But databases, like any physical system, have a “design limit”. For Postgres, that limit usually appears when you try to use it as a dumping ground for high-velocity logs and metrics. When your ANALYZE commands start taking minutes and your indexes consume…

WSL2 Is Slow? Fix /mnt/c/ File System Performance & Go Latency

WSL2 (Windows Subsystem for Linux) has been a godsend for developers who love Linux tools but need/have a Windows environment. But for Go developers, WSL2 isn’t just a “transparent layer”. If configured incorrectly, it becomes the bottleneck that can slow down builds by 3x and introduce mysterious latency in networked services. This isn’t a failure of WSL2; it’s a…

What is a Mutex?

Read more: https://nrecursions.blogspot.com/2014/08/mutex-tutorial-and-example.html

AI Coding in 2026: Productivity Multipliers vs. Skill Replacements

“Write a REST API with authentication”. I hit enter. Thirty seconds later, Claude spat out 400 lines of perfectly formatted Go code. JWT middleware, password hashing, error handling, even rate limiting. It looked professional. It looked production-ready. It took me three hours to figure out why the token refresh logic had a race condition. This is AI-assisted coding in 2026. It’s…

Fast Docker CI: Stop Rebuilding Container Images on Every Commit

I used to rebuild my Docker image every time I fixed a typo. A one-line change meant waiting 2-3 minutes for Docker to rebuild layers, reinstall dependencies, and restart the container. I thought this was just the cost of containerized development. Then I discovered runtime containers. Same isolated environment, same reproducibility, but code changes reflect instantly. No rebuilds. No waiting. The…

Python Background Workers: Architecture, Queues, and Retry Strategies

I thought processing audio in the background was simple: spawn a thread, run the script, save the file. Then I hit 200 concurrent requests, and it failed epically. The CPU spiked to full usage because of pydub’s processing. The TTS API didn’t rate-limit me but, it was horribly slow. Then the jobs started failing. Half the jobs died silently. The other half wrote corrupted files because…

Go Struct Field Alignment: How Memory Padding Wastes Your RAM

You write a struct to represent a database entity. Maybe 10 fields, maybe 20. What could possibly go wrong? Nothing, according to your tests. But somewhere in production, your heap is 30% larger than it should be, your Garbage Collector is working overtime, and your L1 cache is not used properly. The reason? Invisible padding bytes silently inflating every instance of your struct. This is the…

I Added Session Management to Aider

I’ve been using aider as my primary AI coding assistant for a while now. It’s the one tool that actually fits my workflow: terminal-based, Git-native, and it works directly on my local files. No copy-pasting into web forms. No context windows that forget everything. And not waiting for agents to keep thinking. But it was missing one thing that drove me crazy. The Problem: Context…

Can ClickHouse Replace Vector Databases? HNSW, Benchmarks & SQL Setup

Everyone’s building AI apps now. And every AI app needs a place to stash embeddings. The instant your data grows beyond “fits in memory”, you need a vector database. Or do you? If you’re already running ClickHouse for analytics, here’s some good news: you might not need another database. ClickHouse can hold its own as a vector store. Not because it was built for it,…

Memory Mechanics In Go - Stack vs Heap

We often talk about “fast” code in terms of Big O notation or algorithmic complexity. But in systems programming languages like Go, “fast” is often a function of where your data lives in memory. When optimizing for high throughput, efficient loops and database indexes are only part of the story. Eventually, you have to talk about the Stack and the Heap. Understanding the…

OLTP vs OLAP - Why You Need Two Databases

At a recent ClickHouse conference in New Delhi, I attended this Saturday. There were many interesting sessions, but one that stood out was a talk on multi-tenant analytics at scale. I was reminded of a fundamental truth in backend engineering: “The database that runs your app cannot be the database that analyzes your app”. Early in a startup’s life, we shove everything into one…