Design patterns are elegant solutions to repeating problems in software design. Can you develop your software without patterns? Sure you can, but utilizing a design pattern can enhance your code and aid in speeding up the development process. What’s not to like about that? Therefore, using patterns makes your code reusable and extendable. There are 23 base patterns created by four C++ engineers called the gang of four. These are categorized as creational, structural & behavioral patterns; that is, how objects are created, relate to and communicate with one another. Herein we aim to introduce five of the most used design patterns.
Let’s begin with the singleton pattern. The problem when you develop the backend code, you naturally want the database connection to instantiate only once across the whole system. If the database connection instantiates every time that you want to communicate with it, you will end up having an excess number of established connections. As you likely know, the database has a limited number of connections based on which instance type you have employed.
To solve this problem, Singleton might be the answer you’re seeking. The singleton pattern is used to limit the creation of a class to only one instance. This is beneficial when one instance is needed to coordinate actions across the entire system. Therefore, every time you want to communicate with different places in the database, it will point you to the single instance.
For our second pattern we have the factory method. Again let’s present the situation and problem therein while following with the solution. We created an application called Alertify. The app is used to send SMS texts to participants with a sophisticated template. For example, it can be SMS marketing to your customer, or human resources wanting to send a salary alert SMS at the end of the month. Now for the problem, there are a lot of SMS providers that offer different pricing, some are inexpensive and some are not. We researched many SMS providers to find the most cost efficient ones and combined them together. Naturally, the price continually fluctuates, so we cannot realize the perfectly ideal provider. Therefore, if carrier one is inexpensive with provider A, we will use provider A; however, if carrier B is inexpensive with provider B, we would use with provider B. In laymen’s terms, it’s like selecting the most cost efficient way to ship your products whether it be land, sea or air.
To solve this problem, we used the Factory Method pattern. The Factory Method pattern suggests that you replace direct object construction calls, using the new operator, with calls to a special factory method. With the problem above, we had a list of providers that matched with carriers when we wanted to send an SMS; then, we just needed to pass the cheapest provider name through the created Factory method. Moreover, if we want to add another provider, we don’t need to refactor lots of code; instead, we just need to add more providers as needed. Hence, employing this pattern helped in maintaining the most cost efficient SMS price as possible.
Moving to our third should-know design pattern, the Observer. Consider the following case… You’re a flutter developer who develops a chat app. You are having a lot of problems making the UI interactive when someone is online, a number of people are online, someone is typing, etc. In the chat app there are many screens with similar features; for example, in the contact page you find that there is an online status of your friend’s contact. When chatting with your friend, the chat screen also needs to show if your friend is online or offline. Then you find there is another screen that needs to know the status of your friend. Obviously, you don’t want to constantly request the server to show your friend’s status. This can be done by using a polling technique with the server. Assuming you will have a lot of users, you begin to consider the exponential number of requests that you need to ask of the server which naturally can and will decrease your server performance necessitating the setup of a high capacity server that will put a dent in your development budget. You find yourself between a rock and a hard place, but thankfully there is a solution.
The Observer pattern can solve this problem. Let’s put this into simple terms, think about what happens when you follow someone on Facebook. You are essentially asking Facebook to send you, the observer, follow updates of the person, the subject, you are following. The pattern consists of two actors, the observer who is interested in the updates and the subject who generates the updates.
Returning to the chat app case above , the contact screen and chat screen will subscribe to get a presence event. Once there is an event sent from the server, the subject will notify all the observers that subscribe to that event. So you don’t need to ask the server all the time when a user is online or offline on the contact or chat page.
Moving right along, let’s take a look at the Proxy design pattern. Bearing in mind the same chat app situation from before, you choose to use XMPP as the message protocol. So you have the XMPP client library that talks with your XMPP server. From time to time you find a lot of unexpected issues that come from the XMPP client library such as the XMPP connection is not logged in, the XMPP connection is not in a connected state, and so on.
This is where the Proxy pattern comes in to save the day. Proxy is a structural design pattern that allows you to provide a substitute or placeholder for another object. A proxy controls access to the original object, allowing you to perform something either before or after the request gets through to the original object. With the proxy pattern, you can check the login and connected state before passing to the original XMPP client connection to perform any functions. It’s as simple as that!
Building a flow of input where users navigate from one step to another by completing all or most of the inputs first can seem simple. This could probably be done by merely having different forms and validations to check, right? It certainly appears straight forward enough if we have only a couple of steps to check by adding a few if-else or switch-case statements. However, once the number of steps grows, the complexity of checking, validating and adding if-else also grows. If it grows to only 4~5 steps of forms input, things can get out of hand. Adding a new condition to previous steps may get lost in the shuffle, or maybe there are more complicated form validations of other new steps. You can begin to see the problem that lies therein.
At the end of the day, your code will be a tangled mess of intertwined conditions which become vulnerable to bugs; moreover, it makes maintaining for new team members or extended functionality extremely laborious and overly complex. If you know the building problem we’re getting at here then you know the design pattern that presents the best solution; the Builder.
With the Builder pattern, there are multiple components that we can orchestrate for the build process. There is a Client class that acts as the initiator that needs the build, think of it as the page needed for the forms and steps to construct. Then we have the builder’s classes that have inherited the builder base class but can be builders for different parts or steps of the forms that the Client class needed. Finally, there is a Director class that defines the steps, executes and implements them which tells the builders to build. With these methods, we can supply parts for as many builders as we need to build, but in an organized manner where class roles and responsibilities are easily understood.
The benefit of design patterns is that they help us communicate with other developers at a more abstract level. You can use the name of the design pattern to express your idea rather than writing a great deal of code to express said idea. Additionally, it can help you learn and use new frameworks more quickly as they will be more familiar to you. It’s just a matter of memorizing the different syntaxes. The design patterns we’ve introduced are simply some we’ve found to be the most useful though certainly not the only ones available. Any pattern that streamlines your build process is always welcome!
*photos courtesy of https://refactoring.guru/design-patterns
Tag CloudAgile - Agile Delivery - AI - amazonecommerce - Animal Framework - Attracting talent - Autonomous weapons - B2B - blockchain - businessbuilding - Business building - Clean code - Client consulting - cloud platform - Code Refactoring - coding - Company building - Computer Vision - Corporate startup - cryptocurrencies - de-risking business building - Deepfakes - Deep Learning - DeepMind - derisking business building - Design Research - Developer Path - DevOps - Digital Ownership - ecommerce - entrepreneurs - founder equality - founder equity - front end developer - Fullstack Engineer - Growth strategy - Hook model - Incubator - innovation - Manual Testing - Metaverse - methodology - Mobile Engineer - Natural Language Processing - NFT - NLP - online recruitment - playbooks - Podcast - product versions - project management - Prototyping early-stage ideas - Quantum Computing - Recruitments - Remote Work - Robotics - Sales machine - Self-Driving Cars - Serial entrepreneurs - Slash - Software Development - Software Engineering - teamwork - Tech Talks - tech teams - testing playbook - The Phoenix Project - Unit testing - VB Map podcast - Venture Building - Venture building strategies - Venture Capital - venturecapital - virtual retreat - Web3