Part of keeping our intentions intact is assuring that our program works well, that includes the occasions where our programs are guaranteed to fail.
Imagine you are tasked to make an algorithm for the automation of airplane control systems. You closed the deal with a known airplane company. Your software is now used in 30% of all the modern plane control systems. This is an overly complex system that you worked with for years, but you forgot to specify on your program that under all circumstances, an airplane should never enter into a nosedive.
One night, you were called up by the company for an emergency. There's a report on unexpected nosedives to have been caused by your software. You gathered your team to find out the bug that has been causing system failures. This is a notoriously difficult process for an overly complicated system. After weeks of investigating, someone from your team found out that there appears to be a lack of exception handling on your software.
Cases like these are testaments to how crucial exception handling is in our systems.
Discussion
Exceptions provide a way to respond to unexpected events that our program encounters. There are two frames of reference for handling exceptions. They are the events within our control and those that are simply beyond our control. Learning this is important for designing large-scale software systems.
Events that are within our control should be our responsibility whereas, for the events that go beyond our scope, we should at least provide a clear error message indicating what went wrong. Error messages provide feedback to the user in a manner that is insightful enough so they can know how to fix the problem. This is key to good user experience design which I outlined here:
General principles of design — Don Norman’s principles | by Dave Amiana | UX Collective
Dave Amiana ・ ・
uxdesign.cc
As developers, we ask ourselves: on what conditions should our program throw an exception? This is not an easy task. First of all, can you enumerate all cases for undefined behaviors of your program? In these cases, we follow a big picture perspective. We translate the previous question as to what is are the quintessential roles of my functions? What are they intended for? A good design philosophy should insight clear intentions, as our products should be easy to use and difficult, if not impossible, to misuse.
With this in mind, we can guide how we should think about writing our code.
Let's go back to our story. Assume, for simplicity's sake, that our system contains the following code:
static struct Plane_State{
float x,y,z;
float weight;
float velocity;
float lift, drag, pitching_moment;
float air_pressure;
}state;
...
void control_directions(const bool& is_pilot){
Control_Parts obj();
if(is_pilot){
Pilot_Commands pc;
obj.control(pc);
} else obj.automate(Plane_State state);
}
Suppose that the above code has administrative control over the parts of the plane. This leads us to investigate the obj.automate()
function. Upon digging on our code a little further we found this:
void Control_Parts::automate(){
optimize_route(state);
obj.control(state);
}
Can you spot what went wrong with this function?
We can't guarantee that our system will not nosedive.
Let's improve this function by introducing a try-catch
block wherein we can guarantee that the system terminates as soon as it meets a critical condition wherein obj.optimize()
leads to a nosedive decision.
void Control_Parts::automate(){
try{
optimize_route(state);
if(state == critical_conditions)
throw "critical conditions are met, autopilot will not overtake controls.";
obj.control(state);
} catch(const char* msg){
std::cerr<<msg<<std::endl;
return;
}
}
This block of code saves lives!
Now we can guarantee that in the event where critical_conditions
are met, the control will be passed on to the pilot.
Takeaways
Exceptional code should have:
- proper error handling that guarantees the intentionality of our code
- clear and meaningful error messages are key to good design
Notes:
- Programming languages have provided this feature, so depending on your language, you should check out the technical documentation on how to implement exception handling.
- C++ code is used for illustrative examples as most modern control systems are implemented using C++, and I personally love the language!