# UX Mistakes I Made Building Memset > Two design decisions that looked reasonable on paper and quietly taught people to stop opening the app. Source: https://getmemset.app/blog/ux-mistakes-i-made Published: 2026-09-17 --- The two worst things I built were not bugs. Both worked exactly as designed. Both quietly taught people to stop opening the app. A crash gets reported within a day. Someone writes "it closed when I tapped save," you reproduce it, you fix it, you ship. A design mistake does not arrive that way. It arrives as silence: a person who opened the app every morning for three weeks and then never opened it again, with no message explaining why. [Memset](https://getmemset.app) is a review planner. You tell it what you are studying, a notebook page, a textbook chapter, a lecture, a set of cards, and it decides when each of those should come back in front of you. It never holds the material. It holds the timing. That turns out to be an unusual thing to design, because of how the app fails. It does not fail by doing too little. It fails by doing precisely what you told it to. ![A grid of soft rounded squares laid out like a calendar month, with one square holding a tall stack of small cards casting a long shadow and a single card that has slipped onto the next square, while every other square sits empty](https://getmemset.app/blog/ux-mistakes-i-made.webp) ## Mistake one: I let the schedule decide the day Long before any of this shipped, the build I was testing on scheduled every item on its own. Each memset carried a Strategy, the Strategy said how long to wait before the next repetition, and the app did the arithmetic and put a date on the calendar. One of the built-in strategies stretches its intervals along [the forgetting curve](https://getmemset.app/learn/the-forgetting-curve-explained), which is the behaviour you want from a review planner. The idea underneath is about as well established as anything in learning research. A meta-analysis pooling 317 experiments found [spaced reviews beating massed ones, with the best gap widening as the retention target moves further out](https://doi.org/10.1037/0033-2909.132.3.354). I was not worried about the scheduling logic. It was correct. What I had not accounted for is that people do not add material at a steady rate. They add it in bursts. You start a course and enter nine things in the first week, because that is the week you are excited. Nine things with similar strategies, entered on the same evening, come due on the same evening. Then it gets worse, because the good strategies make it worse. A dynamic strategy grows each interval a little beyond the last, which is what you want for long-term retention. It also means two items created on the same day with the same Strategy have identical interval sequences forever. They do not drift apart over time. They move in lockstep, arriving together on day three, day seven, day sixteen, indefinitely. So I would open the app on a Tuesday after work and be handed twenty-three reviews. Not because I had fallen behind. Because three weeks earlier I had a productive Sunday. > A correct schedule and a usable one are not the same object. I had built something that computed the daily number without ever asking whether it was a number a person would accept. And **the daily number is the whole product**. Intervals, Strategies, progress history, the lifecycle a memset moves through, all of that is machinery nobody touches. The one thing a user actually experiences is how much is waiting when the app opens. What came out of that was Categories with daily limits, and it never shipped any other way. A Category caps how many of its items can surface on the same day and rolls the rest forward. Cap "Anatomy" at five and you see five, with the sixth arriving tomorrow. By release the cap was not a patch bolted onto the scheduler, it was the thing the scheduler was organised around. The answer carried a cost of its own that I did not appreciate at the time. Categories began as organisation, a way to keep anatomy separate from contract law. Attaching the daily limit to them turned one concept into two jobs, and a user now has to understand that the label they picked also governs pacing. Unlimited mode exists for exactly that reason. If you want Categories to stay labels and nothing more, you can have that, and the pacing stays out of the way. That is a real concession and it is worth being honest about it. The app now deliberately shows you some items later than the schedule asked for. A purist would call that a worse algorithm. I think it is a better product, for two reasons. The spacing research is tolerant of the exact day, since the benefit holds across a wide band of intervals and nothing collapses when a review lands on Wednesday instead of Monday. And an item reviewed two days late still beats an item sitting in an app you deleted. Most of the work in [keeping a review habit survivable](https://getmemset.app/learn/spaced-repetition-without-burnout) is load management rather than interval precision. ## Mistake two: I built a streak that punished real life I added streaks for the obvious reason. Continuity motivates people, a number going up motivates people, and every habit app on the phone has one. The rule I wrote was clean: if an item goes overdue, the streak breaks. Consistent, easy to explain, easy to implement. It also meant the worst day of someone's week decided the record for the whole month. People do not respond to losing a forty-day streak by trying harder tomorrow. Losses land harder than equivalent gains, which is [the asymmetry Kahneman and Tversky documented](https://doi.org/10.2307/1914185), and a broken streak is a loss with a number attached. The counter does not tick down to thirty-nine. It goes to zero, in one move, on a day you already felt bad about. Notifications made it sharper. A reminder about an overdue item lands in the evening of a day you had already lost. The useful message at that moment is "pick this up tomorrow." What I sent read closer to a receipt. Worse, the mechanic contradicted the pitch. Memset's onboarding tells you the system will survive a missed day, because that promise is most of the reason the app exists. Then the counter reset to zero and told you otherwise. **The promise and the mechanics disagreed**, and users believe the mechanics. The research does not support the reset either. Lally and colleagues followed people forming new daily habits over twelve weeks and found that [missing a single opportunity did not measurably affect the habit formation process](https://doi.org/10.1002/ejsp.674). One skipped day is statistically unremarkable. I had built an interface that treated it as a catastrophe. The fix was making overdue recoverable, and it is worth being exact about what that covers. The current streak still resets when an item goes overdue, and the app says so plainly. What makes it survivable is everything around that moment. Every memset has a grace period, three days unless you change it, before a missed review counts as overdue, so with the default setting one lost evening never touches the counter. An overdue memset is no longer a dead end either: dismiss the overdue state and its progress moves again from where it stopped. The longest streak never resets, so your best run stays on record, and the streak history marks the overdue day as its own entry. A gap now reads as a gap rather than as the end of the record. What changed underneath is smaller than it sounds. For the memset itself, overdue stopped being a failure condition and became a state in its lifecycle, sitting next to Ongoing and Completed like any other. Items move into it and back out of it. That reframing did most of the work, because a state is something you are currently in, and a failure is something you did. ## What the two mistakes have in common Neither was a coding error. Both were faithful implementations of a rule that sounded reasonable when I wrote it down, which is what makes mistakes like these expensive. There is nothing to debug. The seam they share is a mismatch of unit. I was designing a system, and the system's unit is the item. The user's unit is the day. Every decision I made was defensible per item and indefensible per day, and nothing in my tooling showed me the gap between the two. I could open the scheduler's output for one memset and confirm it was right. No screen anywhere said "on the twelfth, this person receives twenty-three of these, and eleven of them are anatomy." I did not find either problem by using the app, and I use it every day. That part genuinely surprised me. When you built the thing you cannot feel its friction, because you always know why the screen is doing what it does. Twenty-three reviews did not read to me as a pile. They read as the scheduler working correctly. I needed retention numbers and a few people willing to write to me before I could see a Tuesday evening instead of correct output. ## What I would tell myself Two things, and neither is specific to study apps. Design the unit your user actually lives in. Not the record, not the item, not the row in the database. Whatever they meet in one sitting is the thing that has to be reasonable, and it is usually a composite of many objects that were each individually fine. Build the screen that shows you that composite early, even if it is a throwaway script, because you will not notice the problem from inside the object. And check what your mechanics say when your copy is not in the room. Onboarding, the marketing page, the feature list: that is what you claim. A counter resetting to zero is what you mean. When the two disagree, nobody notices the copy. If you want a review planner with both of these lessons built into it, [that is what Memset is now](https://getmemset.app). The daily load is capped on purpose, a missed day gets a grace period before anything resets, and your best streak stays on record.