It’s often tempting to write some code to do a task and make it generic enough to handle similar but different tasks. A great example that we dealt this this week was a picker dialog that was used generically for people, organizations, and skill sets in a Xojo web app.
It made sense. The dialog is called from multiple places and it does the exact same thing in each place (displays a list and the user can filter on the list). What’s different is what data we pass into it for initialization and what data it loads for display. We wanted the exact same UI in all three cases.
We all want to write as little code as possible. That’s what’s great about being a lazy programmer. Do more with less. That works until it doesn’t and, to be honest, we’ve learned, the hard way, that sometimes the best approach is to make your objects do one thing and one thing only. Why? Because inevitably the client will say, this is great, but we want to filter for ‘x’ on people, and ‘y’ on organizations, and neither of those things are interchangeable UI-wise and neither x nor y make zero sense for skill sets.
The first approach is to put lots of if-then-else blocks into what was once a very generic picker dialog. Now it’s a complex UI that has three distinct code paths. This complicates testing since every time you make a change it now has to be tested in all three areas. What worse is the code becomes complex and if you’re in a hurry (and who isn’t?) it’s easy to change the WRONG bit of code.
Our solution was to write the first dialog, get the UI working properly, and then duplicate the entire object and customize it for its new task. <Gasp> I know, bad OO programming, right? We disagree and that’s coming from the school of hard knocks.
The end result is that we have specific pickers for people, organizations, and skill sets. It’s now simple for a developer to make a change for the picker in question. No longer do they have to think, “gee, which datatype am I fixing this time,” and possibly get it wrong. Keeping it simple reduces accidental coding bugs and it reduces unintended bugs due to code changes.
Testing also becomes easier because if we’ve done something to the employee picker, we don’t have to test organizations or skill sets. Likewise for the other two areas. Simple is good.
The one area that it does become a bit messier is if we have to do general user interface overhaul. Now you potentially have three places to do it. However, since we have WebStyles with web apps this becomes trivial unless you’re rearranging UI elements. Xojo Desktop apps are a little harder since there are no styles but in those cases it’s actually fairly easy to copy/paste UI from one form to another (assuming that’s possible).
Call me cynical, but I would gladly work on UI for an hour to ensure they’re identical to futzing around with code in three separate code branches that are nearly identical. I am a lazy developer after all.
Our experience says that generic, reusable objects, often lead us into trouble, so we tend simply not to do them. But how do you teach that to a new developer and one that’s trying to do their best to use good OO conventions? And when do you reach that breaking point where the generic way makes it harder than its worth? Good questions that I don’t have good answers for.