Designing DX

👋 Fellow Webnerds!

This is a written version of my talk “Designing DX”. I just want to lollygag about with y’all about this squishy concept of DX. We’ll draw ideas and parallels from the real world (the one with grass, boozy milkshakes, and that glowing orb in the sky that makes you squint). There are things to be learned out there.

DX means “Developer Experience”.

It’s not some new JavaScript framework. Maybe it will be someday because developers sometimes pick horribly unsearchable names. Remember that people who worked for Google made a programming language named “Go”.

My name is Chris Coyier.

I care about DX mostly because I’m a developer and generally a picky bastard. I demand good DX in my tools. I’m like hedonism-bot only the grapes are like cool VS Code extensions.

Also I buy sunglasses that make me look vaguely like a drug lord when I go on vacation just to feel something.

I have some DX cred.

Aside from just being a developer myself, I’m a co-founder of a SaaS website (CodePen), so I’m at least partially responsible for the DX of the tools we use as a team. Alex, my co-founder is the CTO and fortunately he’s got pretty good taste. He’s why I have to write Go all the time (don’t hate it, except the templates).

The product we make (CodePen: Go PRO) is also literally for developers, so I guess we’d better care about DX.

We’ve been working on a CodePen 2.0 for quite a while now. We’ve been taking some 15 years of experience with building and running CodePen, knowing exactly what our users ask for and need, combining that with what we think killer DX for building websites would be, then building that.

Here’s the meat of it. I like to think about DX in narrow pathways. There is a specific job that a developer needs to do, and they are going to use a thing to do it. Good DX of the thing has these four important attributes:

  1. You’re able to do the thing you want to do and it’s clear if you can’t.
  2. It’s obvious and easy how to do the thing you want to do.
  3. Doing that thing is fast and satisfying.
  4. If anything goes wrong it’s clear, actionable, and help is available.

Let’s look at the fairly narrow job of “developer needs to create and edit some HTML”. That just so happens to be a reason someone might want to use CodePen — so it’s near and dear to my heart.

HTML is literally a plain text file. It’s not a proprietary format. It’s just got an .html file extension or .htm if you’re nasty.

Make whatever.html and open it in the browser and will render that bad girl.

My multi-thousand dollar Macintosh™️ computer doesn’t come with any software particularly well suited for this job 🫠. There is the terminal I guess but I’m not one of those VIM weirdos [squints].

The closest thing with a “User Interface” is TextEdit. Mega bonus points for being “free”, pre-installed and ready-to-go.

But TextEdit really wants to create “Rich Text” documents with, like bolditalic and images and whatever. Like a little baby Microsoft Word. Nobody wants this but that’s what it does. If you want to write actual HTML syntax, you need to know to come into the settings and change it to Plain Text format.

Even if you take that Very Extreme® step of changing that setting, if you try to save a file with an .html file extension, it throws up a warning saying that better people than you actually use .txt thank you very much.

Plus it asks you that every single time. It doesn’t do something reasonable like remember.

That’s a video on the left.

It’s of me trying to write HTML in TextEdit.

Notice how it doesn’t help me at all in absolutely any sense of the word.

I’m only sort of setting up a strawman here. Mostly I want to paint a picture of just how far we’ve come with the DX of even such a simple task as writing plain text HTML. It’s gotten pretty good, you’ll see.

Nobody codes typing every character of the final code by hand. I’m not trying to be hyperbolic: I’m pretty sure literally nobody seriously codes that way. Better tools are free and easily available.

This is what the editor is looking like so far on CodePen 2.0, where all I’m doing is writing some HTML. I’m not showing this to wildly impress you, but to show how far we’ve come with this simple plain text editing job.

I’m not just writing HTML but seeing the results of it. I can wipe it all away and bring it back with a snippet. Autocomplete helps me finish what I’m thinking with valid values. Syntax highlighting makes it look nicer. Automatic indentation help it feel nicer. And there is so much more.

One difference when we’re considering this “the job is to write some HTML task” is that CodePen puts a basic scaffold of HTML there for you.

The user can delete it, they can change their defaults, they can start from a different template, they have lots of options.

But, by far, the most important thing is whatever the default is. Just give developers a common working state.

All this is easily satisfying #1: They are able to do the job.

I love me some settings, but I’m Power User McGraff. If you’re sitting in a meeting and someone is like “we could make it a setting” you should say: “Yep, we could. Maybe we even should. Just know that 1) it’s technical debt forever and 2) it matters 10✕ more whatever the default is because most people never touch any settings.”

So we know our hero tool is able to do the job of writing HTML, but is that job easy and obvious? (Another core tenet of DX)

