This is crossposted on essay.dev.
It seems like every time I talk about principles of software engineering to you all I get jaw-droppingly insightful replies. No pressure.
Ok, if you google “documentation-driven development”, it seems to be a lot of people saying that documentation is so important that you should write it first blah blah blah. But I think there’s a deeper insight here that I want to run by you.
Making design decisions — like deciding what to build — is really hard. (That’s not the deep part yet.) We live and breathe Beeminder and we wallow around in its code all day long. Even if we were to establish design criteria like “reduce cognitive load” our first-line thoughts on these are different than our users’.
Power users may live and breathe Beeminder all day long, but we know how the literal bits go together, which parts are wonderful, and which are eldritch abominations. When coming up with ideas, we will naturally discount those which are difficult to implement. Ease of implementation is good to factor in to the decision-making but not good if it shapes what the decisions even are and what ideas are even thought of.
A trick that helps us decide what to build (we’re finally at the deeper insight part now) is to pretend the thing exists and fully write up how you’d describe it to users, both new and old. I’ve been surprised how much clarity I can end up with about the right thing to do by doing that.
“Pretend the thing exists and fully write up how you’d describe it to users”
I sometimes call it blog-post-driven development even though I haven’t done this on the blog before, just beemails and forum posts.
There are downsides to actually publishing the posts. When I floated the idea of requiring a credit card in order to create a goal, everyone freaked the frack out and we were too scared to do it for years. Then finally we did and it was immediately obvious that it was way better and no one (well, maybe literally one person) minded a bit.
But you can always write the documentation or blog post and not actually publish it until the thing it describes exists. Which is the point: let the documentation guide what you build. I feel like I need to say it another way to drive home the profundity of it. Maybe in another language? So far I’m making it sound too obvious. I think the key, and the part that you need to try for yourself, is to put yourself in the mindset of the thing already existing and then start writing. That forces a lot of design decisions that you’d otherwise weasel out of making by writing things like “and then we’d either do X or Y”. Not allowed! Commit to a decision and see where the document goes. You’ll often back yourself into a corner and have to backtrack. Which is wonderful, to be doing that before any code is written instead of after. It’s a lot like writing a spec.
So that was the armchair quarterbacking. Now let’s actually try it. I’m using a design question we’ve been heatedly discussing: the right way to make do-less goals have teeth.
Fictional Feature Announcement 1: Auto-Derail
This is all in italics and block-quoted so you don’t forget that it’s all make-believe at this point. I mean, at least three of these are make-believe.
We’ve had Pessimistic Presumptive Reports (PPRs) for seven years and they’re so much better than nothing but still are so gross, magically adding made-up data to your goals. The problem they solve — Beeminder goals must derail if you ignore them — is as critical as ever but today we are announcing a better solution: Auto-Derail.
Auto-Derail is like PPRs but much simpler and much more draconian: instead of gradually derailing you by eating through your safety buffer if you stick your head in the sand, we just force-derail you immediately if you hit your deadline without having entered data for that day. It’s like an ultra-PPR, but doesn’t touch your data.
And it doesn’t have to be immediate. Auto-Derail is specified as a number of days you’re allowed to go without entering data. By default this is zero for do-less goals, 30 for do-more goals, and 7 for weight-loss goals. But you can set it to whatever you like. You can effectively opt out of the whole feature, just like you can opt out of PPRs, by picking a huge number of days as your auto-derail.
I personally (as user-me) am excited to have a zero-day auto-derail on do-less goals like my sugar consumption. I used to let PPRs come through and then every couple days I’d correct them (if I could remember — otherwise I’d estimate or let the pessimistic amount stand). Now I’m grateful for the greater discipline of a red goal screaming at me to enter my number by the deadline. It’s like any other beemergency this way.
What about scheduled breaks, you ask? It’s already the case that you need to turn PPRs off before going on vacation. (Actually there’s a trick you can use to give yourself safety buffer for a vacation without turning off PPRs but it’s obscure enough that it might as well not exist. The right answer to this is a future feature we call True Breaks.) So with auto-derail you just also have to remember to turn up your auto-derail to be more than the number of days you’ll be going offline. That’s bad, having to remember to do that and especially having to remember to undo that when you come back, but since the previous status quo was as bad or worse in that regard we feel good about shipping this feature first and then improving scheduled breaks separately.
Bonus: This also solves a potentially frustrating corner case discovered by Grayson Bray Morris where a change in slope in your road can mean that PPRs take way too long to derail you. With auto-derail there’s no uncertainty about how long you can go without entering data — on any goal, not just do-less — before derailing. It’s exactly the number of days you specified.
Here’s a big question you probably have at this point: How does your graph indicate how close you are to derailing? If you’re deep in the green based on how far above the the yellow brick road you are on a do-more goal, how does the graph reflect that really you’re in the orange because you’ve almost used up your number of days before auto-derailing? I guess I better answer it! The answer is that we’ve written new code (beautiful, shimmering new code) to make all the countdowns show the minimum of the normal countdown and the auto-derail countdown and we’ve overlaid a ticking time bomb graphic on any graph where the auto-derail is due to happen before the regular derail.
Does that mean that a do-less goal will always have a time bomb on it regardless of the auto-derail setting? Sigh. Consistency dictates that it does. It goes away when you enter a datapoint for today but you generally do that at the end of the day and the time bomb reappears as soon as your deadline is past and it’s the new day.
Aaaand, emergency eject. It was going so well and then things started getting pretty dicey. If we were dead set on auto-derail we’d have our work cut out for us to flesh out that time bomb idea. Instead, let’s move on to another approach.
Fictional Feature Announcement 2: Customizably Pessimistic Presumptions
What if we doubled down on PPRs and improved them?
Pessimistic Presumptive Reports (PPRs) are critical for do-less goals but they’ve felt really wrong to a lot of people and for good reason: they’re magically adding made-up data to your goals.
Today we are announcing a simple solution: When you create a goal to, for example, eat less sugar, we include a step where we say, “if you don’t tell us how much sugar you ate we’re sure as heck not presuming zero so tell us what we should presume!”
Now PPRs are both less magical and less made-up, since you pick them explicitly. You can also change them any time in settings.
We encourage you — by which I mean the UI encourages you by defaulting to it — to pick a PPR of twice your daily rate, same as the previous status quo, because that has a nice property: Just as with flatlining on a do-more goal, it means that you lose a day of safety buffer with each day that you ignore the goal.
If you want to be forced to enter data every day on your do-less goals (as I personally emphatically do) you can just choose a PPR of (in my case of dessert/candy-minding) twice your body weight in sugar or whatever amount is more than any safety buffer you might ever accumulate.
And you do have the choice to set your PPR to zero if you really want to. We don’t think you should and mildly discourage that by still putting the ugly PPRs in your list of datapoints regardless. We consider implicit zeros on a do-less goal to be anathema. If a zero is being graphed on a do-less goal, it’s going to show up as such in your datapoints. This also means you can no longer delete datapoints on do-less goals — only edit them.
But as always, entering a real datapoint makes the PPR self-destruct.
The hard part about this was generalizing all the graphing code to understand arbitrary PPR values, as well as the now special case of “whatever twice your current daily rate is”. It’s also not great how many users will likely insist on picking ill-advised PPRs and make themselves infinitely safe, which may look weird or ugly on the graph, not to mention defeating the point of Beeminder. But we’re all adults, right? The interface makes clear that you shouldn’t touch the PPR setting unless you know what you’re doing.
Bonus: Weight loss goals now work much better! In the old status quo if you had a very shallow yellow brick road and then fasted or got sick and found yourself well below the road, you’d suddenly have an absurd amount of safety buffer and be able to stick your head in the sand avoiding the scale while actually gaining weight. You’d back yourself into a corner where, by the time you finally had to weigh in, you’d be hopelessly above your yellow brick road. (Many of us resorted to meta-goals until now, a separate do-more goal for actually stepping on the scale most days.) Now, your “max daily fluctuation” is also your PPR. So your weight-loss goal never lets you go long without weighing in.
That went better! (The weight loss bonus part applies to auto-derail too, of course.)
Fictional Feature Announcement 3: Meta-Goals Now Come Standard
Here’s a very us approach…
We’ve had Pessimistic Presumptive Reports (PPRs) for seven years but they’re so inelegant.
Fundamentally, the problem PPRs solve is to force you to enter data on your do-less goals. Do-more goals don’t have that problem because if you don’t report on a do-more goal we presume you did nothing and that eventually derails you. PPRs were a kludge to make that be true for do-less goals as well. If you didn’t report on a do-less goal, we’d presume you did more than your daily rate. That would eventually derail you.
Well, we have a much better way than that to force you to do things. Do you know what it is? It’s Beeminder.
From now on, when you create a do-less goal, we automatically create a sister goal for it that ensures you enter data.
Isn’t that overkill? Too much clutter on your dashboard? Confusing for newbees? Yes, yes, and yes. Which is why we hide the meta goal and automatically populate it. As part of do-less goal creation we ask how many days per week you want to commit to adding data. That generates the meta goal — a do-more goal that gets a +1 whenever you add a datapoint to the do-less goal.
Then a miracle occurs. We show you only your primary goal in most cases but give you access to the meta goal when you need it, without that being bewildering to newbees.
Ouch. Moving on.
Fictional Feature Announcement 4: Hitting Users With Hammers
I think this rounds out all the possible approaches to forcing users to do something. We know that nagging can never suffice so there have to be some kind of consequences.
Pessimistic Presumptive Reports (PPRs) are no more!
How do we ensure that users don’t stick their heads in the sand on their do-less goals and accumulate infinite safety buffer, you ask?
We simply hide all your other graphs if you end the day without entering data on any do-less goal. Now, when you look at your dashboard, if you have any do-less goals without a datapoint for yesterday, all your goals except those goals will be blurred out. So you have no choice but to enter the missing data first.
A message at the top of your dashboard, as well as on the graph page of each blurred-out goal, will explain what you need to do and link you to the most urgent do-less goal (ties broken arbitrarily) that’s missing data.
And what if you only have do-less goals? There are no other goals to blur out so in that case we hit you with the only other hammer we have: After 7 days of no data, and lots of warnings, we delete the goal! Use it or lose it, beetches.
That’s sounding extreme enough to abort for now, though I’m not convinced that something like that couldn’t work, if done really thoughtfully.
Back to Reality
It felt weird to write those. I guess I’m not used to writing fiction. Or it just weirds me out to write things that aren’t true. And at least some of those fictional feature announcements can’t ever be true, since they contradict each other. Which is the other reason it felt weird: Writing each one I started to feel attached to it, like it was truly the Right Answer and the thing we really should do. At least at first. Then as I was forced to think it through well enough to cover everything users would need to know, the cracks started to appear. Which is how I know that none of these proposals are ready to start building yet! That seems obvious looking at the proposals now but it genuinely wasn’t until I went through this exercise.
I’m now excited to debate with you all, both at the meta level, about blog-post-driven / documentation-driven / spec-driven development, and at the object level, about which of those fictional features we should actually build.
Image credit: Faire Soule-Reeves. Thanks also to Faire Soule-Reeves, Adam Wolf, Mary Renaud, Christopher Moravec, and (as always) Bee Soule for reading and commenting on drafts of this. Adam Wolf was especially helpful in thinking through all the fictional feature announcements and even co-authoring part of the intro. Thanks also to all the daily beemail subscribers and forum participants who commented on an early version (without the fictional feature announcements, though an early version of one of those was also in the forum).