July 28th 2016 by Fernando Zamora
July 28th 2016 by Fernando Zamora
If you’ve been writing code for more than a year, you might have heard of design patterns. I’m always surprised while interviewing veteran developers that have not heard about design patterns. I always make design patterns a topic during interviews because I believe they are a concept that every developer with more than a year experience should at least be aware about.
So when the interviewees response is “I may have heard of them, can you tell me more…”, I become quite surprised. In truth I’m no longer surprised as much anymore because I’ve come to realize that the developer universe is vast and many developers work in these little vacuums with very particular tools to get their job done without ever tracking the on goings of the bigger developer community. Is that acceptable for a developer, is it not? It depends.
It depends if the developer wants to be more marketable or not. It depends if the developer wants to do better at interviews when the time comes for a new job hunt.
The idea that design patterns are necessary is debatable. Some argue that the only reason we need design patterns is due something lacking in the given programming language. Others live by and love them. In my 15 years of experience I can say that the knowledge of design patterns is important for a few reasons.
1. At some point you may run into a pattern and it will be many times easier to understand the code.
2. At some point you may run into one of the problems that it’s best solved by a pattern.
3. Patterns provide you with language to discuss problems and their solutions with your colleagues.
4. Patterns help you study better ways of leveraging object oriented concepts.
5. If you write business applications you will run into this question during an interview.
I’ve studied patterns, off and on, for several years and I’ve implemented a few of them in areas where they were best suited. In other cases I’ve witnessed their implementation in frameworks such as Spring and Node. Having the understanding of designed patterns helped me get a better understanding of how those frameworks work behind the scenes.
Overall I have a decent understanding of most of the GoF patterns. Not the greatest but decent. In many cases I would have to research the details to implement them but it wouldn’t take me very long.
Recently we’ve decided to make design patterns the topic of our next lunch and learn series here at MAT.
In my effort to lead this series I was quickly reminded how fragmented the resources for learning design patterns are. What I mean by that is that I haven’t found one single place that provides a good way to understand everything about design patterns or at least cover enough breadth to identify the knowns and unknowns.
Some resources provide good examples of their implementation but lack in the explanation of the forces that induce that pattern. In other words they don’t tell you a good way to identify the problem that leads you to use a particular pattern. Other resources provide that but don’t provide a good real world relatable example or in many cases more than one example. Other resources don’t clearly define the difference between one pattern versus another pattern, for example adapter vs. proxy or adapter versus bridge.
So… here is my guide to help you in your design pattern learning journey.
Get a good grasp on Unified Modeling Language
Patterns are most commonly described with UML so if you don’t know it you should get a good understanding before you begin studying design patterns.
A good source for UML primer is UML Distilled by Martin Fowler.
If you’re like me and turn heavily for online resources, a good resource can be found at http://www.tutorialspoint.com/uml/uml_building_blocks.htm.
Understanding the History Behind Design Patterns
Design patterns all started with the book Design Patterns: Elements of Reusable Object-Oriented Code by Erich Gamma, Richard Helm, Ralph Johnson and John Vissides a.ka. “The Gang of Four”. A good summary can be found on Wikipedia at https://en.wikipedia.org/wiki/Design_Patterns.
The book itself is a classic and if you like to collect books have at it but it’s not necessary at all since all you need to learn about patterns can be found for free on the web. Also keep in mind that the book uses C++, which is not the most popular language today. Another book that I don’t recommend is the Design Patterns in C#. If you read that book you will likely end up more confused than not.
Understanding the Categories of Design Patterns
The Design Patterns link on Wikipedia also provides a list of the patterns broken down by their respective categories; Creational, Structural, and Behavioral.
As their category implies, each of the GoF patterns fall into one of the three categories.
While the GoF patterns get you started with design patterns, there are many other types of patterns. If you’ve just started learning design patterns, don’t dive into them right away but definitely put them on your list for future development.
- Patterns of Enterprise Application– These patterns are described in a book by this name. Some of the patterns have lost their relevancy over the years but still worth taking a look at.
- Enterprise Integration Patterns – This concept described in a book by that title is composed of patterns that help solve inter-process communication. This book is very handy in understanding and facilitating a solid approach for inter-process communication. If you don’t know what I’m talking about in regards to inter-process communication think of distributed messaging and message queues.
- Domain Driven Design – Not exactly a book about patterns but rather a book that describes building blocks for designing and modeling any given domain application. One could argue that some of the blocks are patterns themselves such as the Repository pattern.
- Architectural Patterns – https://en.wikipedia.org/wiki/Architectural_pattern. Some patterns fall into architectural patterns and affect the entire application. One popular example is the Model View Controller pattern aka MVC. The MVC pattern is repeated many times for all the different subsystems of the application. Whereas most GoF patterns only require Plain Old Objects, architectural patterns can require entire frameworks to provide the heavy lifting.
High Level Understanding is more important than the details
Assuming that you are a decent programmer, can follow concepts and code a solution relatively easy, the high level understanding of the pattern is more important than knowing the intricate details. Chances are that even if you dig deep into understanding patterns, within a few years you will forget the implementation details. However, the more important thing to understand is the intent and purpose of most if not all of the GoF patterns.
The problem with understanding design patterns is a bit of a wicked problem. You have to dig deep and implement a pattern and then come back to re-investigate the forces and the purpose. This approach will give you the understanding. Yes it will take you some time to implement each of the patterns but I highly recommend it for your own learning experience.
Wikipedia does a decent job of demonstrating examples of each pattern.
With this understanding, when you run into a problem that is well suited for a design pattern you will be ready to take that deep dive for implementation.
With that said, here is a list of the GoF patterns and a brief description. This is my list composed out of the top of my head. You should have your own list off the top of your head.
My descriptions may not be totally correct or accurate. This is just how I remember them. Some patterns can take a longer to understand than others. Just keep that in mind as you read this list and also as you learn more about them. Also, I didn’t list them all, just the ones I could remember off the top of my head.
For a full list visit https://en.wikipedia.org/wiki/Software_design_pattern.
Singleton – When I need to access global resource or set of global data. The singleton enables me to do that in a controlled manner. Singleton can get quite complex when it comes to dealing with multi-threading. Many Inversion of Control (IOC) frameworks allow you to mimic the singleton behavior without actually coding the singleton pattern.
Factory Method – When I want to leverage polymorphism by using different classes and depend on an abstraction instead of a concrete object. Factory method handles the logic that determines which object type to create. Factory is essential to other patterns such as Bridge, Proxy, and Adapter.
Abstract Factory – When the application needs families of components. Depending on runtime context or configuration it may need components from one type or another. All the meanwhile, your client code depends on an abstraction of these components. An off the cuff example is a factory that needs to make ford versus Chevy. The factory class would be responsible for each component such as brakes, engine, and transmission. The factory class can be swapped out to create different concrete types. For example one class would be the FordFactory and the other the ChevyFactory.
Façade (pronounced fassad not fackade as many of us have mistakenly pronounced it) – When you have a library that is complex and in some cases provides more functionality than you need. You can create façade to facilitate use and reduce the complexity. It also allows you depend on your façade instead of the library throughout the application. You application only depends on the library from one place, your façade implementation. It’s good to use a façade to insulate your application from third party library pollution in your application.
Memento – When you require an object that must have the capability to reverse to a previous state. Let’s say you have a class with all these different attributes and as state changes you may want to revert to its previous state or one of its previous states.
Command – Whenever you have an application that requires execution of commands in sequence and potentially has undo capability. An example that comes to mind is a drawing application that records each drawing action and can then undo those actions. For example let’s say you did a red brush stroke, then you pasted a small image, then you drew a square, then resized that square. Each of those actions could be a command. With the command pattern you have the capability to execute those commands and undo those commands.
Another example could be a Word editor program that requires undo capability for each operation.
Chain of Responsibility – This pattern handles a list of responsibilities, each using its own class. As it walks down the chain each responsibility can either handle the situation or pass it down to the next responsibility in the chain. This pattern can be extremely useful in things such as loggers that can log according to severity levels each log responsibility determines if the severity level applies.
Validation that has more than 2 rules is another real world example. Each rule is cohesive because it implements only one single aspect of the validation. Some real world examples are the Filters JSP.
Adapter – Adapter pattern allows adaptation of an incompatible component to the client. The adapter pattern is usually a pass through to the real object. It is necessary when the client requires a particular interface and the concrete class that does the real work does not implement that interface. The adapter implements the given interface and adapts itself necessary to that interface. The adapter is what enables the communication between the client and the necessary concreted classes. The adapter implements the necessary interface and references the necessary concrete classes use.
A real world example would be for example two third party libraries. One library called TransactionProcessoer that requires a FtpClient in order to transmit data. The FtpClient interface must have the methods Send and Put. You also have another third party component call SecureFTPClient that performs secure FTP but instead it implements SendFile and PutFile. You want to use secureFTPClient but it does not implement the required FtpClient interface. So this means you have to create an adapter class called IntermediateFptClient that implements that FtpClient interface and uses an instance of SecureFTPClient. The IntermediateFtpClient passes the Send and Put to the internal member instance of SecureFTPClient SendFile and PutFile.
State Pattern – The state pattern implements a state machine. The pattern is useful when you have complex state logic. The state pattern helps reduce this complexity.
The simplest example that comes to mind with a state machine is an alarm system. The alarm can be armed, off, tripped. In each state the state object responds differently to objects. Handling state without the state pattern can get really complex really quick. The state pattern allows you to reduce the associated complexity, although it has some complexity of its own.
Template Method – Sometimes you have an algorithm that can be reused with slight differences in some of its steps. The template method allows you to re-use the algorithm and provide different implementations for one or more steps in the process.
Proxy Pattern – This pattern is necessary when you need to access a particular service but the client is insulated from the service. In many cases this need arises from the actual real service residing on a remote process or computer. In many cases the client may be able to swap between remote use and local use through configuration or runtime decisions. To the client there is no difference between the local service and the proxy. The proxy in many cases hides certain complexity such as initiating connections and translating to different communication protocols. Some examples of proxy are implementations of web services in C# and Java.
Bridge Pattern – This pattern is necessary when the client and the implementation can vary independently. This is a pattern that I need to understand better and would need some real world relatable examples in order to make it sink in.
Decorator – This pattern extends an object’s functionality at runtime. Unlike inheritance, which extends functionality at compile time to the class, this pattern extends functionality at run time to the object. A lower level object can gain additional functionality. It’s sort of like a run time upgrade. A decorator object normally wraps itself around the decoratee and adds additional functionality. Some dynamic languages are suited for easy implementation of decoration where once the decoration is defined any object that is targeted automatically gets the decoration.
Strategy – This pattern is useful to dynamically handle different strategies. This pattern can be combined with the factory method pattern to instantiate the appropriate strategy. A real world example would be sorting strategies. The factory method could evaluate the data set and determine amongst the different sorting strategy classes, quicksort, bubble sort, insertion sort.
Iterator – Does one really need to explain the purpose of this one? It is for the purpose of iterating over something.
Observer – Think of this one as events in C#. Whenever something interesting happens to a observed object. The observer will take action. You can also think of this as the publisher/subscriber pattern.
I obviously could not think of all the patterns off the top of my head and those would likely require me to study them a little more in order to understand them.
Understanding Determination for a Design Pattern
A design pattern by definition is “a general repeatable solution to a commonly occurring problem in software design”. A big problem with using design patterns is in learning how to recognize the problem and then tie it to the best design pattern. Not all problems require design patterns. When the problem does require a design pattern it is essential for the developer to have the ability to recognize the problem.
Many years ago I attended a course in design patterns. One key factor that the instructor pointed out is that each pattern has some forces associated to it. Just like the best bridge type to construct must take into account the forces in effect; for example wind, weight, distance, weather. Deciding which pattern to use requires us to take the forces into account. The forces are associated with the problems you will encounter in real world programming.
For example the forces for the singleton pattern are:
- There must be exactly one instance of a particular class
- That instance must be easily accessible to all potential clients
Sometimes the forces are not crystal clear, so you may need to dig around from several sources before you fully understand the intent and purpose of a given pattern. Wikipedia gives you a decent understanding in the first couple of sentences for each pattern. Other times in the explanation section, the purpose can be derived from the first three or four paragraphs.
Sometimes it’s best to not use a pattern at all. You should always keep in mind that your goal in writing better code should be to make code readable and reduce complexity. If a pattern adds complexity, then it may not be the most appropriate solution.
Understanding that a pattern is not a perfect solution, recipe or a template but rather an approach. Many times the pattern will fit the problem perfectly and many times it won’t. There may come a time when your solution resembles the solution very much but it has significant differences to not qualify as the pattern and that is perfectly OK. Your quest and primary purpose in using design patterns in the first place is to reduce complexity, improve design and maintainability.