GAP School Module 11 — Continuous Improvement Lesson 11.2

At month 5, the Anchor lead query library had grown to 8 functions that shared a pattern. The code worked but had visible repetition. The decision: refactor to a single parameterized query builder, or ship the next 3 features (credit application flow, saved searches, trade-in form) and revisit later. The right answer was to ship first. By the time the refactor happened at month 8, 2 of the 8 original functions had been replaced by the new features anyway — the refactor scope had shrunk naturally.


The situation

The question wasn’t whether the refactor was worth doing — it was. The question was when. Shipping a refactor that cleans up code in a part of the codebase you’re about to replace produces clean code that nobody uses. Shipping features on working-but-ugly code and deferring the refactor until you’re touching that code anyway is the correct sequencing.


What I did

The refactor decision framework

Four questions that determine whether to refactor now or ship first. Work through them in order:

Decision framework
1. Is the existing code causing bugs in production? YES → Fix it. Technical debt that produces bugs is current cost, not deferred cost. NO → Continue. 2. Is the refactor required for the next feature to be implemented cleanly? YES → Refactor now. Building a feature on a foundation the feature itself requires you to fix is building on sand. NO → Continue. 3. Will refactoring this now save time on the next 3 features? YES (estimate: > 1 day saved) → Refactor now. The ROI is clear. NO → Continue. 4. Is this refactor cosmetic — naming, organization, DRY with no behavior change? YES → Defer. Cosmetic refactors are low-risk but also low-ROI when features wait. NO (behavior-changing) → Evaluate risk carefully before shipping.

Tracking deferred refactors

A deferred refactor that isn’t tracked becomes permanent technical debt. The pattern: a single REFACTOR.md in the repository with a timestamped entry for each deferred item and a review date:

Markdown — REFACTOR.md
# Deferred Refactors These are known cleanup items deferred in favor of feature shipping. Review quarterly. Mark DONE when addressed; mark DROPPED if the code was replaced. ## Active ### Lead query builder — repeated WP_Query construction pattern - **Deferred:** 2026-05-15 (in favor of credit app, saved searches, trade-in form) - **Impact:** 8 functions with similar structure; changes to query logic require updating each independently - **Fix:** Extract to `[client]_build_lead_query( array $args ): WP_Query` - **Effort:** ~3 hours - **Review by:** 2026-08-15 ## Done ### Lead source: text meta → taxonomy migration (completed 2026-05-01) ### Sequence email renderer: inline HTML → template files (completed 2026-04-10)

When refactoring is the right call

The one case where “ship first” is wrong: when the next feature requires touching the code that needs refactoring anyway. Adding a feature on top of bad-structure code means debugging with the cognitive load of the bad structure. Refactoring before building is net faster:

PHP — before and after refactor
// Before: 8 nearly-identical functions function [client]_get_new_leads(): array { ... } function [client]_get_contacted_leads(): array { ... } function [client]_get_leads_by_source( string $source ): array { ... } // After refactor: one query builder function [client]_query_leads( array $args = [] ): array { $defaults = [ 'status' => null, // string or array 'source' => null, // string 'min_score' => null, // int 'date_from' => null, // Y-m-d string 'limit' => 50, 'fields' => 'ids', ]; $args = wp_parse_args( $args, $defaults ); $meta_query = []; if ( $args['status'] ) { $meta_query[] = [ 'key' => '[client]_lead_status', 'value' => (array) $args['status'], 'compare' => 'IN', ]; } if ( $args['source'] ) { $meta_query[] = [ 'key' => '[client]_lead_source', 'value' => $args['source'], ]; } return get_posts( [ 'post_type' => '[client]_lead', 'post_status' => 'publish', 'posts_per_page' => $args['limit'], 'fields' => $args['fields'], 'meta_query' => $meta_query ?: [], ] ); }

Why it matters

The refactor-first instinct optimizes for code quality over feature velocity when the code is working fine. “Working fine but ugly” is a lower-cost state than it looks. “Beautiful but missing features users need” has a real cost.

The REFACTOR.md discipline converts deferred refactors from invisible debt into tracked items. The difference between “we’ll clean this up eventually” and “we’ll clean this up by August 15 when the quarter turns” is accountability.


The Anchor build

REFACTOR.md introduced at month 2. 6 entries over 14 months: 4 marked DONE, 1 marked DROPPED (code was replaced by a new feature), 1 still active. The lead query builder refactor was deferred for 3 months, then completed in one session when 3 of the 8 functions needed to be touched for a new feature anyway — the refactor scope had shrunk naturally and the timing was right. Zero regressions from refactor work in 14 months.


Do this, not that

  • Ship first, refactor later, unless the existing code is buggy or the refactor is required for the next feature. “Ugly but working” is fine. “Buggy” is not.
  • Track deferred refactors in a REFACTOR.md in the repository. Deferred but untracked = permanent. Deferred and tracked = revisable on a schedule.
  • Set a review date for every deferred refactor. Without a review date, “deferred” means “never.”
  • When a refactor touches code you’re already modifying for a feature, do it in the same session. You’re already context-loaded on that code. The marginal cost is low; the benefit compounds forward.
When you’re ready to build

The lessons are yours. When you want it built, we’re here.

Every lesson stays free — no account, no paywall, no email gate, ever. But if you’d rather have this system standing on your business than wire all 48 lessons yourself, leave your email. We’ll send you a direct line to a build — and you’ll be first to hear when we add new tools to the curriculum.

None of this gates a single lesson. The curriculum was free before you got here and it stays that way.

We’ll use your email to send you a fast-track to a GAP build and occasional notes on how GAP builds digital sales departments. Lessons stay 100% free — no email required to read any of them. We never share or sell your information. Unsubscribe any time. Privacy policy at gapindustriesllc.com/privacy.html.

Done learning how it’s built? We’ll build it.

You came here to understand the system, and now you do. If you’d rather have it standing on your business than spend the next three months wiring it yourself, GAP Concierge is the same architecture from these lessons — a white-label AI agent that knows your catalog and captures your leads — set up for you, from $97/mo.

See GAP Concierge →