Weeks chasing a phantom slowdown on one iPhone 14, until an offhand comment blew the real cause wide open.
My partner has used Did It since the very beginning, and for a long stretch she was the only person who could reliably break it. She’d tap Done on a text entry and nothing would happen. The cursor stopped flashing. She’d tap it again a few times, out of habit more than hope. Eventually the app would recover and dump her on History, and when she went back to Today the entry would be there three or four times, always the version with the typo she’d been trying to fix when it froze.
It happened on her iPhone 14, so naturally I worried I had created a floor on which the app would work seamlessly. I switched my simulator to always be an iPhone 13 and kept my daughter’s trashed and discarded iPhone 12 as a physical test device.
What made it worse to sit with was that it never crashed. No error, no stack trace, nothing to search for, just her getting frustrated with something I’d made, repeatedly, over weeks. And nobody else was reporting it. I didn’t know if that meant it genuinely wasn’t happening to anyone else, or if it just hadn’t caught up with them yet, since Did It was still young and she’d been using it the longest, with by far the biggest library. It’s one thing to fix a bug. It’s another to suspect you’ve shipped something that quietly gets worse for everyone the longer they stay.
I could grab an export of her library and drop it into the simulator, so at least I could test against her actual data rather than my own thin one. That felt like the responsible way to validate any fix. So I’d make a change, load her library up, watch it behave, decide it was fixed, ship it, and hear “still happening” a few days later.
The first two rounds of fixes went after launch cost and the photo picker, both real, both shipped, neither one touching her problem. Deferred database work on cold start, a query that had been running once per entry instead of once per day, a picker that opened faster because it was warmed earlier and its permission checks ran in parallel instead of one after another. Each looked solid on her data, in the simulator, because of course it did. By then I’d been round that loop enough times to dread asking her if it was still happening, because I already half knew the answer.
Underneath all of this was a conviction I couldn’t shake and couldn’t prove: that this was about how much she’d put into the app, the entries, the photos, the months of history. I kept saying some version of that to different agents in different chats, and kept getting the same correct answer back: the query that loads Today only touches one day’s rows, so the size of her whole library shouldn’t matter. True, and not the same thing as “the size of her library doesn’t matter.” I didn’t have the background to argue the difference, so I’d drop it, fix whatever the answer did point to, and land back on the same feeling a week later.
That belief sat oddly alongside another one I was holding at the same time. I had her actual library loaded in the simulator by then, exported and imported the same way I tested everything else, and it never once broke there. So while I kept insisting to agents that this was about how much she’d built up, I was also half convinced there was something specifically wrong with her phone, since the same data behaved perfectly on mine. We went as far as wiping her phone and restoring everything from scratch. It achieved nothing except proving the problem came back exactly as before, on the same device, with the same data. I was holding two contradictory theories at once and hadn’t noticed.
What actually cracked it wasn’t a debugging session, it was a throwaway line in a plan document. I work on this alone, just me across different agent chats, so there’s no colleague to bounce a hunch off. One of them had scoped out a plan to fix some entry sheet issues and, under “out of scope,” noted a “larger store/DB redesign” with no detail given. I asked what that meant, out of curiosity more than strategy, and mentioned the thing that had been nagging at me anyway: the one person with problems was also the person with the biggest library. I’d asked “why is this slow” head-on plenty of times already. This wasn’t that question. It just happened to sit next to it.
Turns out that’s where it was. Buried in the app’s background handling was an iCloud backup routine that kicked off the moment the app was sent to the background, if anything had changed since the last one. This entailed reading every photo in her library from disk into memory, one at a time, packing the lot into a single zip, generating one giant blob out of the whole thing, synchronously, on the same thread the rest of the app needed. Fine for a handful of photos. Not fine for months of near-daily ones, whatever phone it’s running on. Her actual habits made it worse: she’d open Photos to jog her memory, then swipe straight back into Did It to write it down, often within seconds, which was usually just long enough to land her back in the middle of a backup that had only just started. What I’d been blaming on the entry sheet and the picker was a backup job still busy on the thread exactly when she needed it. It’s not something the simulator would ever have shown me since it doesn’t reliably connect to iCloud.
Once I knew what it was, none of it felt mysterious anymore. Obvious, the way these things always are once you’re no longer the one stuck inside them.
The fix wasn’t even that dramatic. The backup got a short debounce so a quick app switch doesn’t set it off. It started reusing an incremental zip built from a cached manifest, so a day with no new photos costs almost nothing instead of re-reading everything. We added smaller thumbnails so the list itself has less to decode, and moved the zipping itself to the native side, which streams files from disk instead of holding them all in memory at once.
Her hangs stopped. I didn’t fully believe it until I’d watched her use the app for a few days without a complaint. It was a great feeling, with a little dash of embarrassment for having not clearly defined this backup behaviour at the outset.
I now ask for a flow of whatever I’m planning or diagnosing, a start-up sequence, a new feature, backup routines. It’s the only reliable way I’ve found to compare what agents say the code is doing against what it should be doing.