24 essays, newest first
Writing
Production mistakes, AI product judgment, open source, and the occasional note for students.
I write when something broke in an interesting way, when I changed my mind about something, or when I've explained the same thing to three people and would rather send a link.
If you only read a few
Four to start with, in the order I’d hand them to you.
- 1I Shipped a Race Condition That Oversold Stock (And Other War Stories)Bugs I shipped in a retail system and an AI pipeline, and the fixes that held.Apr 8, 2026
- 2LLMs Can't Save Bad UXWhy most AI features that flop were product decisions first.Apr 8, 2026
- 3The Best Way to Learn a Codebase Is to Break Someone Else'sWhat maintainers taught me by explaining why my fix was wrong.Apr 8, 2026
- 4Agent Middleware: What Kept Obelisk's Agents in LineThe control layer that made fifteen-odd agents manageable.Apr 8, 2026
All writing
Filter by topic, or just scroll.
- kitty's Parallel Test Runner Said OK While Its Workers CrashedOct 6, 2026 · 9 min readA missing addSubTest and an ignored exit status let kitty's new parallel test runner report success after failures. Fixing that exposed seven segfaulting workers on my Mac, and Kovid Goyal fixed those his own way.
- Taking Obelisk's Backend Deploy From 54 Minutes to 32Oct 6, 2026 · 10 min readOur backend deploys had crept up to almost an hour. Docker was fine. Most of the time went to migration tests waiting on one Postgres advisory lock, and to five Cloud Run services promoted one at a time.
- PgBouncer Transaction Pooling Broke Row-Level Security in PolarisOct 6, 2026 · 9 min readI put PgBouncer in front of Postgres to stop a login outage. Two weeks later customer search started returning empty lists on some requests, because tenant isolation depended on a session variable and transaction pooling doesn't keep sessions.
- Moving SMS Realtime Off Postgres Polling and Onto Redis StreamsOct 6, 2026 · 9 min readA Django app whose SSE endpoints polled Postgres from sleeping request threads, and the outbox, relay and Redis Streams setup that replaced them in March 2026.
- An SMS Queue That Wouldn't Drain, and the DynamoDB Row Every Send RewroteOct 6, 2026 · 9 min readIn September 2026 an SMS backlog on AWS drained at four or five messages a minute, and a few weeks later adding workers stopped making sends faster. How I drained the queue by hand, and the DynamoDB items every send was rewriting.
- The Best Way to Learn a Codebase Is to Break Someone Else'sApr 8, 2026 · 4 min readWhat maintainers of kitty, calibre, libtorrent and Fallow taught me in review threads, usually by explaining why my fix was wrong in a way I hadn't considered.
- Every Abstraction I RegretApr 8, 2026 · 6 min readA short list of abstractions I added too early, why they got worse over time, and the heuristics I use now to avoid repeating it.
- How Fallow Analyzes TypeScript in Under a SecondApr 8, 2026 · 5 min readHow Fallow gets dead-code and dependency analysis done fast by skipping the TypeScript compiler, flattening graph storage, and doing the work in Rust.
- Scoring Fraud in Legal Intake CallsApr 8, 2026 · 4 min readCoached callers, invented doctors and borrowed photos. How RISQ scores intake calls for mass tort firms, and why the most useful score is the one that grades the interviewer.
- How Pyscn Analyzes Python with Go and tree-sitterApr 8, 2026 · 4 min readHow Pyscn uses Go and tree-sitter to analyze Python code quickly for dead code, clone detection, and dependency insight.
- Agent Middleware: What Kept Obelisk's Agents in LineApr 8, 2026 · 5 min readObelisk runs more than fifteen specialist agents. Model choice, context, cost, retries and approvals all ended up in a middleware layer around them, and this is how that layer works.
- LLMs Can't Save Bad UXApr 8, 2026 · 6 min readWhen an AI feature flops, look at the UX before you blame the model. Three features I watched fail, what fixed them, and the questions I now ask before anyone writes a prompt.
- Most of My Pull Requests Started as an AnnoyanceApr 8, 2026 · 3 min readDrive-by fixes in qBittorrent, Dokploy and django-hijack: which ones merged, which didn't, and what the rejections taught me about scope.
- Structured Logging for AI DebuggingApr 8, 2026 · 4 min readLogging one structured event per request with evlog, so an AI assistant can follow what happened in a request.
- TF-IDF in OCaml: When Functional Programming ClicksApr 8, 2026 · 5 min readBuilding a local code search engine in OCaml was a good excuse to learn TF-IDF, pure pipelines, and where immutability helps.
- I Shipped a Race Condition That Oversold Stock (And Other War Stories)Apr 8, 2026 · 4 min readTwo cashiers selling the last item, a chain that returned nothing, and a lock that only worked when both requests hit the same process. Bugs I shipped, and the small fixes that held.
- LangChain in Production: What the Tutorials Leave OutFeb 1, 2026 · 3 min readWhere LangChain is worth using, where it gets in the way, and the defaults that stop our AI features failing silently: timeouts, validation, persistent state, tracing and pinned versions.
- Free Web Dev Platforms Worth Your TimeApr 1, 2025 · 2 min readA practical shortlist of free web development learning platforms and how to use them without getting stuck in tutorials.
- Final Year Project (FYP) Guide for StudentsFeb 17, 2025 · 14 min readA practical final year project guide for choosing scope, building steadily, avoiding weak ideas, and presenting work clearly.
- What It Costs to Run mhassan.dev: $8/yearFeb 15, 2025 · 3 min readThe full cost of running this site, what's free, and the tradeoffs behind each choice.
- The Invoice Page That Took 4 Seconds to SearchFeb 12, 2025 · 2 min readHow preloading product data cut search latency from 4 seconds to instant on a POS invoice page, and when this pattern breaks down.
- When to Extract a Component (and When to Just Copy-Paste)Feb 12, 2025 · 3 min readThe 3-usage-sites heuristic for component extraction, a premature ConfirmDialog that cost me time, and why copy-paste is sometimes the right call in Vue.
- Polaris Performance Log: The Django Mistakes I Made FirstFeb 10, 2025 · 4 min readRefunds that queried once per line item, stock updated one row at a time, and signals that recalculated ledgers nobody asked about. What I changed in Polaris, and what I'd tell myself earlier.