Design patterns : the essential to know
Design patterns are inevitable for all developers. If you don’t know them, you need to understand that you are already using them without knowing it. There are some indispensable things you need to know so that you don’t get completely lost. It will serve you well for your entire career.
Concept
A design pattern is a standard way to solve a recurring software design problem.
Concretely, the code organization problems you encounter today, armies of developers have had them before you. Over time, they’ve created these kinds of plans or patterns for your code.
By taking a little height, anyone can observe and use these concepts.
And I don’t use the word concept randomly. A design pattern gives you a direction. A way to organize things in your code.
It’s not a stackoverflow copy and paste and hope of the best type of situation.
You need to be strongly inspired by the design pattern’s operating philosophy to implement a solution optimized for your application.
Utility
I read somewhere that a good developer doesn’t need to know design patterns.
Apparently, a developer, a real one, will naturally reinvent them. Via his higher brain, as he creates his perfect code in his divine application.
It’s false and full of ego.
Design patterns are the fruit of many years of work. Many debates and tests on real applications. Many books since 1994. There’s even a drama developer with the anti-patterns and variant for each design pattern.
A lot of people convulsing for a lot of time, trying to find optimized solutions.
Knowing the design patterns allows you to have reliable and tested solution concepts for any kind of software design problem.
Design patterns also have their own very specific language. It’s very impressive when you don’t know anything about it.
A few months after I joined my first job, I attended a meeting for the design of the next system. Soon, they started talking about a Facade to manage the ton of already existing subsystems, an Adapter to connect an external library, and an Observer for notifications.
I didn’t understand anything and wondered if I really belonged in this room full of alien.
I didn’t make a sound in this meeting.
Knowing the design pattern allows you to exchange and speak the same language with the developers around you.
And believe me, that’s more than important if you want to be part of the effort in your team. So, of course, you don’t need to know them all by heart. But having the concepts in mind makes all the difference.
Especially since today, we end up with a rather impressive catalog.
Scope
In the last century, the famous “gang of four” (I’m not making this up) jointly put a book of more than 400 pages on the table. Inside, 23 different design patterns. They solve most of the recurring software design problems.
I don’t recommend this book.
I find it complex and not very intuitive. I strongly recommend Head First Design Pattern instead. Simpler, better explained and cheaper on top of that. We’ll talk about it later.
You can imagine that we won’t go through the list of 23 and explain them one by one in this article. That would be a reading of several hours. The book I just told you about is more suitable for that.
No, but we’re going to make an overview for the essential to know. First of all, you have to know that design patterns are divided into three main categories
Creational Design Patterns
They focus on ways to instantiate and configure objects and classes. No strategy in managing the creation of objects and classes and your app will sooner or later be filled with devilry.
Creation Design patterns optimize reusability and flexibility.
We are going to touch quite a bit on the concepts of encapsulation and concrete class management/dissimulation with abstraction. If you find all this complicated, I will soon do an introductory article on software architecture. It will be clearer then.
Structural Design Patterns
They focus on organizing the relationships between all the components of a system. No strategy in these relationships will result in a slow and/or faulty exchange of information.
Structural design patterns optimize the simplicity and efficiency of communication within a system.
We will mainly make the link between interfaces and abstract the access to functionalities in a system.
Behavioral Design Patterns
They focus on the distribution of responsibilities among the components of a system. No strategy in responsibilities will lead to classes and objects doing anything and everything, for example the famous god object.
Behavioral design patterns optimize the responsibility of the actors in a system.
We are going to define behaviors through abstractions that will separate each of the actors in very specific responsibilities.
Example: Singleton (the unloved one)
As I told you, we’re not going to do the 23. But I think it’s important that I find a concrete example. Even if only to have an idea of what it looks like.
I decided to tell you about the Singleton design pattern.
Why him in particular? I have three reasons.
- It is very easy to understand and implement. The code is short, easily reproducible and practicable. It’s perfect for a smooth introduction.
- It’s one of the most used so knowing it is mandatory.
- It is a much criticized design pattern. It is considered by a lot of people as an anti-pattern.
This will allow me to talk to you about this notion of anti-pattern and the disadvantages of design patterns in a more general way.
Because yes, it is by far the design pattern that shocks developers the most.
Let’s imagine, you have a big app that makes extensive use of a database to run. So far nothing crazy.
But very quickly, this database becomes a shared resource throughout the application. In many different places. A new class is created each time and each instantiation accesses the same data at the same time.
There is a great potential for chaos in this situation.
We would need a way to have a single instance of access to the database. It doesn’t matter for whom and it doesn’t matter from where. Moreover, we would have to protect this instance from being overwritten to be sure to always use the same one.
This is exactly what the Singleton design pattern allows us to do!
// database.js 'use strict' const path = require('path') const config = path.resolve('config.json') const databaseSingleton = (() => { const myDatabase = require('myDatabase') let instance function init () { const client = myDatabase.createClient(config) return client } return { getInstance: () => { if (!instance) { instance = init() } return instance } } })() module.exports = { databaseSingleton } // use example, in a another file const database = require(path.resolve('database')) const firstDatabaseInstance = database.databaseSingleton.getInstance() assert.instanceOf(firstDatabaseInstance, Object) const secondDatabaseInstance = database.databaseSingleton.getInstance() assert.instanceOf(secondDatabaseInstance, Object) assert.deepEqual(firstDatabaseInstance, secondDatabaseInstance)
The central concept of this design pattern to understand is what happens in the getInstance function.
The customer is only supposed to use this function. In this function it is checked whether the database instance already exists. If it does, we return the existing one, otherwise we create it via the internal function init. Finally, we only have to return the instance.
Very simple concept, but very effective!
Now that we have understood the concept we can transpose it to any language. Why not in Python?
class DatabaseSingleton(object): _instance = None def __new__(cls): if cls._instance is None: cls._instance = object.__new__(cls) return cls._instance first_database_instance = DatabaseSingleton() second_database_instance = DatabaseSingleton() assert first_database_instance is second_database_instance
And just like that we impose a single instance for the access to the database in the whole application and protect it!
Come on, I’ll even draw you a picture with Excalidraw so that you can see what’s going on in the flow.
And it’s great, isn’t it?
Why does everybody hate the singletons so much ?
Disadvantages
Before talking specifically about the singleton, you should know that design patterns in general are often criticized.
- The first criticism is that they are often misused.
Developers often throw them all over the place in an over-engineering madness to prove to everyone that they are super strong. If the scenario has the slightest correlation with a design pattern, you can be sure that the developer will try to make it fit.
It creates a lot of complexity to manage things that are simple at the base.
- The second criticism is that they are often used as is.
And now we come back to what I was telling you at the beginning of the article. A design pattern is first of all a concept to understand. Not a piece of code to be copied/pasted and inserted as is without taking into account the needs of your application.
It creates a lot of inefficient solutions because it is not adapted to the product. Lots of unnecessary noise, things that have nothing to do there.
The last criticism is the source of great debate and drama in the developer community. Some design patterns would be vehicles for bad practices.
Anti-pattern
An anti-pattern is a standard solution to a recurring programming problem that would actually be a vehicle for bad practice.
And the singleton is the perfect example.
You can draw a line in the ground, for or against the singleton, you will always find developers to argue about it. There are many reasons for that.
- Not suitable for mutlithreaded
In a multithreaded environment (C++ for example) it must be treated in a special way. Without this extra work, several instances could be created in spite of protection. Making it completely useless and therefore dangerous.
- Violation of SOLID principle
The singleton is responsible for several things at the same time, violating the principle of single responsibility. There is much debate about whether it would also violate the open/closed principle. We’re not going to get into that, but once again know that the article on software architecture is planned and we’re going to talk about all these principles.
- Use of global variables
The application of this design pattern introduces a global state into the application. This is considered very bad, because this global state does not care about the rest of the application.
- More complicated to test
The problem with this single instance system is that the instance is unique. And when you’re in the context of tests and you want a new fresh instance for each test, it’s very annoying.
In short, the Singleton is considered a devilry.
The funny thing is that the singleton is used by almost everyone, almost everywhere. In fact, it’s the first one you’re supposed to learn since it’s the easiest. So most developers stop there.
And stopping here is a huge mistake.
Go further
Despite the debatable example of the Singleton, most design patterns are very useful and above all very used. Developers around you will use them and most importantly they will come and talk to you about them.
But above all, sooner or later, design problems will present themselves to you. They are going to be more and more important and more and more dangerous. Using design patterns is the best way to defend yourself.
There is no other free or paid resource that has worked as well on me as the Head First Design Pattern book. This is my strong recommendation of the day.
The main argument of this book is the very imaginative way of getting concepts into your head. I love to make diagrams to understand things because I’m a bit stupid. The authors have understood how to do that well too.
The perfect way to use diagrams and illustrations before going into code. And all this is done in a progressive way for the younger ones. Which was very pleasant for my level on the subject at the time.
To give you an idea, the design patterns I see most in my everyday projects are : Singleton, Factory and Abstract Factory, Adapter, Decorator, Facade, Iterator, Observer.
If you are new to the subject and/or want a concrete resource in your hands to fully understand the subject once and for all, this is a must read!
Epilogue
I tried to make it as short as possible, but I see that I still threw away 2000 words in a few hours. The subject is so rich that even the indispensable is consequent. If the subject remains obscure for you, I invite you to study it a little, believe me it will always be useful.