What is DX?
Developer Experience (DX) is the equivalent to User Experience (UX) when the user of the software or system is a developer. DX describes the experience developers have when they use your product, be it client libraries, SDKs, frameworks, open source code, tools, API, technology or service. DX shares some ideas and philosophies from UX design (or HCI), but builds on these with an eye towards modern technology and standards.
Why does it matter?
DX matters for the same reasons good UX matters. Users of your technology are happier, promote it more, and stay longer when the product has good DX. Happy developers are chatty developers, and when we talk to each other to recommend products, the ones with the best DX are at the top of the list. Follows is my list of best practices when it comes to DX. Do these, and youâre well on your way to success.
The Guidelines
Communication
Good communication is key to a successful developer experience. The way you speak to developers is crucial to how they perceive you and your product.
Tone: Be Authentic, Open and Honest
The way you speak to developers is crucial to how they perceive you and your product. Developers can smell bullshit, and they donât like fluff. If you be honest with developers, theyâll respect your product more.
If you have a data breach, a bug, a period of downtime, or some data loss, be clear with this. Create a status page and comms system and use it to communicate with your developers. Be honest about your timelines and be prompt with any post-mortems or debriefs.
Communicate product roadmap with product forums, and let developers contribute to those priorities directly. Engage with them, ask them what they think.
Great Documentation
Your docs are your voice to the customer. But what makes for great documentation?
Always write your docs as if the developer is a beginner, not just with your technology (which they definitely are) but also the platform for that technology. If youâre documenting an NPM module, include a link to how to even install NPM in the first place, and how to include the code into other JS files. If itâs a ruby gem, the same thing.
Consistency of language in the docs is also important. If you have multiple contributors to documentation, make sure theyâre all using âfunction instead of âmethodâ, or âpackage instead of âmoduleâ. This also is important for your own product related nouns, such as âActivity Log instead of âLogâ. Being consistent stops readers from becoming lost and second guessing what theyâre reading.
Thirdly, a logical layout and structure to your docs is important. Surface common reading, and lay out docs in order of integration steps. An âOverview with core concepts then âGetting Started section with installation and/or set up is a great start. What follows after that depends on your product, but you should know based on what you expect people to do â just document that expectation.
Finally, verbosity is always great in docs. You can never say too much. Itâll be one sentence or a few extra words that really helps a stuck developer. Itâll mean the difference between a developer who feels comfortable and supported versus an irate one calling your support line. Docs can sometimes feel like a last minute thing, but slowing down, investing in them, will pay dividends in the long run.
Good Release Notes and Changelogs
When releasing a new version, itâs another important time to be on the ball with communications to developers. Explain clearly what is new, what was broken but now fixed (yes, own your mistakes, please), and what any risks of this version is (eg, this might break x). Even better if you can link to a public issue tracker for these for more detail. Why? Well, when developers want to catch up on versions, they want to be able to quickly scan the release notes or change logs and try find the thing theyâre looking for. They might be asking âwhich version did this get deprecated in? or âwhat version did x get added? or âwhat version did they fix the bug Iâm experiencing?â. If you can answer these in your release notes, then youâve nailed it. Release notes are also a good place to point out any security vulnerabilities that have been fixed, which obviously add more motivation to update. Developers should always be motivated to update to the latest version. Having them on the latest version also reduces support overhead.
Respect Standards and Idioms
When writing a client library, SDK, API, etc, itâs important to respect the standards of the industry and/or community and idioms of the platform from those gone before you.
Respect Platform Idioms and Toolsets
I work on an iOS SDK as part of my day job, and when I do this, I must always be mindful the app developer using this. What Xcode version are they on? What language are they using? Objective-C or Swift? How can I make this API work better with either of them? While just an anecdote, itâs important you also think of the same thing. So, think to yourself, what tools are people using to interact with me? What *versions *are they? Do they make a difference?
Donât Assume Programming Paradigms
Itâs easy to think that because you like a certain style of programming, others will like it too, but this isnât always the case. For example, if you like functional programming, you may be tempted to write your library with a functional interface. Please donât. Write it the plain, or more traditional or standard way, such as plain JS vs a Fluent Interface or plain Ruby or plain Swift vs a functional style API, or a Java Builder pattern vs just an object to construct, and then also provide a wrapper or facade for a given style. That way, everyone can use it, and no one has to learn a new style of programming just to use your code. If there is no given paradigm, chose what is best, preferably most likely to prevent mistakes and a quick time to learn.
Consistency
Consistency is key with interfaces for developers. Very much for the same reason as in UX, it stops people from making mistakes. Be consistent with the rest of the language or platform. For example, letâs say you have a simple library that talks to and endpoint and provides a native object for use. If youâre writing Java or C#, your asynchronous methods might expose a Listener pattern, which is very consistent with the language. However, if youâre writing Swift, you the equivalent method might expose a callback. If itâs in Javascript, it might also be callback, but it could be a Promise. Figure out whatâs common on the platform by researching other code (with the ultimate source of truth being the platform source itself), and then use that.
If it doesnât matter, then be consistent between your different libraries across the different languages, but platform consistency comes first. Methods should be called similar names across the platforms, so developers integrating in multiple languages can gain momentum, and generally because itâs just cleaner. This goes back also to* Respect Platform Idioms and Toolsets *above, keep this in mind as you ship code for a certain language or platform.
Be a Good Citizen
For code that will be embedded in other peopleâs code (such as frameworks and libraries), itâs best to make sure your code isnât going to be a cause of concern. If anything, this code needs to better than the code itâs in as it should never be an issue.
Method Annotations and Docs
If youâre exposing methods, try use annotations to indicate a few things. Some languages like Objective C and Swift provide these features, where as some tools like Android Annotations provide this. The first is nullability, can the thing you pass me here be null? What does that mean if it is? And can what the method returns also be null? With these explicitly called out, Developers can change their style to code more defensively or not around these cases. For as something as simple as adding an annotation, you may save your users a NullException or similar.
Secondly, over-document. Document each parameter and method carefully, and name them well. Probably name them better you would your internal names, in an effort to make them accessible to beginners. The more documentation about how to use the method, any prerequisites or postrequisites it needs, and a hint to how it works, and any equivalents it has or redundancies, and any side-effects.
Not only will this help external developers, itâs also great for your internal team to get up to speed if theyâre making a change to the code. Well documented code is great. The usual rules of âdonât over comment and âyour code should be self-documenting just donât apply for external code. The more the better, always. Itâs about reducing confusion and stopping that support line phone ringing.
Method Removal and Deprecations
If you want to change your mind about some external methods, youâll need to slow down and let your developers adjust. The recommended approach for this is to introduce the new behaviour and deprecate the old. Deprecate refers to functions or classes that are in the process of being replaced by newer ones. What you must not do is just remove functions or change their behavior, as this will almost certainly affect other code that interacts with it. You should always deprecate the old first, an in a future, preferable major version(more on this later) remove the deprecated methods. Deprecated periods should last at least a month, but can last up to a few years.
Youâve probably felt me defining deprecation above was a bit silly because youâve seen and dealt with them before, well, *exactly â *itâs a great way to communicate and youâre used to it â so do it yourself when youâre the one providing the code.
Non-Colliding Namespaces
If your language that youâre programming with doesnât have namespace or package support, then you should prefix your code to avoid this. This is fairly common in Objective-C, where a lot of provided classes have the NS- or UI- prefix. My code as SJ in front of it, for my name, or sometimes a acronym based on the name of the project. Using two or three letters (preferably three) reduces the risk of errors during compile time, where your code is named the same as something in the rest of code.
If your language supports namespaces and/or packages, make sure these are also configured for the same reason.
Threading
Arguable more aimed at mobile development, be careful with threads and processes. Try use a secondary or background process to do your work such that actions such as UI work arenât blocked by your code. Because of this, code with common multi-threaded pitfalls in mind, and test carefully.
Be Open Source (At least try!)
While I acknowledge that some code must stay closed source, if not required, have it be open source. Follow the open source best practices, which, in themselves are part of a good DX. This advice is more of the same as above, centering around good communications.
Why Open Source?
Open source code is more trusted by developers, and anecdotally, more developers are exclusively using only open source dependencies in their products. Theyâre able to look into the source and find and fix bugs, as well as inspect it for any code that is questionable, and remove it.
Great Read Me
Whatâs in a great Read Me? A full list here is here, but in short, a good description, installation notes, good (trivial examples), contribution guidelines and any known issues. Links to more docs is also great. Some of the best projects I see also shout out top contributors, or shout out notable users of it.
Safe Space for Contributions
Having a Code of Conduct for your open source efforts is super important. Your users could be anyone, and their contributions should be welcomed and protected no matter who they are. A code of conduct (even the one Github gives you by default) is great, as long as you action it if it is broken. Create a safe space for contributions, remember, these people are probably adding value to your company, why not do the best for them that you can?
Open CI
If possible, and if it makes sense to, open your CI system too. Most hosted CI systems are *free *for open source projects, so just hook it up and tie it in. This will make it easier to contribute with pull requests and makes it easier for you to review and accept or reject contributions. Some would even recommend going further, and using bots. Use what you think you need. More active repos will need more automation to scale.
Make It Easy
Make it easy for developers to actually get your product and integrate it. Itâs amazing how many products would benefit from developers using it, but donât understand how they think.
Clear Pricing
The first of these is clear pricing. No developer ever will ever click a âBook a demo button. Let us have a free trial, or pop in our credit card and give it a spin. We want to know how the pricing works and what variables control how much it cost. Even better if that makes sense to us, eg things that would cause more costs for you, such as higher number of requests or more compute time used.
Sure, value-based pricing is a thing, and you may want to work out a deal for larger customers, but if freaking SpaceX can have a pricing page, so can your software product.
Self Serve Option
As above, we want to be able to use it ourselves. We donât necessarily want to sign a custom contract, have to get on a call with a sales person, or pay an implementation fee. We just want to sign up, integrate it that day and see if the price makes sense for the value weâre getting. Sure, your business may not work like that (and thatâs okay), but thatâs a compromise of the model, you miss out on a self-serve market. And as above, developers are a chatty bunch, and they might recommend your product to their friend who works for that customer youâve always wanted, so you never know. But, of course, use your best judgement.
Versioning
Version your code and products correctly. Semantic Versioning (SemVer) is what the industry has landed on, and itâs good, and you should use it. In short, a version number should have three parts, three numbers. Eg, âX.Y.Zâ, or âMajor.Minor.Patchâ. Patch releases fix bugs. Minor adds small features, and major removes deprecations and releases bigger features. So, when versioning, think carefully about what version number you are really meant to use, such that you communicate to developers the impact of the version. And sorry if you spent two weeks on a change, it might only still be only a patch version. The *semantics *of the version number matters more.
Packaging
Most languages now have one or more accepted way to distribute code. Thereâs NPM and Yarn for JS, RubyGems for Ruby, Nuget for C#, Maven for Java, CocoaPods/Carthage/SPM (grr) for iOS, PIP for Python⊠and the list goes on. Your code should be distributed by this way as well. As a developer scans your installation docs, theyâre looking for the line that installs your product via one of these systems, theyâre looking for gem ĂąâŹËSamâ or npm install sam in the first paragraph. Take the time to generate the files required to interact with these systems, and use Git Tags and SemVer to create and push releases to your users.
Secondly, if the packaging system supports code signing or security features like that, be sure to use those, so your developers know the software came from you, and is less likely to be compromised.
Do Your Best
To finish off, we get onto the obvious stuff about the actual quality of your product.
Use Your Own Stuff
If youâre shipping anything that a developer will use, be sure to always test it as if youâre a new developer. Create a fresh project, integrate it and test it. Try to rule out any false positives from your dev environment and really just eat your own dog food. The more you do this, the more knowledgable youâll be about the integration process, and thatâll lead to finding gaps in documentation, ReadMes and much more. Give this task to someone on your team completely unfamiliar with the product (or a friend if youâre solo) and see what they find confusing, and improve from there.
Feature Set
The feature set of your product must match what a developer has come to expect from competitors. However, you might have something they miss, and that might indicate a UX problem, or poor DX. Ask developers what is missing, and use that crucial (and free) feedback to make your product better. A good product also scales under load or is built for purpose well. It is also secure noting the latest concerns and keeps its dependencies up to date.
So thatâs what makes for great DX. In conclusion, a lot of DX is just doing what youâd expect if you were a developer. Put yourself in their shoes (and remove your knowledge of the subject) and try see what youâd expect, and do that.
Have Fun
Developers, like everyone like to have fun. Keep all your interactions light hearted and enjoyable for both sides. Remember: If theyâre using your product, youâre on the same team. Youâre just two people working together to solve a problem. Use your teamwork skills to make the interaction positive and enjoyable.
Need help with this? Get in touch and I can help out you and/or your team.
Liked this post? Please give me an emoji reaction, or leave a comment to show your appreciation. It really keeps any person creating content on the internet going when you express your gratitude â we do this for you.