A Technical Product Manager’s Guide to Letting UX Principles Drive Technical Decisions
By: Jeremy (20 years building products, now coding them myself)
After two decades as a technical product manager, I thought I understood the relationship between UX constraints and architecture decisions. Then I started building VoiceCatcher myself, and learned that seemingly tiny UI principles can completely reshape your entire technical approach.
Here’s the story of how a simple “no scrolling in the main UI” constraint forced us to architect a completely different solution—and why that constraint was worth every line of code it demanded.
The Setup: A Simple History Feature Request
The requirement seemed straightforward: “Users need to view their previous voice transcription sessions.”
In most apps, this would be a simple embedded list with scrolling. As a TPM, I’d seen this pattern a thousand times:
- Add a scrollable container
- Render the list items
- Call it done
But VoiceCatcher had one non-negotiable design principle: The main UI should never require scrolling.
Why “No Scrolling” Matters: The Business Logic
This wasn’t arbitrary design stubbornness. The constraint served three critical business goals:
1. Cognitive Load Reduction
Voice capture tools need to be invisible during use. Any UI that requires exploration, scrolling, or hunting interrupts the user’s primary workflow. When someone hits our hotkey, they want immediate access to their most important controls.
2. Professional Tool Standards
Apps like Alfred, Raycast, and Spotlight have trained users to expect compact, single-screen interfaces for productivity tools. Scrolling signals “complex application” rather than “instant utility.”
3. Mathematical Precision
Our main UI is exactly 350×700 pixels in compact mode, 900×700 in expanded mode. Every pixel has a purpose. Scrolling would mean we failed to prioritize properly.
The Architectural Cascade: When Constraints Have Consequences
Here’s where it gets interesting for TPMs: One UX constraint triggered a complete architectural rethinking.
Attempt 1: Embedded History Tab
The obvious solution: Add a third expandable section after “Essential” and “Advanced” settings.
The problem: With our existing 700px height limit, adding a meaningful history list (showing 5-6 sessions) would require 400-500px. This pushed our total height past our no-scrolling constraint.
Lesson learned: Always calculate your UI math before committing to technical approaches.
Attempt 2: Compressed History Preview
The compromise: Show just 2-3 recent sessions in a tiny preview area.
The problem: User research (okay, it was just me testing it) revealed that 2-3 sessions provide almost no value. Users wanted to browse 10-20 sessions to find specific conversations from “last Tuesday” or “that client call.”
Lesson learned: When UX constraints force you to compromise core functionality, you’re solving the wrong problem.
Attempt 3: Popup Window Architecture
The solution: Completely separate the history feature into a dedicated popup window.
This wasn’t just a UI decision—it was an architectural pivot that required:
- New IPC communication channels
- Shared CSS architecture between windows
- Window management complexity
- Cross-window state synchronization
The Technical Implementation: TPM Communication Made Real
As TPMs, we often describe technical work without fully understanding the implementation complexity. Here’s what “just make it a popup” actually meant:
1. IPC Handler Development
// What the TPM says: "Open history in a new window"
// What the engineer builds:
async ['open-history-window']() {
if (historyWindow && !historyWindow.isDestroyed()) {
historyWindow.focus();
return;
}
historyWindow = new BrowserWindow({
width: 800,
height: 700,
frame: false,
titleBarStyle: 'hidden',
// ... 15 more configuration options
});
}
2. Shared Design System
The popup needed to feel like part of the main app, requiring:
- Shared CSS variables and components
- Consistent neumorphic design patterns
- Proper build process to copy assets
- Theme synchronization between windows
3. Window Lifecycle Management
- Prevent multiple history windows
- Handle window focus and restoration
- Manage memory cleanup on close
- Coordinate with main window state
The Prompts That Made This Possible
For TPMs who want to implement similar solutions, here are the key prompts that drove our architectural decisions:
Constraint Evaluation Prompt
Analyze this UX constraint: [specific constraint]
1. What business value does this constraint provide?
2. What technical complexity does it add?
3. What alternative solutions preserve the constraint?
4. What is the cost/benefit ratio of maintaining this constraint?
Architecture Decision Prompt
Given this constraint: [no scrolling in main UI]
And this requirement: [show 10-20 history items]
Generate 3 technical approaches that satisfy both:
1. Include technical complexity assessment
2. Include user experience trade-offs
3. Include development time estimates
Implementation Planning Prompt
For a popup window solution:
1. List all IPC communication requirements
2. Identify shared resources (CSS, assets, state)
3. Plan window lifecycle management
4. Design error handling for window failures
The Results: When Constraints Create Better Products
Six months later, the popup history window is one of VoiceCatcher’s most praised features. Here’s why the constraint was worth it:
User Experience Wins
- Main UI remains instantly accessible
- History browsing doesn’t interrupt primary workflow
- Dedicated space allows for rich history features (search, filtering, etc.)
- Users can keep history open while using main app
Technical Architecture Wins
- Modular window architecture enables future features
- Shared design system scales to new windows
- IPC patterns established for cross-window communication
- Memory isolation prevents history data from slowing main UI
Business Value Wins
- Professional tool aesthetic maintained
- User workflow remains uninterrupted
- Foundation for advanced features (AI processing, bulk operations)
- Competitive differentiation from “just another list”
The TPM Framework: Making Constraint-Driven Decisions
Here’s the decision framework I now use for constraint-driven architecture:
1. Constraint Validation
- Does this constraint serve real user value?
- Does it differentiate our product meaningfully?
- Is it worth the technical complexity it creates?
2. Solution Space Exploration
- What are 3 completely different approaches?
- Which approach best preserves the constraint while meeting requirements?
- What technical debt does each approach create?
3. Implementation Reality Check
- What’s the actual development complexity (days/weeks)?
- What new architectural patterns does this introduce?
- How does this scale to future requirements?
4. Success Metrics Definition
- How will we measure if the constraint was worth it?
- What user behavior changes do we expect?
- What technical metrics will we track?
For TPMs: You Can Build This Yourself
The most important lesson from this experience: As a TPM, you can absolutely implement these solutions yourself.
The tools that made this possible:
- Cursor + Claude: For real-time implementation guidance
- Electron: For desktop app architecture
- TypeScript: For architectural safety
- Clear constraint definition: For focused decision-making
The skills you need aren’t mysterious engineering magic—they’re systematic thinking patterns you already use as a TPM, applied to code.
Practical Next Steps
If you’re a TPM wanting to try constraint-driven development:
Start Small
Pick one strong UX constraint in your current product. Trace through how it affects technical decisions.
Use This Prompt Template
I need to implement [feature] while maintaining [constraint].
Show me 3 architectural approaches:
1. Embedded solution with constraint modifications
2. Separate interface preserving constraint
3. Hybrid approach with partial constraint relaxation
For each approach, include:
- Development complexity (1-10 scale)
- User experience trade-offs
- Long-term maintenance considerations
Measure Everything
Track both user behavior and technical metrics. Constraints should improve both.
The Bottom Line
Great products come from great constraints, not from avoiding them.
When you encounter a UX constraint that seems to make technical implementation harder, that’s often a signal you’re onto something valuable. The question isn’t “how do we work around this constraint?” but “how do we build an architecture that makes this constraint feel natural?”
In VoiceCatcher’s case, “no scrolling” wasn’t a limitation—it was a design principle that forced us to build a better, more modular architecture. And as TPMs, learning to implement these solutions ourselves doesn’t just make us better at our jobs—it makes us better at building products that actually serve users.
The constraint drove the architecture. The architecture served the users. The users validated the constraint.
That’s the cycle that builds great products.
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: “The Three-Attempt Rule: Technical Problem-Solving in Product Development” - How we solved the history window scrolling issue that failed twice before finding the right solution.