The Cascade Effect: How Testing the UI Led to Architectural Discoveries
June 23, 2025
I just wanted to test a web interface. You know, basic stuff — upload a file, send a chat message, see if the buttons worked. A quick validation session before moving on to bigger features.
Three hours later I’d built a complete file resolution system with multi-factor scoring, confidence thresholds, and database persistence.
This is how “vertical slice development” works in practice: you can’t predict where testing will lead, but following the threads reveals what really matters.
The innocent test that started it all
PM-011 was supposed to be straightforward. The file upload worked, the chat interface responded to greetings, and I figured I’d just verify everything connected properly. But when I tried “analyze the file I just uploaded,” nothing happened.
Well, something happened. The system politely informed me it couldn’t resolve which file I meant. Which was… odd, considering I’d uploaded exactly one file thirty seconds earlier.
Down the file resolution rabbit hole
Here’s where vertical slice development gets interesting. I could have faked it — hardcoded the file reference, added a quick lookup, shipped the demo. Ostensibly we were just testing the UI and yet, it was a graphical user interface on the web. But it was also supposed to work and if users can’t easily reference files they just uploaded, then really the whole feature was broken.
So we went deeper. (Generally when I say “we” did something, it usually means Claude Code proposed something and I tried to evaluate whether it made architectural sense.)
What started as “fix file references” became:
- Database-first approach with proper UploadedFile models
- Smart scoring algorithm with four factors: recency, file type, name matching, usage patterns
- Confidence thresholds for auto-proceed vs. confirmation vs. clarification
- Edge case handling for ambiguous references
The performance surprise
One of those happy accidents: we built something that actually performed. File resolution clocked in at under 3ms for 50 files, when our requirement was 100ms. The scoring algorithm correctly differentiated between files, ambiguity detection worked as designed, and edge cases (old files, unicode names, empty directories) all handled properly.
Sometimes when you build the right abstraction, performance comes free.
Retroing my manic AI-driven rush to build
But the biggest insight wasn’t technical — it was about process. Halfway through implementing the file resolver, I realized something uncomfortable: I would never run a team this way!
Here I was, working at a manic pace without retrospectives, skipping sustainable development practices, accumulating context without proper tracking. If an engineer on my team worked like this, I’d be concerned about burnout and technical debt.
Mind you, this was right after PM-010 (error handling) had gone so smoothly I’d completely forgotten to write about it. At this point I didn’t realize that after finishing 010 in one day I would be stuck on 011 for weeks! When things work perfectly, we move on without celebration or reflection. When they’re messy, we get compelling stories and hard-won lessons.
Here I was treating myself like a rented mule. Chasing that next exciting checklist item without enough sleep or reflection.
The irony was perfect: building a PM assistant while ignoring basic PM practices. Maybe Piper Morgan’s first task should be helping me manage the Piper Morgan project?
What I learned about vertical slice development
Testing isn’t separate from development — it drives architectural discovery. That innocent UI test revealed a fundamental gap in our user experience. Users expect to reference files naturally, and our system couldn’t handle that.
Follow the threads. Each missing piece revealed another missing piece. File references needed resolution, resolution needed scoring, scoring needed persistence, persistence needed proper domain models. The cascade led to a complete feature.
Performance often emerges from good design. We didn’t optimize for speed — we optimized for correctness and clean abstractions. The performance was a side effect of thinking clearly about the problem.
Process discipline matters even with superpowers. AI tools amplify capability but don’t replace the need for sustainable practices. Working at unsustainable pace catches up eventually.
To be honest, these are all things I have learned in the past, first as a UX practitioner where we’d often develop new feature ideas while usability testing what we had designer, and then again as a product leader trying to discipline and manage complex projects. Now, I am learning these lessons again viscerally as a pseudo-engineer.
The conversational bonus
Oh, and we fixed the conversational handling too that had proven wonky in the interface. Turns out the system already supported greetings, thanks, and farewells perfectly — it just needed proper testing. Sometimes the feature you think you need to build already exists.
It’s still a little confused by edge cases like “Hello, world!” (traditional programmer’s first test message for new software) and “Goodbye, cruel world!” (stereotypical “ending it all” message), but I haven’t asked it to understand puns or layers of meaning yet, so that seems fine?
What’s next
With file resolution complete and conversation handling working, we were now ready to implement document ingestion workflows. Everything was smooth and on track. The foundation is solid, the performance is proven, and we’d just learned some valuable lessons about following user needs wherever they lead.
Plus I’ve got a new appreciation for why we do retrospectives. When things go smoothly, it’s easy to forget to celebrate and learn from success.
