Skip to content

This is not content

Posted May 2021 in #dev

Having yet to learn my lesson, I’m writing another CMS. My go-to excuse is that solving an old problem in a new language is a great way to learn. In truth, learning a new language is just an excuse to try again. When the unsolvable task invariably remains, at least I’ll have something to show for the effort.

It’s just such an interesting challenge. For example, the managed content should be consumable both in a browser and through an API. The input and output of the CMS should be static when possible, but dynamic when necessary. The system should be self-contained, open-source, easily self-hosted, optionally expertly hosted, accessible and extensible, inspirational yet invisible.

From a stakeholder perspective, the CMS should not expect editors to design, nor designers to code, nor developers to acquiesce to its choices. It should gently steer away from the common annoyances of the modern web. At the same time, the CMS should not attempt to be everything for everyone, but instead aim for a near-zero upfront cost to make it a safe default in the typical case.

From a development perspective, the CMS should not feel like a framework that dictates programming outside its purview, nor like a limited service that subs out one problem for another. Instead it should act like a fronting proxy that helpfully and orthogonally chips away at the ever recurring tasks of making a website.

Stale data beats fresh errors

Posted June 2018 in #dev

A web browser’s back button is more than a link to the previous page. It is the navigational equivalent of undo. Going back should restore the previous page, exactly as it was last time we were there. Conversely, the forward button is redo. These actions traverse history — they should never mutate state.

Luckily, the browser is a capable time machine on its own, at least for regular web sites. It will cache content, remember form values, reset scroll bars, and all the other things required to preserve the browser history. Just make sure to keep Cache-Control: no-store out of your response headers.

However, for web apps, where we make our own little world of routes and state, it’s up to us to tackle time travel. And while an implementation as polished as the browser’s may be out of scope, a little consideration goes a long way.

An expired session is not an error when going backwards. Navigating history should never clear data or result in a spinner. It should not show any sudden 4xx or 5xx errors because of a fetch. Previous form values should be restored, even if invalid. And navigating history should always work — even when offline.

Cherries picked

Posted May 2019 in #dev

  • Things already have names

    Naming things is the hard part, so don’t. Most things already have names. Use the API field, the design files, or ask the user. Projects fail without a common language.

  • Design systems make work

    Graphic tension beats branding if it the friction helps intuition. Design systems where native controls don’t fit only make more work. Users don’t mind the details.

  • The two world wide webs

    The divide between web apps and sites will remain. Apps should use more JS, while sites far less. Interactivity decides. But an unstated premise fuels discord.

  • Scale beats best practice

    Most opinions are wrong at some scale. Availability, security, and accessibility are all spectrums. Taste is acquired through experience in the scale bracket at hand.

  • Cherry-picked tidbits

    Ideas are cheap if you don’t have to think them through. Write out their abstracts in nice little boxes. Readers will helpfully fill in the blanks. People are nice like that.

Unread doesn’t count

Posted May 2018 in #design

There’s a new notification about enabling notifications. The email client tells of three unread spam messages. The settings app has exactly one new system update. Twitter’s tab title counts five new tweets, as always. The home screen is littered with red badges. There’s no value in a predictable notification.

Unread counts are everywhere in modern interface design. They are tasked with retention and growth, often implemented without restraint, and typically end up ignored by most users. But just as in computer science, when it comes to what’s unread, there are only three amounts that count: zero, one, and some.

Most unread counts should stay at zero. This is the kind of feature that works best as opt-in. Better to err on the side of not-annoying. Even if important, many prefer to check counts themselves, at set intervals. And instead of counting to one, show a dot. But not a dangerous red dot. Make it blue, or green.

If there are some notifications, show, at most, a more more prominent dot. There’s probably no actionable difference between 4 or 8 or 16 unread items. However, if there are always some notifications, just remove the indicator. Nobody needs another ignored attention grabber. Leave the user alone.