As someone who creates open-source software, I spend a lot of time thinking about how to make software better.

This is unavoidable: there’s an unending stream of pleas for help on Stack Overflow, in GitHub issues and Slack mentions, in emails and direct messages. Fortunately, you also see people succeed and make fantastic things beyond your imagination, and knowing you helped is a powerful motivation to keep at it.

So you wonder: what qualities of software lead people to succeed or fail? How can I improve my software and empower more people to be successful? Can I articulate any guiding principles, or do I just have intuition that I apply on a case-by-case basis? (Thinking about something and externalizing — articulating — that thought are two very different activities.) Perhaps something like Dieter Ram’s principles for good design, tailored for software?

Good design is innovative.Good design makes a product useful.Good design is aesthetic.Good design makes a product understandable.Good design is unobtrusive.Good design is honest.Good design is long-lasting.Good design is thorough down to the last detail.Good design is environmentally-friendly.Good design is as little design as possible.

I’ve tried in the past to talk about big picture stuff. Things like finding the smallest interesting problem, identifying and minimizing harmful biases in tools, or leveraging related technologies and standards.

The big picture is important — probably more important than what I’m writing about today — but I can’t help but feel that big picture advice is sometimes impractical or impossible to apply. Or worse, truisms. Like saying, “Make it as simple as possible, but no simpler.” Well, duh. We all want things to be simpler. But we may not know what to sacrifice in order to achieve that goal.

And even if you get the big picture right, there’s no guarantee your design will be successful. The execution of an idea matters as much as the idea itself. The devil is in the details.

If I can’t offer actionable big picture advice, perhaps there’s lesser advice that would be useful. A practical inspiration is Green & Petre, whose “cognitive dimensions” framework defines a set of “discussion tools” to “raise the level of discourse” about the usability of “information artifacts” such as code.

Abstraction gradientCloseness of mappingConsistencyDiffusenessError-pronenessHard mental operationsHidden dependenciesPremature commitmentProgressive evaluationRole-expressivenessSecondary notationViscosityVisibility

It’s not perfect; no framework is. It was conceived to study visual programming environments, and sometimes feels specific to that application. (Consider visibility, which refers to seeing all the code simultaneously. Is any software today small enough to be visible in its entirety on a single screen? Perhaps modularity would be better?) I find it difficult to assign some usability problems to one dimension or another. (Both hidden dependencies and role-expressiveness suggest I thought the code would do something other than what it did.) Still, it’s a good starting point for thinking about the “cognitive consequences” of software design.

I won’t be defining a general framework. But I do have some observations I’d like to share, and this is as good a time as any to perform a post hoc rationalization of the last year or so I’ve spent on D3 4.0.

I’m not revisiting the “big picture” design of D3. I’m quite happy with concepts like the data join, scales, and layouts decoupled from visual representation. There’s interesting research here, of course, but it hasn’t been my recent focus.

I’m breaking D3 into modules — to make it usable in more applications, easier for others to extend, and more fun to develop — but I’m also identifying and fixing a surprising number of quirks and flaws in the API. Stuff that’s easily overlooked, but that I believe causes real pain and limits what people can do.

I worry sometimes that the changes are trivial, especially when taken individually. I hope to convince you that they are not. I worry because I think we (that is, people who write software) tend to undervalue the usability of programming interfaces, instead considering more objective qualities that are easier to measure: functionality, performance, correctness.

Those qualities matter, but poor usability has a real cost. Just ask anyone who has struggled to decipher a confusing block of code, or pulled their hair out fighting the debugger. We need to get better at evaluating usability sooner, and better at making software usable in the first place.

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/1c4cbcf5-1647-4b73-b90e-5a1cac9a96af/15p5we6kQBUnJS7MXqzdDYg.jpeg

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/fe3df9c0-ca47-472b-b45a-abba802c2e9d/143y1tWj2XK_pM49LGR8yuQ.jpeg

Mori Masahiro Design Studio, LLC., CC-BY-3.0

You can’t pick up a piece of code and feel its weight or texture in your hands. Code is an “information artifact” rather than a physical or graphical one. You interact with APIs through the manipulation of text in an editor or on the command line.

Yet this is interaction by the standard definition, subject to the complexities of human factors. So we should evaluate code, like any tool, not merely on whether it performs its intended task, but whether it is easy to become proficient, and whether using it is efficient and enjoyable. We should consider the affordances and even the aesthetics of code. Is it understandable? Is it frustrating? Is it beautiful?