004 On Software Engineering as the UX of Code

M. Treaster

2024-02-18

When building a software product, a team of software engineers builds a variety of artifacts. Primary among these, of course, is the actual business product itself, the application used and experienced by end users who derive value from the software.

As the obvious generator of value or revenue for an organization, the business product typically receives great attention from user experience (UX) perspective. And rightly so! Improvements in the product UX can directly impact an organization’s productivity (for internal software) or revenue (for external software). Countless authors have written even-more-numerous treatises on the value of UX design in software applications.

However, the business product is not the only artifact of software development. Other artifacts include:

While the ultimate end users are the users of that final business product, each of these other artifacts will have its own, possibly overlapping set of other users. This essay will concern itself with the software code artifact.

In software engineering, we tout a variety of practices as key facets of software development. Testing. Modular, reusable code. Simplicity. Code readability and consistent style. Standard design patterns and standard existing libraries. Why do we advocate for these practices? Obviously because they make software development easier, faster, and safer!

But “software development” isn’t actually doing anything. It’s a concept or a practice more than anything else, not an actor. “Software development” doesn’t care how difficult it is or how long it takes. Humans care about these things. Specifically, the humans doing the software development work.

Software Engineering is about the experience of a Human with Code. We value Software Engineering because we value those Humans who work with the code. Who are those users? How will they use the code? How can the engineer-author help those users accomplish their goals as efficiently and effectively as possible?

Let’s consider some example users of code:

The Feature Developer

The Feature Developer needs to add a new feature to a system, without breaking any existing behaviors. If the code is tangled and confusing, this work may be difficult or error-prone. If the code is modular and well-organized, it may be easy to drop in the new feature cleanly.

The Code Editor

Closely related to the Feature Developer, the Code Editor needs to alter the implementation of existing code, perhaps to improve refactoring, fix a bug, or increase reusability. If the code is brittle or opaque, they'll probably have a bad time. On the other hand, if they can easily understand the existing code and modify it safely, they'll have a better user experience.

The API User

The API User needs to use a library or module published by another another team, perhaps even another company. Such users will likely be unfamiliar with the internal workings of these dependencies, but they’ll need to learn how they behave and how they should be used in order implement their application. If the API is poorly documented, confusingly implemented, or lacking examples, the API User might have trouble getting traction, or worse, they misuse the API and set themselves up for future errors. But if the API is clearly documented, with methods that are impossible to misuse, then the API User is likely set up for success.

The Code Reviewer

The Code Reviewer’s job is to provide feedback to the author on the quality of a code submission. For the feedback to be most useful, it must be Insightful, Accurate, and Timely. If the Code Reviewer struggles to understand the code, then they may fail in one or more of these three objectives, and both the Reviewer and the author will be inconvenienced. But if the code and the commit description are written in a way that makes the purpose, implementation, and correctness of the code change obvious, the the Code Reviewer can unblock the author quickly and smoothly.

As an aside: The code reviewer must anticipate the needs of all other future users of the code and provide feedback to the author about where the code might provide a less-than-ideal experience for that user.

Oncall Engineer

The Oncall Engineer is responsible for triaging problems when things go wrong. They may be working with software they don't deeply understand, and it may be a time of crisis or panic if the misbehaving system is directly impacting the business. If the Oncall Engineer struggles to understand what's going wrong or how to fix it, they'll have a stressful, miserable time when they get paged. On the other hand, if the nature of problems and the corresponding remedies are clear, then their shift may be more effortless.

The Regulatory Auditor

Many software systems require some sort of regulatory oversight. A government auditor may demand to be shown why they should trust that the software does what it's supposed to do. If they have questions that are difficult to answer, or if the investigation leads into ever-deeper rabbit holes, then ... actually they may not be too concerned but the audited company may have a very bad time. If the Auditor's questions be answered easily and clearly, and if the software and documentation is tidily compartmentalized to minimize awkward follow-up questions, then the Auditor may accomplish their goals quickly and smoothly, and give the company the go-ahead to continue their work.

Other Users

There are many other types of users-of-code as well.

Conclusion

What types of users do you have for the code you write? Almost certainly, you'll be one of those users! What can you do today to improve their (your!) user experience with that code, minimizing frustration and maximizing productivity and flow?

When someone touts a software engineering principle, what user is that principle in service to? Who gets a better UX if that principle is followed? (There's one good list of software engineering principles here).

When you make an engineering decision, what code users will be impacted by that decision, and how?