Let’s first step out into the real world for a moment: we’ve got a new job. We pull our car up to our house, and we need to get the car into the car hole garage.

What is the tool at hand now? Yes: the aptly named “garage door opener”. It opens garage doors.

There are lots of other little things at work here, like the fact that garage doors are slatted and hinged so they can roll up on tracks, making more useful garage space. Plus the fact that the garage door is actually counterbalanced by large springs making it easier for the garage door opener to open it. (There are tangential areas for improvement!)

Is the garage door opener easy and obvious to use? That is, core tenet #2 of DX. Indeed it is, it’s a button! You boop it! It opens the garage!

A single button that does exactly the thing you want it to do is an excellent user interface.

Can your thing be as easy as a button?

The keypad for garage door openers are arguably even more important. Garage door openers were invented in the 1920’s but didn’t take off until the 1940’s when they keypad came along. The experience matters!

So garage door openers are easy to use, but are they fast and satisfying? That being core tenet #3, of course. Sure, I’d argue that they are. It’s certainly faster than getting out of your car and manually lifting the door up. If it’s raining you better bet that’s satisfying.

The satisfaction can come in other ways, though. For instance, my garage door opener (and most do) has a light on it that comes on when you interact with it at all, including opening the door. It’s a little, perhaps obvious, thing, but it’s like thanks little guy! I absolutely prefer driving my car into a room that isn’t pitch black. These jobs that people need are directly related, so do them both!

Can your thing do ancillary helpful and satisfying things?

What about when things go wrong? A power outage is common, where the garage door opener stops working and actually prevents the door from being opened.

But there is a solution: a RED cord that hangs down. Pull it, and the opener disengages and then you can open/close the door manually.

Is that red cord perfect? Nah. There have been multiple times in my life I’d had to teach someone how to do that, so it’s not as clear as it could be. I’m sure I was taught it at one time. Maybe some kind of switch could be built that would put the door in manual mode when the power goes out?

It’s fun to think without limitations on how any part of this could be better. Don’t always worry about how it could be made, how to market it, how expensive it is, etc. What if the door was a force field? Disengaging that would be a heck of a lot faster than waiting for the garage door to slowly open.

You don’t ever need the boop button on my wife’s car, it just automatically opens the garage when she pulls up. As much as I love the button, that’s clever stuff.

Thinking even bigger, what if we didn’t need garage doors at all? We use them to keep the car safe and warm and away from the elements, but what if there was some kind of wild Batman Car Shield we could invent instead?

Let’s move back into actual technology.

It’s become almost table stakes for a framework to provide what I called common working state. Right on the homepage for Next.js we can see:

npx create-next-app@latestCode language: CSS (css)

Developers will recognize that as a CLI command. Run it, and a Next.js app will be scaffolded out for you quickly. This would be a lot of fiddly work to do by hand, so they are very smart to just do it for you. It feels impressive and helpful.

Astro does the same exact thing with:

npm create astro@latestCode language: CSS (css)

Here’s how that looks to use. The video here is exactly one minute long. Not bad as it includes the complete npm install.

Is there common working state you can give to the users of your technical product? Is there anything at all you can just do for them?

You should just do it.

Shia Labeouf said that once and it was so impactful Nike later picked it up as a slogan.

What about coding itself?

That’s a huge part of DX. I’ll say: obviously.

This is a massive opportunity for being helpful, that is, making the job the developer is trying to do quicker and more satisfying.

These days, we’ve got THE TRIFECTA of things trying to help us inside the code editor:

  1. Snippets (e.g. user custom, installed, Emmet, etc)
  2. IntelliSense (e.g. Autocomplete)
  3. AI (several forms)

Here, watch them all work together at the same time, allowing a user to take advantage of whichever seems the most helpful.

That is tricky stuff, people. And I don’t think it’s perfect.

Here’s the rub. Snippets are typically invoked with TAB. IntelliSense is typically invoked with ENTER. But now AI comes in with the ghost text typeahead, and it needs a key too. So far (e.g. GitHub Copilot in VS Code among many others) have absconded TAB. That means snippets and AI are fighting for which one gets to respond to that TAB (not to mention TAB is for tabbing!). So the DX here requires a lot of nuance. Right now, AI typically takes a second or two to kick in, so if you want a snippet you’ve got a second to hit it, then it’s replaced with an AI suggestion. That’s… OK. Not great but OK. It gets worse as AI gets faster (so it might be smart to keep AI purposefully slow, take the time to be smarter!). Or you have to hit ESC (or something) to whisk away the AI and hope the snippet will still work.

This is all awkward, yet interesting territory and I think it will take time for the DX of “code help” tools to shake out.

