The Drift Log · Audit, then actually repair
Extracting Pure Primitives from Tangled Monoliths
4 September 2026 · 3 min read · 569 words · established

Shrink refactoring blast radius by carving pure, deterministic business logic out of I/O-heavy monolithic controllers before attempting major rewrites.
Most code audits end in a PDF that nobody reads or a backlog of Jira tickets labeled "technical debt" that nobody touches.
The audit identifies fifty coupling violations across a monolithic billing module. The proposed remediation is an architectural overhaul: decouple the database layer, extract a service, and introduce event queues. Because that rewrite carries a four-month timeline and substantial regression risk, leadership shelves it. The audit produces expense without repair.
The failure is not the diagnostic; it is the blast radius of the proposed fix.
When refactoring legacy code, attempting to untangle an entire subsystem at once invites merge conflicts, broken edge cases, and reviewer paralysis. To turn an audit into merged code, you must shrink the blast radius. You do not rewrite the module. You carve isolated, pure primitives out of the messy file.
The Trapped Calculation
Most tangled files are not uniform sludge. They are usually composed of loose glue code wrapping a few dense, critical business calculations. The database queries, HTTP handlers, and state mutations obscure the actual logic, but the logic is there.
Consider a typical 400-line controller method handling subscription changes. It fetches user records, queries billing tables, calculates proration fees, updates Stripe, writes three database records, and dispatches two transactional emails.
When a bug occurs in the proration math, engineers fear fixing it because the calculation is fused to the I/O.
// Buried inside a 400-line controller
async function changePlan(userId: string, newPlanId: string) {
const user = await db.users.find(userId);
const currentPlan = await db.plans.find(user.planId);
const newPlan = await db.plans.find(newPlanId);
// 30 lines of date math and tier delta logic mixed with db fields
const daysLeft = Math.ceil((user.periodEnd.getTime() - Date.now()) / (1000 * 60 * 60 * 24));
const dailyRate = currentPlan.priceCents / 30;
const refundAmount = Math.max(0, Math.floor(daysLeft * dailyRate));
const chargeAmount = Math.max(0, newPlan.priceCents - refundAmount);
await stripe.charges.create({ amount: chargeAmount, customer: user.stripeId });
await db.subscriptions.update({ userId, planId: newPlanId });
// ...
}
The repair here is not to replace the billing pipeline with an event-driven architecture. The repair is to extract the date and tier arithmetic into a single-purpose, pure primitive with zero external dependencies.
// Extracted primitive: pure, deterministic, zero I/O
export function calculateProrationDelta(
currentPriceCents: number,
newPriceCents: number,
periodEndMs: number,
nowMs: number,
billingCycleDays: number = 30
): { refundCents: number; chargeCents: number } {
if (periodEndMs <= nowMs) {
return { refundCents: 0, chargeCents: newPriceCents };
}
const daysRemaining = Math.ceil((periodEndMs - nowMs) / (1000 * 60 * 60 * 24));
const dailyRate = currentPriceCents / billingCycleDays;
const refundCents = Math.max(0, Math.floor(daysRemaining * dailyRate));
const chargeCents = Math.max(0, newPriceCents - refundCents);
return { refundCents, chargeCents };
}
Why Small Extractions Merge
This extraction does not fix the monolithic controller, but it permanently improves the code health of that boundary.
- Deterministic verification: The new function takes primitive numbers and returns primitive numbers. It has no network handles, no mocks, and no database state. You can exercise every boundary condition in a test harness in milliseconds.
- Trivial code review: A PR that adds an isolated mathematical function with unit tests and replaces ten inline lines in a controller takes five minutes to review. The blast radius is visible at a glance.
- Permanent asset creation: Once extracted, that logic is no longer legacy code. It is an owned, deterministic component that can be moved anywhere when the broader architectural rewrite finally happens.
Repositories do not get clean through heroic rewrites. They get clean when teams routinely harvest pure logic out of tangled coordinators.
The Honest Limit
Extracting pure primitives will not cure bad data models or eliminate concurrency bottlenecks. If your database schema is fundamentally broken, isolating pure functions will only make the calculation layer reliable while the storage layer remains brittle.
What it does is separate mechanical complexity from business rules. Once the rules are decoupled from the transport and storage layers, changing the architecture later becomes a routing problem rather than a logic puzzle.
The Monday Morning Rule
Do not plan a six-week refactoring initiative next sprint.
Instead, run a baseline repository evaluation or look at your version control history to find the single file with the highest churn and defect rate over the last ninety days.
Open that file. Find one calculation trapped between two database calls or network requests. Extract that calculation into a standalone file with clear inputs and outputs, write exhaustive unit tests for its edge cases, call it from the original site, and submit the PR before lunch.
Keep reading
Next in the log
- Closing the Loop from Repository Audit to Merged Repair
Static audits fail because they catalog symptoms instead of isolating boundaries. Here is how to convert legacy audit findings into verifiable, merged patches.
- From Audit Report to Pull Request: Automating the Repair Loop
Transform static analysis audits into verified pull requests by pairing machine-readable diagnostics with a strict certification harness.
- Automating Dead Branch Pruning After Legacy System Audits
Static analyzers miss dynamic dispatch. Safely prune legacy dead code by coupling runtime execution logging with syntax-aware AST excision.
The Strategic Master Library · written and reviewed under the house's own epistemic rules: nothing claimed that we cannot show.