Inspired by “Usable Software Design” by Alexandru Bolboaca
Navigating and learning to use code other people have written (or code we wrote a long time ago…) is part of a software developer’s everyday job. Understanding unfamiliar code is a skill that can be improved and strengthened, but so is creating easy to understand codebases. Investing more time into usable software design saves us from pointing fingers at each other which is never productive, doesn’t fix the design and frankly, isn’t very nice.
What if we saw the raw code base as a product itself that can be improved based on feedback received from its users i.e. the developers that work on it? We can draw some inspiration from UX usability testing for that.
What is Usable Software Design?
We want to dismiss the idea that code “is what it is” and that a developer should just be able to deal with it. We aim to incrementally change a codebase to empower developers to be more productive throughout the lifetime of that product. A usable codebase is characterised through 5 qualities:
- Learnability: How easily can you carry out simple tasks from the get-go?
- Efficiency: How quickly can you perform common tasks after learning the design?
- Memorability: How quickly can you remember the design when revisiting it in the future?
- Errors: How ‘breakable’ is the code? How often do you create bugs and how easily do you recover from them?
- Satisfaction: How pleasant is it to use the design?
Motivations for Usable Software Design
Taking the time to consider the usability of our code can solve some common problems:
- New developers taking a long time to become productive within a team
- Complicated codebases
- Disagreement on what is considered ‘good code’
How to Enforce Usable Software Design?
A Change in Mindset: it’s much more likely for the design to be at fault than the developers working on it, but how can we mandate this and move forward?
Traditional Code Reviews
Typically code/peer reviews happen because of pull/merge requests, which is good practice but these will only happen once the developer has understood the code and has committed new work. We are aiming to make it easier for a developer to get to this stage. In the context of striving to make a codebase easier to understand by all developers involved, this type of code review has some pitfalls:
- The code owner dictates code style/design
- Creates knowledge silos between author and reviewer
UX Inspired Code Reviews
This type of code review does not intend to replace traditional code reviews, but to compliment it. It draws inspiration from UX user observations and mob/pair programming.
Due to these code reviews’ collaborative nature, they boost team discussions around the code which can help strengthen the team’s knowledge of software engineering vocabulary. This is also a good opportunity for senior developers to pass down knowledge to junior developers to ultimately strengthen good software craftsmanship across the entire team.
Group Code Reviews
One person ‘drives’ and the rest of the team ‘observe’. The driver ‘thinks out loud’ and aims to answer three questions:
- What does this code do?
- How would I use it?
- How does it do it?
The observers take note of things the driver struggles with and try to diagnose design faults.
For example, take the following code:
- What does this class do?
Carries out add, subtract and multiply operations on two numbers.
- How would I use this class?
Create an instance of the
Calculatorclass with two numbers and the decimal point to round the result to then call one of the
- How does this class do what it does?
The class functions will read the properties for numbers to do the operations on, round and return the result.
During the review, the driver was confused about:
The name of the argument is not descriptive enough. The driver was unsure where this was a boolean that would determine whether the result is to be rounded or if it defines the decimal point to which the result is rounded to
And the observers made the following observations:
- The class can only deal with 2 numbers at a time.
The numbers could be passed in as a list so the operation can be applied iteratively.
- The class can only deal with the 2 numbers it was initialised with.
The numbers could be passed directly to the
multiply()functions, so we don’t have to initialise
Calculatoragain for each set of numbers.
- The confusion about the
roundargument can be solved by either naming the argument more descriptively, like
round_to_decimal_pointor by using Python’s inbuilt type hints, to show that an int is expected.
Task-driven Usability Testing
One person ‘drives’ and the original designer of the code ‘observes’
Prior to the review, the observer:
- Defines the scope and goal for the review e.g. what files/classes to be reviewed, how much company-specific or background knowledge is required to understand the code?
- Defines a set of tasks to be carried out by the driver
The driver will then attempt to carry out the tasks and gives feedback
For example, consider a web application intended to retrieve and display information about wind farms; things such as metadata about turbines installed, the layout the wind farm is based on, etc.
The observer has defined the goal of the test as:
- To check how easily a new developer can understand how the code is laid out.
- Write code to create a new wind farm
- Write code to retrieve turbine specifications given a wind farm
- Explain where the data displayed on the deployed version is retrieved from
- Explain the authentication flow to access and retrieve the displayed data
The driver is given 45 minutes to complete the tasks.
When time is up the driver gave the following feedback:
- Classes representing wind farms and turbines are held in the same file, making it difficult to locate either from top-level/ through the file explorer.
- Difficult to figure out how to install the project’s dependencies due to an under-maintained README file.
- Lack of a single config file meant that the developer had to search through the code to find what REST API the code was making calls to.
Usable software design is something all software teams should strive for. Designing a codebase with its developers in mind will boost productivity and team morale and ensure a codebase remains maintainable as it grows. Mandating this through UX inspired code reviews help improve software engineering vocabulary and good software craftsmanship across the entire team.