Legacy Surgery
Debugging and modernizing a profitable 20-year classic-ASP SaaS without a rewrite. Real production bugs, the data that hid them, and the payment rails that could not go down while we operated.
46 posts · ~196 min total reading
-
Every migration batch found a nuance nobody predicted
-
Migrating thousands of customer domains to a layer above the server
-
The Whole Feature Was Built and Verified in Sandbox, Then Prod Said E00044: CIM Not Enabled
-
It Looked Exactly Like a Bot Swarm. It Was SQL Server Parameter Sniffing.
-
The Ambient-Global Bug: When "Current Account" Is a Mutable Global Your Whole App Reads
-
The bot swarm that turned out to be one bad query plan
-
314 broken stats pages and one bad cursor
-
The exit survey that overwrote a live mailer
-
The Button Clicked and Nothing Happened: IIS Ate My JSON Error and Handed Back HTML
-
An Index Seek Can Still Read Far More Than You Expect
-
The IPv6 fix bit back: how localhost resolving to ::1 quietly broke a three-hop proxy chain
-
The reuse story died, so I shipped a new cart instead
-
Avoid Unnecessary Date String Round Trips
-
Your JIRA Session Won't Cross Into an Iframe. Here's the Reused-Popup Workaround.
-
Single-currency database, dual-currency checkout: adding CAD without a schema change
-
The fix that ran on every request
-
I had to stop letting the package tier pretend it was the product
-
A 25-Second Admin Screen Meant We Trusted the Wrong Query
-
The bug wasn't the upload, it was the URL contract
-
The bug wasn't the upload, it was the URL contract
-
The Bug Was Not in the Mobile UI
-
The call was coming from inside the house
-
Classic ASP Doesn't Care That It's a Comment: The Script-Delimiter Collision
-
Why schedules broke around March 4, 1973: a getTime() digit-count sort bug
-
I Almost Built an Entitlement System for a Feature That Was Already a Page
-
The Banner Wasn't a Safari Bug, It Was an Empty Frame
-
The Page Was Performing a Ceremony, Not a Job
-
The CSS Bug That Was Actually a Delete Bug
-
The new door was already in the building
-
The feature was fine. First-time state was the real bug.
-
A 47,490-line JavaScript file and what it tells you about a profitable legacy app
-
Hand-rolled hydration: passing server state to the browser with no framework
-
A New Feature Is the Best Fuzz-Tester for Your Existing Data Model
-
Carry Your State in the URL, Then Actually Carry It: The Dropped Query Param
-
A Client Tree-Walk That Was Really a Server Business Rule
-
The Duplicated-Derivation Bug: One Fragile Expression in Four Queries
-
'Newest First' Is a Re-Priority Problem, Not an ORDER BY
-
Shipping a Whole Analytics Suite Into a Legacy ASP Admin
-
clipboard.js Named Its Global 'Clipboard'. So Did the Browser. Boom.
-
A fluent DOM builder for legacy ASP: modernize without a rewrite
-
Server-Side JavaScript on Classic ASP in 2026: Prototype Pages and the DB Helper Pattern
-
Stripe Needs a Post-Back, Authorize.Net Doesn't: One Page, Two Flow Shapes
-
Shipping a Throwaway Relay Page to Debug a Payment Integration in Prod
-
A Trusted Gateway POST Is Still a Public Endpoint
-
x_trans_id Is Not Your Invoice Number: An Authorize.Net Direct-Post Bug
-
N Drifting Copies Share One Bug: The Legacy Consolidation Thesis