Software engineers know that one of the keys to achieving development goals is effective complexity management. The single best way of managing complexity is to remove it from the system completely.
As a simple example, in an earlier version of my BRayTracer project (I really need to come up with a better name!), scene objects were edited by double-clicking on them in the tree view, which opened up a dialog window that displayed the properties of the scene object. The user could make changes and then click OK or Cancel.
This data flow introduced complexity by requiring:
- An additional window to manage
- Moving data between the main window and the dialog
- Making a copy of the scene object
- Allowing the user to cancel or undo previous actions
The functionality of being able to cancel changes necessitated most of that complexity.
While this example wasn’t overly complex, I still felt there was a better, simpler way. You can probably see a number of possible solutions:
- Implement a general undo system (more complexity)
- Don’t allow users to cancel changes–they’re committed! (possible, but wise?)
- Eliminate the dialog by having a child window on the main form (does not allow cancelling, but removes the additional dialog)
- Rethink how objects are edited from the ground up (expensive)
I went with option 3. Obviously, there’s a tradeoff here. I sacrificed some functionality for the sake of simplifying the interface and the code. In fact, in usability testing, many users wanted a way to cancel or undo changes. Someday, I’ll have to go back and add a way of doing it. This illustrates the principle that sometimes complexity is unavoidable for certain features (Undo support, for example, is nearly always very complex to implement effectively) and that often what is really going on is shifting the burden of complexity somewhere else.
Minimization of complexity is also tightly coupled to the principle of optimality (ah…but optimality of what?).
The tendency of developers (at least I assume it’s a tendency–I am, of course, generalizing from my own experience and those people I’ve observed) to minimize complexity is something that can carry over to our normal lives. I notice this myself in a number of ways, most of which probably aggravate Leticia to no end 🙂
- When driving, I almost aways get in the “optimum” lane as soon as possible, that is, the lane from which I’ll have to make the fewest changes. Changing lanes adds to complexity. Having to worry about changing lanes when it becomes crucial adds too much complexity. While there are exceptions for painfully slow people, I change lanes only about 6 times on my 35 mile commute (4 roads and 4 highways).
- When I cook, everything is optimized for minimal disruption. All ingredients and equipment are pregathered and then prepared in a way which minimizes work, time, and coordination.
- When I watch movies at home, I try to optimize the experience by first queing up the movie, setting up the environment, volume, and then making popcorn. That way, once the popcorn is done we can begin watching immediately, while it’s hot. I almost can’t watch a movie without popcorn.
Check out my latest book, the essential, in-depth guide to performance for all .NET developers:
Writing High-Performance.NET Code, 2nd Edition by Ben Watson. Available for pre-order: