Every design problem, in a specific application context, tends to have its identity pattern. Such a flaw in a system might compromise a great solution, turning it into a non-flexible, expensive, and difficult-to-maintain solution. Usually, new requirements will break other functionalities.
A design pattern is known for highlighting and working around such design flaws. It also describes how entities within a system should interact and be exposed. We can look at it as blueprints, which you can customize to solve a recurring design problem in your code.
Patterns sometimes might get misunderstood as a piece of code that you can easily copy and paste into your codebase. But those should be known as theoretical concepts for solving a particular problem.
Design patterns can be split into four different categories:
It is always a matter of trade-offs when choosing one design pattern over the other.
Design patterns can be of three different categories:
These categories differ in terms of complexity, level of detail, and scalability when applied to the entire system.
These patterns are technology agnostic, and you can easily apply them to any programming language or framework.
Such design pattern type provides several creational mechanisms, increasing code flexibility, and reusability. It abstracts the instantiation process, separating how objects should be created, composed, and represented from the code that relies on them.
It describes how entities should be assembled into larger structures while keeping them flexible and efficient.
Such design patterns identify common interaction patterns and enhance flexibility in carrying out this communication. Doing so allows those entities to easily talk to each other while maintaining the loose coupling between components.
After introducing the theoretical concepts, let me give you now a real example of the application of design patterns, by telling you about a problem I had to face at work.
Once I had a ticket where the goal was to refactor our data file extractor service. Visually it would reflect on having to upload a file, such as a PDF or an excel. After the upload, we needed to extract all the file data and display it through a pretty UI. We all knew that another new file type was heading our way in a future sprint, reinforcing the need for such refactoring.
Diagram showing the structure before applying any solution.
We’ve noticed throughout the development that a lot of similar code was being created, making the task of new additions more cumbersome and less flexible. A change to the specification, like a constraint change, would now require to be redone equally in two separate components. In terms of readability, if you had seven different types of files to upload, the probability of missing some crucial steps could be high.
Luckily, design patterns describe several problems that other engineers faced during their careers. Most of the reasoning it’s done, leaving you with the task of recognising the issue and applying the corresponding solution.
While investigating several design patterns, the Template Method Pattern seemed to be the solution for the type of challenge we were facing.
It suggests the existence of a skeleton shared through other subclasses. Inside this skeleton, we can define several steps, which behavior might differ based on the context. In those cases, a subclass should override the step and introduce its specifics without changing the overall algorithm structure.
Perfect, that’s what we needed!
Following this approach allow us to:
Technically, by the end it looked like this:
The final structure.
As you can see, there’s a template method that we used as a starting point. Besides this template method, which shouldn’t be changed by subclasses, we have several steps that subclasses can override if needed.
To implement this, we have followed the below blueprint:
There are plenty of solutions for multiple problems that one might have, and each solution has its pros and cons. It is always up to you and your team to decide if the former covers the latter so you can follow such a path.
Identifying the problem and matching it to a given pattern is one of the most challenging things that one engineer will face during their career. It’s all about experience and experience.
I know folks with more than ten years of engineering experience that still struggle to identify some of those. So don’t worry, because time and code experience will help you with it.