UX and DX

Not long ago, I tweeted something about Developer Experience. Which had the most traction a tweet of mine has ever had, by far.

It means to me I said something more people were willing say, or, at the very least, resonate with.

So, let me try and expand on that. I look forward to some nice debate in case you disagree, or some feedback in case you just have something to say about it. So reach out and let‘s chat!

What is Developer Experience?

Let‘s not jump to assumptions that everyone has the same understanding about what Developer Experience (DX) is. Some replies from that tweet made it clear to me that we don‘t.

If you aren’t keen to dig into this definition, you can skip to the next chapter. Otherwise, let’s make a philosophical exercise right now!

There‘s no definitive definition (pun intended), as Chris Coyer has said more elegantly on his What is Developer Experience (DX)? post:

(DX) is a term with a self-declaring meaning — the experience of developers — but it eludes definition in the sense that people invoke it at different times for different reasons referring to different things.

From the article, we can understand that DX is quite nuanced. Let‘s then briefly point out the different aspects of it:

  • Companies when the user-base of such company are actually developers. DX become a synonym of UX

  • Technologies when talking about experience provided by different frameworks or libraries

  • Technology Context when talking about things around said technologies. Documentation, Guides, Tutorials, ...

  • Technology Offerings additions to platform on top of the context. CLI and helpers, for example.

  • Coding the experience of typing code. IDE integrations, compile-time checks, hot reloading, ...

  • User Experience (UX) Some say one degrades the other, some say one boosts the other.

  • Onboarding the time a technology takes to be adopted, size of initial investment.

I will excuse myself and shuffle those cards a bit so I can take some out of the deck to level our discussion. First of all, if developers are the consumers of a product, for constraints of this article: they are the users. So I will take the first 4 bullets and throw them on the User Experience pile.

Now we‘re left with Coding, Onboarding, and the relationship with User Experience (UX). This third one is a paramount aspect of DX, without it our code will crumble down.

It directly impacts the return over investment of the whole product, and therefore to DX. In other words: you can‘t have a good Developer Experience if you don‘t have a product, and you don‘t have a product if your User Experience can‘t retain users. See the chain reaction?

So what does DX really mean?

Let‘s try and summarize what is Developer Experience with our added constraints:

The experience of developers when interacting with a piece of software. How smooth it is to understand, use, and/or alter the code without impacting User Experience negatively.

User Experience

The end-user comes first, always!

As we established before: the end-user is the person who keeps the lights on at any business. They not only pay for the product, but they‘re also the reason the company exists (in the most usual cases, at least). It‘s only fair that such a core aspect of a company mission be front and center to your efforts of evolving the product.

So I would say this is the golden rule of Developer Experience:

  • Don‘t sacrifice UX for DX!
  • Don‘t hurt accessibility and semantics for easy styling.
  • Don‘t increase bundle-size to decrease build time.
  • Don‘t ditch tests for more frequent releases.

Switching gears

Now that we cleared the way by defending UX as the paramount aspect of our products, we can focus on our users. When it comes to Developer Experience, devs are the users.

I consider mostly 5 topics as the most important towards a good DX:

  1. Readability
  2. Extensibility
  3. Performance
  4. Accessibility
  5. Code coverage

Let’s expand on those!

Readability

By transpiling/compiling our code, we‘re now past the time where we had to hand perform most code optimizations by hand. Things like implicit programming and single-letter variables should live only on production code.

We are now lucky enough that we need to write our code exclusively for the humans who will later read or use it, not for the machines who will run it. Of course, to a certain degree! Be sure to write optimizable code, and always check what‘s running on production! Eluding tree-shake for example is quite an easy trap to fall through, for example.

Linting and code formatters are your allies on this, if your code is consistent there‘s a bigger chance it will be more readable and it will make it easier for good patterns to erupt from it. The more readable a code is, the more productive and efficient newcomers will feel. This kind of perception allows for more confidence in tackling tasks and even offering input for improvements. I‘d also go on a limb and say: if the code is welcoming, chances are the team also is.

Extensibility

I believe all of us agree that granularity and abstractions are useful tools for creating code that scales. As frontend developers, we all fell in love with modules, arrived in ES2015, or even CommonJS sometime before. And probably have been guilty of creating those 30-line files. So concise. Import everywhere and let the bundler tree-shake them later.

Sorry, that was sarcasm.

Abstractions and modularization are good, I'm not here to deny that. Though, as most good things in life, overuse takes a toll.

Those tiny modules give us the impression our code is highly reusable. But as time goes by, new use-cases emerge. And since the abstraction is already decoupled from business rules, it‘s logical to just create a new use-case inside our abstraction. A new parameter, a new conditional. And our tiny module grows. Or worse: our application grows around it, twisting and flexing to accommodate into the abstraction proper usage. This is an allegory of the Sunk Cost Fallacy and also the foundation of AHA Programming methodology.

On her article The Wrong Abstraction, Sandi Metz describes really well how a wrong abstraction can cost more for to your code maintenance than a little bit of duplication. Don‘t abstract too soon. Allow some duplicated code to live for a while until the patterns emerge. No need to take my word for it, though, Kent C Dodds said it better on his AHA Programming post:

After you've got a few places where that code is running, the commonalities will scream at you for abstraction and you'll be in the right frame of mind to provide that abstraction.

For a good Developer Experience, code needs to be reusable, easily reusable. Plus, I don‘t need to remind you less code is faster than any code, right? Skip those conditionals and extra parameters by creating the right kind of abstraction.

Performance and Accessibility

These two don‘t add much to Developer Experience in usual cases, but because most of us are privileged enough, it‘s easy to forget it is not a norm. And that‘s when we start overlooking the compound of cases that add up to a terrible User Experience.

Remember our golden rule? There‘s not DX without good UX.

So, set your Accessibility tests early, define a Performance Budget sooner than later. This way, it‘s possible to ship better DX with confidence of not messing up the UX as a side-effect.

Coverage

People need to confidently be able to tweak functioning parts of the code, refactor, and improve them without fear of breaking the application in production. We‘re just as good developers as the tests we write. Everybody write bugs all the time, some get caught at compile-time, some on build, others in integration, and worst case scenario: in production.

There are multiple ways of assuring good coverage. The only footgun is trusting the 100% Coverage mark on your library reports. Testing units, is not testing behavior and user-interaction.

To be more specific, test what user behavior. No impossible states and no forcing weird edge-cases that won‘t really exist. Focus on how your users will interact and the bits and pieces of your code will integrate with each other. Another very good reference is the Testing Trophy (from Write Tests):

Testing Trophy, by Kent C Dodds

Making things work… well

With proper tests and benchmarks, developers are allowed to raise the bar on the MVP (Minimum Viable Product) of whichever thing they are coding. This happens because tests will assure nothing gets left out. And benchmarks will provide actionable insight on degrading quality of the UX.

Conclusion

With that approach, the fallacy that Developer Experience deviates focus from User Experience and treat them as opposing forces is not only moot, but plain wrong. Better DX paves the way to actually worry about things that matter the most to the end-users.

If you liked this article, please consider sharing it with your network. I‘d also love to hear what you have to say about it down in the comments or on twitter.

References

Thanks

Thank you very much to Eva Dee for reviewing this post and giving the final nudge to actually publishing it! 🚀

If you liked this article, please share it with your network! I appreciate it a lot.