Recipes for Success: Coding with Design Patterns

27 Apr 2023

Following a Recipe

Picture a master chef preparing a delectable dish. They start with a recipe as a guide, but along the way make adjustments based on their taste, experience, and intuition, ultimately creating something unique, delicious, and masterful. In the world of software development, design patterns serve a similar purpose. Like a tried-and-true recipe, design patterns provide a proven framework for building software applications, allowing developers to customize and adapt them to suit individual needs and preferences. In addition, using design patterns leads to improved code quality, maintainability, and scalability—essential ingredients for success in software development.

The Cookbook of Four

Design patterns are reusable solutions to common programming problems that have emerged over time. They have their roots in architecture, being formally introduced to the software development community in the 1990s by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, collectively known as the “Gang of Four” in their book “Design Patterns: Elements of Reusable Object-Oriented Software.” In their seminal work, they documented 23 patterns that play a vital role in the toolbox of a professional software developer to this day, offering guidelines for improving code organization, clarity, and efficiency. Some of these include the Singleton, Factory, and Observer patterns, each serving a distinct purpose to address specific programming challenges.

As was alluded to previously, there are many design patterns. The Elements book by The Four was the first of many such books to have emerged, but let’s contrast only a couple:

The Observer

The Observer pattern, for instance, is where a single object (the subject) maintains a list of its dependents (observers). This pattern is helpful in cases where multiple objects need to be informed of changes in another object’s state. For example, a multi-process application managing several end-points might use the Observer pattern to notify all end-points that a particular global state variable has changed. This one-to-many relationship is well suited for the loose coupling between the subject and its observers, making modifying or extending the system easier. The drawback to this is that sharing an observer’s state change can trigger a cascade of updates in the dependent subjects.

The Command

On the other hand, the Command pattern encapsulates a request as an object, decoupling the request’s sender from its receiver. This separation allows for greater flexibility in managing requests, such as executing them in a specific order or delaying their execution. A common use case for the Command pattern is implementing menu items or toolbar buttons in a graphical user interface (GUI). This pattern is particularly adept at managing the creation and undoing of operations, as each command object maintains its own state, and provides methods for operations concerning its use. This type of encapsulation enables the composition of complex commands from simpler ones, which is great for code reuse and modularity, but does come at the cost of a more complex code base, where each request type has an attache of classes, state variables, and methods that accompany it.

Beyond the Kitchen

Design patterns crop up in your code, whether you immediately recognize them or not. I’ve listed the Observer and Command as examples because I’ve recently used these without knowing about them. In a network simulation program that I recently worked on, I used both of them. The Command pattern was used to manage the various states and components associated with the asynchronous scheduling of jobs that did work with network packets. The Observer pattern proved helpful in relaying information to the different independent processes running the simulated network nodes to manage the state of a binary semaphore, which controlled access to printing to the system terminal. Reading about them now and associating them with my code in retrospect makes me think that the solutions I arrived at aren’t all that unique and do crop up often enough to merit writing a book about.

As I gain more experience as a software developer, more of these patterns will emerge, and having a set of recipes in my toolbox will make me all the more effective. I see the utility and sense in studying design patterns to adapt toward an optimal solution to common problems.