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
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.
Comments
Post a Comment