Wed 13 Jun 2007
“I’m trying to write a DOS bat file that runs an Access macro to import a CSV output file from my COBOL program. Any help would be appreciated.” - Anonymous
A short while ago I hired a stained glass artist to create a window for my back door. I told him I wanted something simple but distinctive and let him sketch some designs that he felt would work well in the room. He smiled and had a look of happiness, then told me a story about a recent customer. He said, “This guy had a beautiful master bathroom and wanted me to create a large stained glass window of a hula dancer for it. I tried to suggest some other ideas, but he was very serious about having a hula dancer. So I made the best hula dancer I could for the guy.”
I immediately related to his story. I’ve had to design a lot of hula dancers in my software development career. One thing I’ve always found is that users and managers who aren’t familiar with (or don’t care about) the latest technology will often ask for features or user interfaces that cross the lines of absurdity. Sometimes businesses just can’t give up the archaic interfaces to their data because of cost or fear of change. As a developer it’s your responsibility to suggest alternative solutions that better fit the business and technical model. But users and managers are often a stubborn group of people who really believe that they know what’s best in all cases, and will stick to those beliefs.
There are many articles about developing good software up front. There are many more articles on refactoring bad code to make it better. However, there are very few resources about the common necessity of having to fully implement bad requirements. It goes against the very nature of a good developer, yet is a necessity that most run into at some point. This article discusses some of the strategies that can be used when you are asked to create a hula dancing piece of software.
Write Good Use Cases
When a user demands a particular feature or requirement that goes against common sense, the best first defense is to draw up a good set of use cases that show why you feel the requirement is a bad one. Use cases take a relatively short amount of time to do and you don’t need to touch a single line of source code to make them. Often, when a user can visualize specific scenarios in their mind, they will realize that a particular requirement is a bad one. It’s important to hear the users concerns, but good use cases can shed light on bad requirements with the least amount of effort.
Create a Prototype
If use cases have failed to convince your users that a requirement is flawed, a good second step is to create a prototype. Prototypes should not take more than a day or two and should be functionally thin. The idea is to create a skeleton implementation that just gives the user a sense of how the requirement will behave. It’s often useful to create a second prototype that shows your suggested design in action. This is much more powerful than use cases because it lets the user experience both cases and gives a better sense of real-world usability. Your users might not have even realized that life could be so good with your suggestions until they actually get to try them out first hand.
What if there’s no User Interface?
Use cases and prototypes work well for requirements that involve user interfaces. However, when bad requirements must be implemented that don’t involve a user interface, you must use defensive programming. In these cases, abstraction is the best option for protecting your design in the long run.
For example, let’s assume your company wants to rewrite the server software that processes the orders, and the software must get its data form the legacy terminal system that dumps the orders out to flat files in a directory that must be polled. The thought of such a lousy implementation is enough to make most developers cringe, but interfacing with such legacy systems and legacy data exchange workflows are sadly a common occurrence.
Quarantine the Implementation
quarantine [kwawr-uhn-teen]: Enforced isolation or restriction of free movement imposed to prevent the spread of contagious disease.
If you’ve been committed to implementing functionality that goes against your better judgment, your best strategy is to quarantine the implementation of it. This is where your design skills can really shine and save you from a sure path to maintenance hell. Completely separate your implementation from the rest of the application, anticipating that it has a high probability of change. From our previous example, this means completely isolating the code that monitors and reads the legacy data files from the code that processes them.
The best approach in this case is to design an interface that defines the functionality you will need to load data into your system, regardless of the implementation. Another class may then implement that interface and provide the functionality to monitor for new data files. For example, when the order entry terminals are eventually replaced with a system that stores the entries in a database, the legacy data file implementation can be replaced without affecting the rest of the code base. Data may even be retrieved from a web service someday. This design is shown in the following diagram:
This type of design is typically seen when a set of different objects must implement the same interface so they may be used polymorphically. Although this is a very simple example, the approach is an extremely effective way to protect yourself against certain change. It is good practice, even if you only create one concrete object that implements the common interface so that it’s isolated from the rest of the application.
Keep Development Spirits Up
Having to implement bad requirements can be one of the biggest motivational killers to a team of developers. It’s easy to talk badly about it and wind up doing a poor development job when you just don’t believe in the vision. Don’t let this happen, because it quickly snowballs into a situation that’s bound to fail. Instead, be positive and look at it as a challenge to your design and coding skills. When you feel like you’re applying your creativity, even bad requirements can be made interesting.
All software developers have customers; the end users. Even if they are just the people in the department next door, they are the people who drive our work. Ultimately, it’s our job to deliver what they want, not we believe to be what they want. Sometimes that’s a tough fact to face. The next time your manager says that he needs the company software to hula dance, design the best hula dancing software you can. Just remember to make the grass skirt easily detachable.