Design patterns shouldn’t be rigid structures demanding adherence. Yet many developers treat them exactly that way—cargo-culting implementations rather than understanding the underlying principles.
The “Cargo Cult” of “Design Pattern Evangelism”
Technology can be a fickle industry, whereby today’s “tried and tested” is often tomorrow’s “tired and rested”. An industry where techniques and technologies are often picked upon the basis of social media consensus, as opposed to actual technical merit.
This leads to a peculiar herd mentality, one where there’s often more weight placed upon developer preference than the actual needs of solving a given domain problem or requirement.
For instance; consider the humble Singleton pattern - a simple concept that can be pivotal in certain scenarios. Alas, due to the negative connotations associated with it - it’s often dismissed, if it even gets suggested to begin with! Yet for many use cases it just makes sense.
Similarly, I’ve seen scenarios where the adoption of CQRS has arguably been an acceptable solution, but it’s actually resulted in entirely unmaintainable abominations - all due to attempts at adhering to the strictest definition of it. Yet it needn’t have been that way, and with a few simple modifications - whilst keeping the principles of the pattern in mind - the quality of the end result would’ve been far superior, and the complexity (and thus maintainability) would’ve been reduced heavily.
It doesn’t have to be this way, and it really shouldn’t be.
Design Patterns are about language
The primary advantage that comes with the usage of Design Patterns is the resulting common language that can be used to describe architectural decisions. This actively facilitates the communication of abstract - and often complex - ideas. Consider the following two examples, each discussing a simple desktop application complete with UI, and decide which is more concise:
Example One (using design pattern terminology)
“The architecture relies upon an Observer pattern implementation, whereby the Subject maintains the state of the application, emiting updates upon changes, whilst the UI components act as Observers - rendering based upon those changes.”
Example Two (without design pattern terminology)
“The architecture relies upon a central object which contains (a) the state, and (b) a registry of other objects which need to be updated upon state changes. Upon a state change, the central object will iterate through it’s registry, interacting with each other object. These other objects - which are often UI components - expose a method that the central object can call, allowing the central object to push state changes.”
Both of these descriptions provide enough detail for a developer to either (a) sit down and begin working on a feature, or (b) understand an existing feature and begin a maintenance task. The difference between the two descriptions is the language used, and the conciseness used to express the core idea.
Note how neither description prescribes enough detail for a developer to get bogged down in minor implementation details; it doesn’t dictate any minutia, and still allows developer freedom. That’s the real beauty of basing a solution on an existing design pattern.
The Warning
If you find yourself fighting against the constraints of a given pattern, or ruminating on specific definitions, you’re chasing an incorrect approach. Design Patterns are architectural ideas, and like most ideas, they exist not to dictate; they exist to be challenged, adapted, and improved.