I have had many friends that were musicians, some of which are good enough to make a living doing nothing else. Despite the style, personality, and trend differences of each they all share the same message with regards to song writing: sometimes you write ten songs just to find one that is a keeper. The song writer can perform the ten songs leading up to the one keeper all they want however diluting their musical offering with sub-par works is likely to reduce the overall attraction of the artist. Only by playing the best of their offerings can they hope to attract the largest audience and following.
Software is no different.
Software, like music, is a creative process. Any creative process will produce failures at one point or another but will hopefully also produce successes. It is the ability, as an artist, to let go of sub par work in order to continue on to the prize winner that sets the great software designers from the mediocre. Note however that moving on does not mean forgetting. The lessons learned on the “failure” are often going to be invaluable in designing successes in the future and sometimes the failure may even re-manifest itself as a success in a future endeavor.
A great example of this comes from my personal experience. I recently worked on a project that was attempting to greatly simplify a very complex problem. I spent a good deal of time (mainly thinking while in the car, falling asleep, eating, and other quiet times) designing the application, its structure, and its interactions in my head before I started writing a lick of code. From the beginning I had two paths to choose from. One path was very well traveled and it was quite easy to find applications down this path on the internet (however none of them quite met our needs). The other path was not traveled at all, at least not noticeably. After thinking through the two paths I decided that the less traveled one would be able to give us a better advantage in the context of our goal. Off I went.
It was a dead end. It wasn’t until I was 75% down the less traveled path that I realized that it was definitely the wrong solution for our needs. After going back through the design, shifting things around, and playing with different variations I came to the conclusion that the only way to get the idea working would be to go all the way back to the initial fork in the road and choose the other path. Damn. Discouraged, I pushed the application aside.
After giving the problem a weekend to settle in my brain I returned to it with a couple ideas of how to make it work and, more importantly, other possible uses for the code that would turn it into a success. The ideas to rectify the code didn’t pan out so I turned to a reuse scenario and found that my design was a perfect fit for another function. The irony of the situation is that the ability to recognize the failed code as being useful elsewhere stemmed from an earlier failure. Years ago I had designed a solution that worked well but soon failed to be able to keep up with business demands. It was the experience that I gained through this early failure that opened my eyes to a potential reuse for my most recent failure. So even though my original intent for the application failed, the solid underlying design created an opportunity to plug it into another function with virtually no design changes.
Failures happen, especially in the complex world of software design. Just as the musician is able to reuse certain chord progressions, vocal mixtures, or harmonies from a failed song to create a masterpiece, software designers are able to glean useful portions of code or design concepts from a failed design. When it comes to failures, push them aside or reuse them, but always learn from them. Put simply, as Mark Turansky is fond of saying, good simple code is hard to write.