On Software Engineering as the UX of Code
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:
- the software code
- APIs used by other internal or external teams
- non-code assets such as images or videos
- usage metrics and monitoring data
- all manner of documentation (designs, API descriptions, usage instructions, ...)
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.
Related Engineering Practices
- Modular design
- Minimize the number of places where code must be changed
- Common design patterns
- Testing
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.
Related Engineering Practices
- Clear, simple, explicit code
- Common design patterns
- Common language idioms
- Testing
- Clear documentation
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.
Related Engineering Practices
- Good naming practices
- Simple, obvious usage patterns ("only one way to do it")
- Types and type-checking
- Easy-to-understand, difficult-to-overlook failure and error patterns
- Clear, comprehensive documentation
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.
Related Engineering Practices
- Small, targeted commits
- Clear, simple, explicit code
- Common design patterns
- Common language idioms
- Testing
- Clear documentation, especially in the commit description
- What does this commit do? Why is it necessary? Why should the reviewer believe it works?
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.
Related Engineering Practices
- Monitoring & alerting
- Metrics
- System visibility and debugging tooling
- Documentation, especially a comprehensive runbook describing common problems and their solutions.
- Operational tooling to execute the fixes easily, quickly, and safely
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.
Related Engineering Practices
- Documentation, especially regarding operational procedures
- Release approval and deployment processes
- Careful system design to minimize or isolate regulatory blast radius
Other Users
There are many other types of users-of-code as well.
- The Code Borrower, trying to adapt code for use in a new context.
- The Diverse User, who may have different physical, communication, or other capabilities abilities or perspectives.
- The Finance "User", who's concerned with how much things cost.
- The Code Archaeologist, trying to explain why the code is the way it is.
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?