In software development, we often focus on the “happy path”. It’s the ideal route through a system when everything goes as planned. To create robust and user-friendly applications, we need to venture beyond this path and explore the paths of potential errors.
This article discusses a proactive approach to error management that combines intentional error triggering with comprehensive error documentation and guidance, when an error happens.
The “happy path” represents the optimal flow through a system. For example, in a robot control application, the happy path for connecting to a robot might be:
However, users, especially newcomers, sometimes stray from this path. To create a more robust system, we need to prepare for these deviations.
The key to understand where users stray from the path and what then happens is to intentionally trigger and document errors. This process involves:
For our robot connection example, we might intentionally trigger errors by:
Once we’ve triggered and documented these errors, we can create informative error messages and guidance. Let’s look at a real-world example of how this might be implemented:
def connect(self, ip, waiting=True):
# ... (connection attempt code) ...
while not self.is_connected and waiting:
sleep(0.1)
i = i + 1
if i > 50:
print("")
width = len("Make sure your laptop is not using a firewall or other security software that blocks the connection") + 3
print("")
print(" Could not connect to robot, please check the following:")
print(" - Make sure the robot is turned on")
print(" - Make sure the laptop is connected to the same network as the robot")
print(" - Make sure you have the correct ip address of the robot (" + ip + ")")
print(" - Make sure that your laptop is not using a firewall or other security software that blocks the connection")
hostname = socket.gethostname()
IPAddr = socket.gethostbyname(hostname)
print(" - Your Computer Name is: " + hostname)
print(" - Your Computer IP Address is: " + IPAddr)
print(f"\\{'_' * width}/" + self.character)
exit(1)
In this case it’s easy to catch the errors, as all the errors end up as a “Not being able to connect” error. So catching the error and then showing a useful error message with tips on what could have gone wrong can lead to a smoother experience for inexperienced users.
When this code runs and runs into a timeout while trying to connect, it produces an output that looks like this:
Trying to connect to ws://10.0.233.55/live
Connecting ..................................................
Could not connect to robot, please check the following:
- Make sure the robot is turned on
- Make sure the laptop is connected to the same network as the robot
- Make sure you have the correct ip address of the robot (10.0.233.55)
- Make sure that your laptop is not using a firewall or other security software that blocks the connection
- Your Computer Name is: user-laptop
- Your Computer IP Address is: 192.168.1.100
\__________________________________________________________________________________________/
_-_ | /
/_ \ |/
(o)(o)
| | |
| \/ /
\ |
¯--¯
This error output demonstrates several key principles:
If there is a stacktrace, you should still display it, as it might contain more information about the error. In this case with the timeout there is no stacktrace from an exception.
To implement this approach in your own projects:
By venturing beyond the happy path, deliberately exploring error scenarios, and providing informative guidance, we create software that’s not only more robust but also more user-friendly.
In the world of software development, errors are not just problems to be solved—they’re opportunities to improve user experience and system reliability.