Speaking of being helpful.

Syntax highlighting is an amazing feature of coding. It’s certainly not new, but it’s worth thinking about.

It helps “reason about” code. The reference to an object and the method on the object will (probably) be different colors. Syntax highlighting helps us understand that quickly. Brackets of matching color frame chunks of code that is grouped (indentation helps with this too).

Better, when code is malformed the first line of defense is syntax highlighting.

CodePen’s “High Contrast” themes have pretty error-looking colors when there is broken HTML.

Back in the real world, we can liken this behavior to rumble strips along highways. If things are going a little wrong (put your phone down, jeepers crimeny) you are warned with sight, sound, and feel. This is designed to help you get back on track before things get worse. The same kind of benefit of syntax highlighting.

What can your tech product do to help push people back in the right direction without being too heavy handed about it?

This is a DX classic, and I agree heartily:

Make the right thing easy.

Heck yeah. We already looked at with providing a common working state (that working state should be excellent: good accessibility, good performance, good design, whatever metrics apply).

If we were, say, applying this concept to an API, an example might be requesting records should be paginated by default. This is probably the right thing, and ensures queries aren’t too heavy by default.

But making the right thing easy has a sister: making the wrong thing hard. This is what smarter people than I call the “Pit of Success”. If you making doing the wrong thing hard/annoying, you’re protecting people on two sides and they are much more likely to succeed that way.

React’s dangerouslySetInnerHTML prop is a perfect example of making the wrong thing harder. If you have a bit of raw HTML, it’s the wrong thing, generally, to just plop it onto a page (that’s ripe for XSS security vulnerabilities). So React automatically escapes, and thus makes safe, that HTML, but it also won’t really be HTML anymore, it will be a string representation of that HTML and probably not what you want. If you absolutely know it’s safe and need to do it anyway, you can but it’s annoying in that you have to use this weirdly named prop and pass in the value in a bit of a convoluted way.

Red squiggles are the best DX concept ever. They are in the same bucket as syntax highlighting in the sense that the intention is to alert you to problems, and they do it in the perfect context: exactly where the problem is.

TypeScript is a quintessential example of red squiggles. Red squiggles are in fact most of the value of TypeScript. They point you toward problems in your code and give at least some indication of what’s wrong.

One trait I love about them is they have various levels of intensity that you opt into just by interacting with them. You may just see the squiggle and that’s enough and can fix it from there. You might need more info so you hover over it and get whatever messaging TypeScript can muster up. Or you might need to leave all the errors “expanded” so you can see the error message in a more stable format while you deal with it. That is intentionally built DX.

At CodePen we’re of the opinion that a high level distinction can be made about squiggles. Some squiggles are show-stoppers. Bad syntax, bad config… whatever it is that actually prevents the code from being usable at all. That’s a red squiggle.

That is distinctly different than code that might be a problem. That’s everything a “linter” might tell you about your code (e.g. a different type of loop would be better) but it could also be things like a config file having a value that doesn’t match a schema. It might be a problem but it doesn’t need to prevent the code from running. I feel like a lot of TypeScript could be yellow squiggles honestly.

We call these messages about the code to the coder “diagnostics” and spent a lot of time figuring out how best to present them. The dial, so to speak, needs to be turned up to the point they are obvious and actionable, but not so high they are actually annoying.

Speaking of linting (and formatting), these are the tools that help developers be as opinionated as they want to be. I probably don’t need to tell you that developers are awfully opinionated. If you have 45 minutes ask a developer what kind of socks they like.

It’s a double whammy though. Developers can be opinionated about some code related thing, and be opinionated about the tool that helps them enforce the opinion.

Tabs vs Spaces is a classic example. Yes, you probably have an opinion on this. Great. But I’d be willing to bet your actual opinion is that you have some preference, and you want it to be consistent and not to have to think about it constantly. That is: an opinion about the tool used and its config.

My yard sign at home.

When I started writing Go code, I found it interesting that the language itself ships with a formatter. It doesn’t even feel optional really, everyone uses it, and thus all Go code in the world looks the same.

It’s great.

After that silly Silicon Valley episode, Business Insider did research on GitHub repos by language to see how the tabs vs spaces thing played out across different languages.

I used to be a spaces guy so part of me isn’t surprised seeing it dominate most languages. I learn toward tabs now because there are some clear advantages (accessibility being the biggest) and mostly it doesn’t matter.

Notice Go: it’s 100% tabs.

Fortunately, Prettier exists for the bulk of front-end specific languages and it does a great job.

The DX of using it is rather fascinating to me. Prettier is just a software program. You feed it some input (a file of code) and config and it produces output (your file of code, formatted).

