Technology changes fast. With it, new tools and frameworks are continuously becoming available, making it nearly impossible to keep on top of it all. The only defense against this profusion of technology is to have good fundamental software design skills. That starts with being familiar with design patterns. If you can recognize these, you’ll find they’re often transferable among a vast array of technologies.
Let’s start with the basics. Design patterns are specific implementations of one or more of the S.O.L.I.D principles that are used to solve common problems. Inspired by Daugherty’s own John Gobble’s evening class on Pragmatic Middle-Tier Design, the strategy pattern created below at a client site converted what was becoming an increasingly kludgy section of code into a clear and concise set of modules. This makes it more easily maintained and extended over time.
The project entailed a set of web services that would:
The existing system was in place, but the project expanded it to accept different types of agreements, each of which interfaced with different systems under unique conditions.
Figure 1 is an extremely simplified and generalized version of the code snippet that red flagged a need for a refactoring effort.
A few things noted were:
A spreadsheet was built to get an understanding of which agreements were supposed to go where (once again a simplified version).
The “agreement accepted” information would be sent to System 1, 2, and 3. For each system there were different flavors (concrete classes – i.e. System1A, System1B, System1None) involved. First, an abstract class was added and had three properties of an interface type, one for each system. Then, a set of abstract methods were added and that forced any derived classes to assign a concrete instance for each system.
To review at a particular agreement manager class, we would have something like this:
From there, the concrete classes for each of the interface systems was set up. The UML for the whole set is shown here.
After the refactoring effort was completed, the original snippet of code boiled down to the following.
The factory method shown in Figure 3 was implemented using Ninject named bindings. It determines which concrete agreement manager class to return based on the name of the agreement.
The strategy pattern in this example allows us to easily maintain where and when data should be sent for a particular agreement without having to change the overall process. Putting John Gobble’s evening class into practice created a clear path forward for the project.