System Design

Stop persisting defaults!

4 min read

Not every option is always explicitly set. Libraries offer many optional features that you don’t necessarily care for. Web APIs need to provide sensible defaults. No one wants to burden users with filling out a form containing every single setting they provide before they even get to register. A desktop application should work out of the box while offering the ability to customize the experience somewhat.

If anything, we sometimes don’t provide enough options, because it increases the testing surface (functionally and security-wise).

Software is also improved incrementally. Web applications need to be able to perform migrations without all their users being in the room, ready to check whether they would like to use the newly-added dark theme. Library developers need to be able to add new options for users that need them.

Options are a must.

But please, when adding new settings, do yourself a favor: do not persist them. What may seem like a boolean (binary) option is actually a ternary option.

When you launch your new product redesign as an opt-in beta, the default is of course off, but only at that given time. Users who do not explicitly turn it on are expected to be moved over in the future automatically. Those who explicitly choose to stay with the current (old) design would like for that preference to be persisted after the redesign becomes opt-out. Although this preference may seem binary, for you to be able to move indifferent users over to on, you must actually design it as a ternary option. Often, this would be a boolean that can also be null.

Do you see the mistake?

-- PostgreSQL syntax
ALTER TABLE user_preferences ADD COLUMN use_redesign boolean NOT NULL DEFAULT FALSE;

DEFAULT is applied to existing rows and persisted. When in a future migration, you change the default value:

-- PostgreSQL syntax
ALTER TABLE user_preferences ALTER COLUMN use_redesign SET DEFAULT TRUE;

Existing users still have use_redesign set to false. This would obligate you to set use_redesign to true for all users:

-- PostgreSQL syntax
UPDATE user_preferences SET use_redesign = TRUE;

What you actually should have done here, is keep the column nullable. Tables which do not have a NOT NULL constraint effectively also are DEFAULT NULL:

-- PostgreSQL syntax
ALTER TABLE user_preferences ADD COLUMN use_redesign boolean;

Many interactive command line interfaces make use of rc files to store a user’s preferences.

Let’s take telemetry as an example. You might start off with telemetry being opt-in and unprompted. Later on, you get a ticket to change this to be opt-out. But, oops: you persist default settings to their .rc file. This was requested by a user to make settings more discoverable.

Instead of persisting

telemetry=0

You really should have persisted the setting commented-out:

# telemetry=0

And defaulted to 0 only at launch, in memory.

Now you will have no choice but to wipe the setting, for example, by naming it something else. Otherwise, only new users would ever give you any data points.