When does that happen, though?

You could (and can) call it at the command line with an API. You could use it’s JavaScript API. You could wire it up to your GitHub precommit hooks and not allow unformatted commits. Or make it part of your CI process and autocommit formatted code in case any slips through.

All those are fine and things that teams can do (and, ahem: do do). But they aren’t why Prettier is loved.

Prettier is loved because it has the same interface as your garage door opener: boop.

Prettier (by virtue of code editor integrations) runs when you save a file. That’s the real DX innovation. It’s the perfect place to slot it in. You’re likely done with a bit of work, habitually saving, taking a breath, and now formatting your code. It fits into a natural cycle.

Another thing to love about Prettier is that it respects a wider “standard” of EditorConfig. If something better than Prettier comes along, or Prettier gets cancelled or whatever, the new tool can respect the formatting settings in an .editorconfig file. That’s lovely and I wish more tech worked that way.

Remember how syntax highlighting is like rumble strips for coding? Formatters (like Prettier or gofmt) can be like that too. If your code is too jacked up to be formatted, it’s a poke in your ribs to fix your shit. In my experience, it becomes priority #1 to get that fixed before thinking about coding anything else. And I don’t mind! I like the DX of slightly-increasing annoyingness to produce correct code.

Developers are more opinionated than most, but everyone tends to have them. People tend to have a fairly strong opinion about window vs isle seat if they fly a lot, for instance.

Most people like the window. Friggin weirdos if you ask me. I don’t like having to ask someone to get up to pee.

Knowing that people have those opinions, software can be built to accomodate them. Delta allows you to simply save your preference, so that when booking it can default to that, or if they need to upgrade you or rebook you they can do so and stick to what you like.

Surely not that many people actually do that (nobody changes defaults, see above) but for those that do, it’s a very appreciated gesture and cultivates loyalty.

Opinions opinions opinions.

Developers have favorite keyboards and mice. They certainly have a strong one about their operating system. They likely have a browser you’ll pry from their cold dead hands. And it goes on and on and on.

Now here comes you. Building a thing. For them.

You’re rolling in thick with an opinion.

Your opinion is: use my thing.

If you’re going to do that, it’s almost your duty to then be unopinionated about as much else as you can. Your thing should work with other things seamlessly. That’ll probably be work, but hey, that’s the job here.

At CodePen we have (and are building) a web-based code editor. So our opinion is: use that editor. And the plan is to be as flexible otherwise with the other things developers might want to do.

Strike the right balance, and people will love you and your thing because of the opinion and because of the lack of other opinions.

I’m sure Redwood is great and all, and has it’s fans, but it seems like it’s behind other frameworks in it’s cohort.

I’d bet you a glazed donut it’s because it rolls too deep with opinions. That stack of opinions is simply too big. They might be great opinions and developers like it when you come in with opinions, but not ten. Ten is too many opinions.

Time between doing some work and seeing the results of that work is crucial. That’s why being a gravedigger is so satisfying. Shovel, hole.

In computers we have to wait for computers to compute. Computers are incredibly fast, so of course we make them do the most complicated shit imaginable to make sure websites at least take a couple of seconds.

Most coding is a two-panel game (at least). Code in one area and see output in the other. The smoother you can make that, the better the DX. It’s worth literally building tools to improve it.

You can imagine writing HTML then seeing that HTML rendered in a web browser, that’s a feedback loop I’ve spent my career on. But it’s anything really. You could be writing Ruby code and having it triggers tests that run when you save the file. You could be writing an integration and watching your terminal log out data and events as you work.

How fast do you want that feedback loop to be? What if it was an hour? I guess you’d be careful as hell what you punched on those cards with the code you write as silly mistakes will take ages to emerge. Any amount of minutes as you’ll almost certainly get up to do something else. Any amount of seconds and your brain will wander.

It’s not until a feedback look is one second that you brain won’t leave the task at hand.

It’s not until 100-200ms that the task feels instant. That’s the goal of course. Instant literally makes developers do better work.

A version of an instant feedback loop is an affordance, a term I heard in Don Norman’s book The Design of Everyday Things.

This is not I teapot I own or have ever used, but I immediately understand it. It has a handle, you pick it up with that. It has a lid, you can open it there. It pours out of the spout. Done deal.

This one is metal and has a stove-burned sized footprint, so, ya know, it goes on the stove. The handle says: “this thing gets hot so this design helps you pick it up anyway.”

Designs can be very different and even work a bit differently, but affordances ensure we understand it and likely can use it immediately.

