Journal tags: universal

2

Putting design principles into action

I was really looking forward to speaking at An Event Apart this year. I was going to be on the line-up for Seattle, Boston, and Minneapolis; three cities I really like.

At the start of the year, I decided to get a head-start on my new talk so I wouldn’t be too stressed out when the first event approached. I spent most of January and February going through the chaotic process of assembling a semi-coherent presentation out of a katamari of vague thoughts.

I was making good progress. Then The Situation happened. One by one, the in-person editions of An Event Apart were cancelled (quite rightly). But my talk preparation hasn’t been in vain. I’ll be presenting my talk at an online edition of An Event Apart on Monday, August 17th.

You should attend. Not for my talk, but for Ire’s talk on Future-Proof CSS which sounds like it was made for me:

In this talk, we’ll cover how to write CSS that stands the test of time. From progressive enhancement techniques to accessibility considerations, we’ll learn how to write CSS for 100 years in the future (and, of course, today).

My talk will be about design principles …kinda. As usual, it will be quite a rambling affair. At this point I almost take pride in evoking a reaction of “where’s he going with this?” during the first ten minutes of a talk.

When I do actually get around to the point of the talk—design principles—I ask whether it’s possible to have such a thing as universal principles. After all, the whole point of design principles is that they’re specific to an endeavour, whether that’s a company, an organisation, or a product.

I think that some principles are, if not universal, then at least very widely applicable. I’ve written before about two of my favourites: the robustness principle and the principle of least power:

There’s no shortage of principles, laws, and rules out there, and I find many of them very useful, but if I had to pick just two that are particularly applicable to my work, they would be the robustness principle and the rule of least of power.

What’s interesting about both of those principles is that they are imperative. They tell you how to act:

Be conservative in what you send, be liberal in what you accept.

Choose the least powerful language suitable for a given purpose.

Other princples are imperative, but they tell you what not to do. Take the razors of Occam and Hanlon, for example:

Entities are not to be multiplied without necessity.

Never attribute to malice that which is adequately explained by stupidity.

But these imperative principles are exceptions. The vast majority of “universal” principles take the form of laws that are observations. They describe the state of the world without providing any actions to take.

There’s Hofstadter’s Law, for example:

It always takes longer than you expect, even when you take into account Hofstadter’s Law.

Or Clarke’s third law:

Any sufficiently advanced technology is indistinguishable from magic.

By themselves, these observational laws are interesting but they leave it up to you to decide on a course of action. On the other hand, imperative principles tell you what to do but don’t tell you why.

It strikes me that it could be fun (and useful) to pair up observational and imperative principles:

Because of observation A, apply action B.

For example:

Because of Murphy’s Law, apply the principle of least power.

Or in its full form:

Because anything that can go wrong will go wrong, choose the least powerful language suitable for a given purpose.

I feel like the Jevons paradox is another observational principle that should inform our work on the web:

The Jevons paradox occurs when technological progress increases the efficiency with which a resource is used, but the rate of consumption of that resource rises because of increasing demand.

For example, even though devices, browsers, and networks are much, much better now than they were, say, ten years ago, that doesn’t mean that websites have become better or faster. Instead, it’s precisely because there’s more power available that people think nothing of throwing megabytes of JavaScript at users. See Scott’s theory that 5G Will Definitely Make the Web Slower, Maybe:

JavaScript size has ballooned as networks have improved.

This problem would be addressed if web developers were more conservative in what they sent. The robustness principle in action.

Because of the Jevons paradox, apply the robustness principle.

Admittedly, the expanded version of that is far too verbose:

Because technological progress increases the efficiency with which a resource is used, but the rate of consumption of that resource rises because of increasing demand, be conservative in what you send, be liberal in what you accept.

I’m sure there are more and better pairings to be made: an observational principle to tell you why you should take action, and an imperative principle to tell you what action you should take.

Ubiquity and consistency

I keep thinking about this post from Baldur Bjarnason, Over-engineering is under-engineering. It took me a while to get my head around what he was saying, but now that (I think) I understand it, I find it to be very astute.

Let’s take a single interface element, say, a dropdown menu. This is the example Laura uses in her article for 24 Ways called Accessibility Through Semantic HTML. You’ve got two choices, broadly speaking:

  1. Use the HTML select element.
  2. Create your own dropdown widget using JavaScript (working with divs and spans).

