How the Three-Attempt Rule Separates User Value from Engineering Preference
By: Jeremy (TPM learning that not all technical debt is worth paying down)
Here’s something I learned building VoiceCatcher: Technical debt isn’t inherently bad—it’s only bad when it prevents you from delivering user value or building new features efficiently.
When our Electron build process became a 47-step nightmare of .js to .cjs renaming, path rewriting, and manual file copying, my engineering instincts screamed “fix this immediately!” But applying the three-attempt rule taught me something counterintuitive: some technical debt should be maintained, not eliminated, if fixing it doesn’t drive measurable user or business value.
This is the story of how we developed a business framework for technical debt prioritization, and why treating all technical debt as urgent creates more problems than it solves.
The Setup: When Engineering Debt Meets Product Reality
Context: Our build system had evolved into a complex beast:
- TypeScript compilation with custom path rewriting
- Manual .js to .cjs file renaming for 15+ files
- Regex-based import path fixing
- Multi-target builds (main process, GUI, shared libraries)
- Asset copying across multiple directories
The engineering perspective: This build process was embarrassingly hacky and needed immediate refactoring.
The product reality: It worked perfectly, was completely automated, and hadn’t caused a single user-facing issue in 6 months.
The question: Should we spend 2-3 weeks refactoring the build system, or ship the export functionality that users had been requesting?
The Problem: Technical Perfectionism vs. User Value
The Engineer’s Dilemma
As developers, we’re trained to recognize and eliminate technical debt. But as TPMs, we need to optimize for user value delivery, not code elegance.
Common TPM mistake: Treating all technical debt with equal urgency.
Reality: Technical debt exists on a spectrum from “actively blocking user value” to “aesthetically unpleasing but functionally perfect.”
The Three-Attempt Test for Technical Debt
Applying our three-attempt framework to the build system mess:
Attempt 1: Address the apparent problem Problem statement: “Our build process is too complex and hacky.” Solution: Refactor the build system to be cleaner and more maintainable.
Attempt 2: Question the problem Reframed problem: “What user or business problem does build complexity actually cause?” Analysis: Build works reliably, deployment is automated, new developers can understand it within a day.
Attempt 3: Question whether it’s a problem Fundamental question: “Is build complexity blocking user value delivery or feature development velocity?” Conclusion: No. The build system enables fast iteration and reliable deployment.
Decision: Don’t fix the build system. Ship user-requested features instead.
The Solution: Technical Debt Triage Framework
The Business Impact Matrix
interface TechnicalDebt {
id: string;
description: string;
userImpact: 'blocking' | 'degrading' | 'invisible';
velocityImpact: 'blocking' | 'slowing' | 'neutral';
riskLevel: 'high' | 'medium' | 'low';
fixEffort: 'hours' | 'days' | 'weeks';
businessValue: 'critical' | 'beneficial' | 'aesthetic';
}
const prioritizeDebt = (debt: TechnicalDebt[]): TechnicalDebt[] => {
return debt
.filter(item => item.businessValue !== 'aesthetic')
.sort((a, b) => {
// Prioritize user-blocking issues first
if (a.userImpact === 'blocking' && b.userImpact !== 'blocking') return -1;
if (b.userImpact === 'blocking' && a.userImpact !== 'blocking') return 1;
// Then velocity-blocking issues
if (a.velocityImpact === 'blocking' && b.velocityImpact !== 'blocking') return -1;
if (b.velocityImpact === 'blocking' && a.velocityImpact !== 'blocking') return 1;
// Finally, effort vs. impact calculation
return calculateROI(b) - calculateROI(a);
});
};
The Four Categories of Technical Debt
Category 1: User-Blocking Debt
- Definition: Technical issues that directly prevent users from accomplishing their goals
- Example: Electron IPC failures that break recording functionality
- Priority: Fix immediately, before any new features
Category 2: Velocity-Blocking Debt
- Definition: Technical issues that slow down new feature development
- Example: Lack of shared component library causing UI inconsistency work
- Priority: Fix when development efficiency is measurably impacted
Category 3: Maintenance Debt
- Definition: Technical issues that increase maintenance burden but don’t block progress
- Example: Complex but working build processes
- Priority: Fix during natural refactoring opportunities
Category 4: Aesthetic Debt
- Definition: Technical issues that feel wrong but don’t impact functionality or development
- Example: Inconsistent variable naming across files
- Priority: Fix only if you have absolutely nothing else to do
The TPM Framework: Business-Driven Technical Decisions
1. Measure User Impact, Not Code Quality
Technical debt should be prioritized based on user experience degradation, not engineering aesthetics.
The User Impact Assessment Prompt:
For this technical debt issue: [describe technical problem]
1. How does this directly affect user workflows or experience?
2. What user tasks become impossible, slower, or more frustrating?
3. How many users are affected and how frequently?
4. What's the user-visible difference between current state and fixed state?
5. Would users notice or care if this was fixed?
If users wouldn't notice the fix, consider this maintenance or aesthetic debt.
2. Track Development Velocity Impact
Some technical debt slows down future feature development. This debt has business value because it affects delivery speed.
The Velocity Impact Assessment Prompt:
For this technical debt issue: [describe technical problem]
1. How much time does this add to typical development tasks?
2. How often do developers encounter this friction?
3. Does this prevent implementing certain types of features?
4. How much time would fixing this save over the next 6 months?
5. What's the opportunity cost of not fixing this?
If the fix takes longer than 6 months of accumulated friction, defer it.
3. Risk-Adjust Technical Debt Priority
Some technical debt represents future risk rather than current problems.
The Risk Assessment Prompt:
For this technical debt issue: [describe technical problem]
1. What could break if this isn't addressed?
2. How likely is that breakage to occur?
3. How severe would the impact be if it breaks?
4. How much warning would we have before it becomes critical?
5. Can we implement monitoring to detect problems early?
High-probability, high-impact risks deserve immediate attention.
The Business Impact: When Technical Debt Strategy Drives Product Success
Before: Engineering-Driven Debt Management
- Fixed technical debt based on developer discomfort
- Spent weeks on infrastructure improvements with no user benefit
- Delayed user-requested features for code cleanliness
- Over-engineered solutions for problems that might never occur
After: Product-Driven Debt Management
- Fixed technical debt based on user or velocity impact
- Maintained working but ugly systems that didn’t block progress
- Shipped user value while accumulating sustainable technical debt
- Invested technical effort where it multiplied product development capacity
The Product Delivery Metrics
- Feature delivery velocity: +60% (focused effort on user-valuable work)
- User satisfaction: +40% (prioritized user-facing improvements)
- Development frustration: Unchanged (technical debt didn’t slow daily work)
- System reliability: Unchanged (ugly but stable systems remained stable)
Advanced: The Technical Debt Portfolio Strategy
Debt as Investment Vehicle
interface TechnicalDebtPortfolio {
category: 'user-blocking' | 'velocity-limiting' | 'maintenance' | 'aesthetic';
allocation: {
immediate: number; // % of technical effort
planned: number; // % of technical effort
deferred: number; // % of technical effort
ignored: number; // % of technical effort
};
}
const optimalPortfolio: TechnicalDebtPortfolio = {
'user-blocking': { immediate: 100, planned: 0, deferred: 0, ignored: 0 },
'velocity-limiting': { immediate: 20, planned: 60, deferred: 20, ignored: 0 },
maintenance: { immediate: 0, planned: 20, deferred: 60, ignored: 20 },
aesthetic: { immediate: 0, planned: 0, deferred: 10, ignored: 90 },
};
Strategic Debt Accumulation
Sometimes deliberately accumulating technical debt enables faster user value delivery.
VoiceCatcher example: Our build system became complex because we added support for:
- Multiple Electron window architectures
- Shared component libraries
- Custom module resolution
- Cross-platform asset management
Each addition made the build more complex but enabled features users wanted. The complexity was productive technical debt.
Debt Refinancing Strategy
const refinanceDebt = (currentDebt: TechnicalDebt[], newFeatureRequirements: FeatureSpec[]) => {
// Identify debt that blocks new features
const blockingDebt = currentDebt.filter(debt =>
blocksFeatureImplementation(debt, newFeatureRequirements)
);
// Prioritize debt that enables multiple features
const leverageDebt = blockingDebt.filter(debt => debt.featureEnablement.length > 1);
return {
immediatelyFix: leverageDebt,
planToFix: blockingDebt.filter(debt => !leverageDebt.includes(debt)),
continueCarrying: currentDebt.filter(debt => !blockingDebt.includes(debt)),
};
};
Common TPM Technical Debt Mistakes (That I Made)
Mistake 1: Treating All Debt as Urgent
Wrong thinking: “Technical debt is bad and should be eliminated.” Reality: Most technical debt doesn’t impact users or development velocity.
Fix: Categorize debt by business impact before prioritizing fixes.
Mistake 2: Engineering Perfectionism
Wrong thinking: “Clean code is always better than working code.” Reality: Clean code that doesn’t deliver user value is less valuable than ugly code that works perfectly.
Fix: Optimize for user value delivery, not code aesthetics.
Mistake 3: Ignoring Productive Debt
Wrong thinking: “All shortcuts create problems later.” Reality: Strategic shortcuts can enable faster user value delivery without meaningful downsides.
Fix: Distinguish between productive debt (enables features) and wasteful debt (creates friction).
Mistake 4: No Debt Monitoring Strategy
Wrong thinking: “We’ll deal with technical debt when it becomes a problem.” Reality: Some debt creates sudden, catastrophic failures rather than gradual degradation.
Fix: Monitor technical debt that could create sudden user-facing failures.
The Technical Implementation: Debt Management Systems
Automated Debt Tracking
interface DebtMetric {
id: string;
category: TechnicalDebtCategory;
impactMetric: 'build-time' | 'deploy-frequency' | 'bug-rate' | 'feature-velocity';
threshold: number;
currentValue: number;
trend: 'improving' | 'stable' | 'degrading';
}
const monitorDebt = (): DebtMetric[] => [
{
id: 'build-complexity',
category: 'maintenance',
impactMetric: 'build-time',
threshold: 120, // seconds
currentValue: getBuildTime(),
trend: calculateTrend('build-time', 30), // 30-day trend
},
{
id: 'test-coverage',
category: 'velocity-limiting',
impactMetric: 'bug-rate',
threshold: 0.8, // 80% coverage
currentValue: getTestCoverage(),
trend: calculateTrend('test-coverage', 30),
},
];
User Impact Correlation
const correlateDebtWithUserMetrics = (debt: TechnicalDebt[], userMetrics: UserMetric[]) => {
return debt.map(debtItem => ({
...debtItem,
userCorrelation: calculateCorrelation(
debtItem.metricHistory,
userMetrics.filter(m => m.category === 'satisfaction')
),
priorityScore: calculatePriorityScore(debtItem, userMetrics),
}));
};
Velocity Impact Measurement
const measureVelocityImpact = (debt: TechnicalDebt) => {
const beforeFix = {
featureDeliveryTime: getAverageFeatureTime(),
developerFriction: getDeveloperFrictionScore(),
codeReviewTime: getAverageReviewTime(),
};
// After fixing debt
const afterFix = {
estimatedFeatureTime: estimateImprovedFeatureTime(debt),
estimatedFriction: estimateReducedFriction(debt),
estimatedReviewTime: estimateImprovedReviewTime(debt),
};
return {
velocityGain: calculateVelocityImprovement(beforeFix, afterFix),
timeToBreakEven: debt.fixEffort / afterFix.velocityGain,
confidenceLevel: calculateEstimateConfidence(debt),
};
};
The Psychology: Why Engineers and TPMs See Debt Differently
Engineering Psychology: Quality as Inherent Value
Engineers are trained to see code quality as inherently valuable. Poor code feels psychologically uncomfortable regardless of its functional impact.
The Engineering Perspective: “This build system is a nightmare to maintain.” The Reality: The build system requires 10 minutes of maintenance per month.
Product Psychology: Value Through User Impact
TPMs optimize for user value delivery. Technical systems are tools for creating user value, not ends in themselves.
The Product Perspective: “Does this build system block user value delivery?” The Reality: The build system enables reliable feature deployment.
Bridging the Perspectives
const technicalDebtDiscussion = {
engineer: {
concern: 'This code is unmaintainable and embarrassing',
focus: 'Code quality and technical best practices',
metrics: 'Complexity, maintainability, elegance',
},
tpm: {
concern: 'Does this affect users or development velocity?',
focus: 'User value delivery and business efficiency',
metrics: 'User impact, feature velocity, business outcomes',
},
resolution: {
question: 'What user or business problem does this technical debt create?',
decision: "Fix debt that blocks value, manage debt that doesn't",
measurement: 'Track user metrics and development velocity, not code aesthetics',
},
};
Advanced: Strategic Technical Debt as Competitive Advantage
Debt-Driven Development Speed
const strategicDebt = {
principle: 'Accumulate technical debt that enables faster user value delivery',
examples: [
'Complex build process that supports rapid feature iteration',
'Duplicate code that enables independent team velocity',
'Quick-and-dirty implementations that validate user demand',
],
management: [
'Monitor debt for user impact escalation',
'Plan debt refinancing around major features',
'Maintain debt service capacity for critical fixes',
],
};
Technical Debt Refinancing Strategy
Like financial debt, technical debt can be strategically refinanced:
Refinancing triggers:
- New features require major architecture changes
- Development team growth necessitates better systems
- User scale demands performance improvements
- Competitive pressure requires faster iteration
VoiceCatcher example: We’ll refinance our build system debt when we add team collaboration features, because shared development requires better tooling.
The Prompts That Enable Strategic Debt Management
Technical Debt Assessment Prompt
Analyze this technical debt issue: [describe technical problem]
Business Impact Analysis:
1. How does this affect user experience or functionality?
2. How does this affect development velocity or team efficiency?
3. What's the risk of this causing user-facing failures?
4. How much effort would it take to fix properly?
5. What's the cost of carrying this debt for 6 more months?
Recommendation: Fix immediately / Plan to fix / Monitor and maintain / Ignore
Include specific metrics for measuring impact and tracking degradation.
Debt Portfolio Optimization Prompt
I have these technical debt items: [list debt items with categories]
Optimize technical debt portfolio:
1. Categorize each item by user/velocity/maintenance/aesthetic impact
2. Estimate fix effort and business value for each
3. Identify debt that enables multiple future features
4. Create debt refinancing plan tied to product roadmap
5. Design monitoring system for critical debt escalation
Provide allocation strategy for technical effort across debt categories.
Strategic Debt Accumulation Prompt
I want to ship [user feature] quickly and am considering [technical shortcut].
Strategic debt analysis:
1. What technical debt would this shortcut create?
2. How would this debt affect future development?
3. What's the user value of shipping faster vs. shipping cleaner?
4. How would we refinance this debt when needed?
5. What monitoring would detect if this debt becomes problematic?
Recommend whether to accumulate this debt strategically or invest in cleaner implementation.
Lessons Learned: Technical Debt as Business Tool
Not All Technical Debt Creates Business Problems
Complex, ugly, or non-standard code can work perfectly for years without affecting users or development velocity.
VoiceCatcher example: Our 47-step build process looks terrible but has enabled stable, fast deployment for 8 months without a single failure.
Strategic Debt Accumulation Can Accelerate Product Development
Deliberately accumulating technical debt can enable faster user value delivery when managed properly.
Measurement: We shipped 3 major user-requested features in the time it would have taken to refactor our build system once.
Debt Management is Portfolio Management
Like financial portfolios, technical debt portfolios should be actively managed with different strategies for different debt categories.
Strategy: Immediately fix user-blocking debt, plan velocity-limiting debt fixes, monitor maintenance debt, ignore aesthetic debt.
Advanced: The Future of Technical Debt Strategy
AI-Assisted Debt Impact Analysis
const aiDebtAnalysis = {
capability: 'Analyze code changes for user impact probability',
input: 'Code diff, user behavior data, system metrics',
output: 'User impact risk score, velocity impact estimate, fix priority',
application: 'Automated technical debt triage and prioritization',
};
Real-Time Debt Monitoring
Future tooling: Systems that monitor technical debt impact on user metrics and development velocity in real-time, automatically flagging debt that escalates from maintenance to velocity-limiting.
Predictive Debt Management
Concept: Predict which technical debt will become problematic based on product roadmap and team growth, enabling proactive debt refinancing before it blocks progress.
The Meta-Lesson: Technical Decisions as Business Strategy
The biggest insight from managing VoiceCatcher’s technical debt: Technical perfection and business success are not the same thing.
Technical debt management isn’t about eliminating all imperfection—it’s about:
- Optimizing for user value delivery over code aesthetics
- Investing technical effort where it multiplies business capability
- Strategic debt accumulation to enable faster product iteration
- Risk management for debt that could create sudden user impact
The framework: Treat technical debt as a business tool, not a business problem.
Practical Implementation for TPMs
Start with User Impact Assessment
Before addressing any technical debt, understand how it affects users and whether they would notice improvements.
Track Development Velocity Correlation
Measure how technical debt actually affects feature delivery speed, not how it feels to developers.
Build Debt Monitoring Systems
Monitor technical debt that could escalate into user-facing problems, but don’t monitor debt that’s stable and contained.
Embrace Strategic Debt Accumulation
Sometimes accumulating technical debt enables faster user value delivery and should be done deliberately.
The Bottom Line
Technical debt isn’t inherently good or bad—it’s a tool that can either accelerate or decelerate business value delivery.
VoiceCatcher’s strategic technical debt management enabled us to ship user-requested features instead of spending weeks on infrastructure that users would never notice. More importantly, it taught us to optimize for business outcomes rather than engineering aesthetics.
As TPMs, we need to recognize that technical decisions are business decisions. The goal isn’t perfect code—it’s perfect user value delivery through whatever technical means are most effective.
Our ugly, complex, hacky build system became one of our most valuable business assets because it enabled reliable, fast product iteration while staying completely invisible to users.
That’s the power of treating technical debt as product strategy rather than engineering embarrassment.
Jeremy is a technical product manager turned solo developer, building VoiceCatcher as a local-first voice transcription tool. Follow the journey at [project repo] or connect on [social links].
Next in this series: “Performance Constraints Drive UX Decisions: The Whisper.cpp Story” - How the technical limitations of local speech recognition shaped our entire product architecture, and why constraints often enable better user experiences than unlimited resources.