Here’s a device I saw in the same category. It’s designed to go on the stove. But it looks plastic so that’s scary? And there is no handle so where do you pick up the thing that affordances tell us will be hot? And why does it grow blue-ice looking designs on it when it’s… hot?? And it’s multi functional apparently but how do I know that? It’s probably innovative in certain ways, but the company doesn’t exist anymore, so what does that tell you?

I heard about this term from my boss Kevin Hale who I worked for at Wufoo who I thought was a great designer. It’s a Japanese term that means to “mistake proof” something.

I don’t know if this is the perfect example but it’s one I think about.

Gas pumps have gotten better over the years. We can do it ourselves (I like that, I don’t like having to wait). We also don’t need to go inside first, we can do it all right at the pump by inserting a credit card.

But ooops wait, it’s the wrong way, oops it’s backwards, derp. Happens all the damn time.

So screw inserting or sliding, let’s poke yoke this sucker.

Now you just tap it with your card. Can’t be upside down or sideways or even have a scratched up swiping strip. It just works.

Better still, you can boop your phone or watch it on it which is likely even handier than getting out a credit card.

It’s not perfect (I love those hand written notes explaining exactly where you need to boop it) but it’s in the right direction.

What you can you poke yoke on your thing?

Remember this user interface in the movie Total Recall?

It’s amazing.

This weird ass alien comes out of a dude’s chest and tells Arnold Schwarzenegger he needs to start the reactor in order to bring back atmosphere to Mars.

But Arnold…

But then he sees the user interface for the reactor and is like: oh.

It’s like the garage door opener of alien atmosphere generation technology.

I actually kinda like it better, so I did this mockup for someone to build later.

Think I used AI for that? You bet I didn’t I used Shutterstock and Photoshop like jesus intended.

Let’s do another tech one. Say we’ve made a website locally and we want to now put it on the Real Internet.

Not all tools do all jobs, and that’s fine. But sometimes it means hunting around for tools that do help us, which is why developers are always on the prowl for good DX. If we have to pick tools, impress us.

Buy a domain name

Buy web hosting where we can put code for the website.

Configure the web hosting to allow yourself to upload files to it and be running the web server software you need.

Use a tool like FTP to put the files into the correct place on the web hosting.

Configure the domain name to point to the web hosting.

Wait (DNS)

Website!

For most of my formative years of making websites, these were the steps. It’s kind of a lot of steps!

I think of the book Jobs to be Done here. Or at least the principal around it that is how people talk about it. Hone in on the thing that a person is actually trying to do. Don’t be fooled by what a product says it does or how it’s marketed but the real life task the person has in their brain.

I need to put this website online.

That’s a job-to-be-done.

It’s seven steps, and involves at least three tools. The place where you buy the domain name, the place where you host the site, and the tool you use to move the files to the hosting.

I credit Heroku for being an early player (the first?) in crushing this job-to-be-done. Part of the innovation was putting the tools to do this right at the command line where users are building their websites already.

Run a single command, your website files shoot up the cloud and becomes a website.

This takes a 7-step, 3-tool job in to a 1-step, 1-tool job. That rules.

All hosts worth their salt do this now in some fashion. The Netlify, Vercel, Cloudflare, etc of the world have their own innovation in reacting to Git commits rather than CLI commands, which honestly I like even better.

Here’s my updating a website on Cloudflare Pages. So satisfying.

DX is the product and using the product. Technical products tend to have a degree of complication by their nature. They tend to need documentation to fully understand how they work.

Airtable has pretty decent docs.

Their docs actually show example code for every part of their API. Better, they have a little toggle to add your API key to the code, so if you need to quickly execute it to test it, it’s a copy and paste job.

Sadly, I’m told that in the short time between when I took these screenshots and publishing this, they have removed that feature as it’s all token-based now. Booooooo.

What’s better than that?

The docs are scoped to literally the exact table I navigated to these docs from. These aren’t generic API docs, they are specific API docs.

What would be better than that?

Prove it! The code is sitting right there, why don’t they allow me to run it right there and see the results?

What would be better than that?

Let me edit the code! You’re just a data warehouse, a lot of the value is in me getting the data out in a useful way. Let me play!

What would be better than that?

Host the code for me as a cloud function. Why not? It’s cheap and secure and a nice little upsell. Give me a URL to hit that runs a bit of code and ships me exactly the data I want with my own custom logic.

What would be better than that?

Poutine.

They put cheese curds and gravy on fries it’s wild.

Thanks!

Thanks for checking out my talk.

Feel free to support independent software that loves you back.

Thoughts? Email me or comment below. Also CodePen PRO is quite a deal. 🙏

Leave a Reply

Your email address will not be published. Required fields are marked *