The advantage of the first choice is that it’s lightweight, it works everywhere, and the browser does all the hard work for you.

But…

You don’t get complete control. Because the browser is doing the heavy lifting, you can’t craft the details of the dropdown to look identical on different browser/OS combinations.

That’s where the second option comes in. By scripting your own dropdown, you get complete control over the appearance and behaviour of the widget. The disadvantage is that, because you’re now doing all the work instead of the browser, it’s up to you to do all the work—that means lots of JavaScript, thinking about edge cases, and making the whole thing accessible.

This is the point that Baldur makes: no matter how much you over-engineer your own custom solution, there’ll always be something that falls between the cracks. So, ironically, the over-engineered solution—when compared to the simple under-engineered native browser solution—ends up being under-engineered.

Is it worth it? Rian Rietveld asks:

It is impossible to style select option. But is that really necessary? Is it worth abandoning the native browser behavior for a complete rewrite in JavaScript of the functionality?

The answer, as ever, is it depends. It depends on your priorities. If your priority is having consistent control over the details, then foregoing native browser functionality in favour of scripting everything yourself aligns with your goals.

But I’m reminded of something that Eric often says:

The web does not value consistency. The web values ubiquity.

Ubiquity; universality; accessibility—however you want to label it, it’s what lies at the heart of the World Wide Web. It’s the idea that anyone should be able to access a resource, regardless of technical or personal constraints. It’s an admirable goal, and what’s even more admirable is that the web succeeds in this goal! But sometimes something’s gotta give, and that something is control. Rian again:

The days that a website must be pixel perfect and must look the same in every browser are over. There are so many devices these days, that an identical design for all is not doable. Or we must take a huge effort for custom form elements design.

So far I’ve only been looking at the micro scale of a single interface element, but this tension between ubiquity and consistency plays out at larger scales too. Take page navigations. That’s literally what browsers do. Click on a link, and the browser fetches that URL, displaying progress at it goes. The alternative, as exemplified by single page apps, is to do all of that for yourself using JavaScript: figure out the routing, show some kind of progress, load some JSON, parse it, convert it into HTML, and update the DOM.

Personally, I tend to go for the first option. Partly that’s because I like to apply the rule of least power, but mostly it’s because I’m very lazy (I also have qualms about sending a whole lotta JavaScript down the wire just so the end user gets to do something that their browser would do for them anyway). But I get it. I understand why others might wish for greater control, even if it comes with a price tag of fragility.

I think Jake’s navigation transitions proposal is fascinating. What if there were a browser-native way to get more control over how page navigations happen? I reckon that would cover the justification of 90% of single page apps.

That’s a great way of examining these kinds of decisions and questioning how this tension could be resolved. If people are frustrated by the lack of control in browser-native navigations, let’s figure out a way to give them more control. If people are frustrated by the lack of styling for select elements, maybe we should figure out a way of giving them more control over styling.

Hang on though. I feel like I’ve painted a divisive picture, like you have to make a choice between ubiquity or consistency. But the rather wonderful truth is that, on the web, you can have your cake and eat it. That’s what I was getting at with the three-step approach I describe in Resilient Web Design:

  1. Identify core functionality.
  2. Make that functionality available using the simplest possible technology.
  3. Enhance!

Like, say…

  1. The user needs to select an item from a list of options.
  2. Use a select element.
  3. Use JavaScript to replace that native element with a widget of your own devising.

Or…

  1. The user needs to navigate to another page.
  2. Use an a element with an href attribute.
  3. Use JavaScript to intercept that click, add a nice transition, and pull in the content using Ajax.

The pushback I get from people in the control/consistency camp is that this sounds like more work. It kinda is. But honestly, in my experience, it’s not that much more work. Also, and I realise I’m contradicting the part where I said I’m lazy, but that’s why it’s called work. This is our job. It’s not about what we prefer; it’s about serving the needs of the people who use what we build.

Anyway, if I were to rephrase my three-step process in terms of under-engineering and over-engineering, it might look something like this:

  1. Start with user needs.
  2. Build an under-engineered solution—one that might not offer you much control, but that works for everyone.
  3. Layer on a more over-engineered solution—one that might not work for everyone, but that offers you more control.

Ubiquity, then consistency.