I’d like to start speaking about design patterns by quoting Christopher Alexander, founder of modern patterns who influenced many industries around the globe, including our own.
…each pattern represents our current best guess as to what arrangement of the
physicalvirtual environment will work to solve the problem presented.
As you can see, I slightly modified original version of what mister Christopher said and boom, we have a clear explanation of what patterns are. In our case, a pattern would be an arrangement of code which when applied to a specific problem, solves the problem in the most elegant and efficient way.
Another worth quoting definition of patterns comes from a very popular JS patterns book written by Addy Osmani:
If we carefully observe both definitions, we can come to a conclusion that patterns are simply “templates” applicable to specific problems.
With all this being said, how come that design patterns are so misunderstood among developers ?
Be warned, here comes my personal opinion about this matter so don’t take it too much for granted ‘cause you know how they say, opinions are like assholes, everybody has one.
In my opinion, lack of understanding of patterns comes due to two simple things:
- Framework-oriented programming aka step 1,…n-developers (will explain what I mean by this term)
- Bad approach to software architecture e.g. not defining what the problem is and which tools are the right ones for the given problem.
Framework-oriented programming aka step 1,…n-developers
While some people will maybe get filled with hatred while reading this part, this sadly is a fact. With the high interest in tech due rich job eco-system, we see more and more people coming into industry. Tech bootcamps are booming (I’m a mentor at one), tutorials and videos are pretty much everywhere and it has never been easier to pick a specific framework, learn steps in a very generic way, e.g. require this, download this, connect this and you have a full stack application running.
Due to this, people never actually get to a point of learning patterns because they are already given full-featured framework(s) which offer everything you need to build an enterprise ready platform.
That being said, I came with a term 1,…n-developer which relates to people who are successfully using given frameworks but have absolutely no clue how those frameworks operate and which core API’s are they running on.
Bad approach to software architecture
I work for an AI startup focusing on deep learning, creative skills and critical problem solving. Creativity and problem solving skills are the hardest to acquire and sooner then later, will be the main decider when it comes to recruiting and us being relevant on the market. But why am I even talking about this ?
Problem solving skills believe it or not are also patterns, slightly different ones and they focus on one, most probably hardest thing ever, asking the right questions. To bring you close to what I just said, I will quote mister Einstein:
If I had an hour to solve a problem, I would spend 55 minutes looking for the right questions to ask.
I slightly shortened the original version but when aggregated, it means just that.
If we translate all this theory into practice and design patterns, we realize that in order to efficiently use “right tools for the given problem”, we need to define and understand the problem and then focus on solving it.
Design patterns are just like a toolbox in your garage. You have bunch of tools in there but you will not use a hammer to glue your’s wife porcelain cup. Design patterns for solving the “wife problem” aren’t invented yet. :0)
To get yourself to a point of asking the right questions, you need to deeply understand the problem and what you’re trying to solve. You need to identify existing and possible future flows of the system, research and familiarize yourself with similar problems some other individuals ran into and use an existing pattern or if you are lucky, invent your own.
But beware, not every solution is a pattern. Patterns are proven and community accepted solutions for common problems. Not every piece of code is a pattern even though there’s a high chance that your code, regardless of how you wrote it will at least a little bit, fall under some specific category.
For more specific explanation of this, refer to the free JS Patterns book by Addy Osmani.
Types of Patterns
In this article, we will divide patterns into three categories:
- Creational - constructor, composition, module, factory, singleton
- Structural - decorator, facade, flyweight
- Behavioral - command, mediator, observer
Creational Design Patterns
An example of creating instances of our “class” looks like this:
If you take a look at line 6, you will notice a comment: implicitly returns “this”. What this means is that every time we invoke our Constructor with a “new” keyword, Constructor will return “this” and assign it to the instance (variable on the left). Values and methods held on “this” will be those we initially assigned in the Constructor function, in our case, name and printFruit method. To simplify it even more in a human language, whatever we attach on “this” will be part of that specific instance e.g. var apple, var orange. So basically, when using “new” keyword in front of a function, a new object is being created with specified blueprint aka schema in our constructor. Reason I used terms “blueprint and schema” is because Constructor is just a function that creates new objects that have identical properties (blueprint aka schema) but optional values (in our case apple and orange variables both have name and printFruit but the name itself is optional depending on what we passed to the constructor when we created those objects).
Also, you’ve noticed a term “instance or instantiation” showing up several time. If we leave this article for a second and ask Google what instantiation is, we’ll get the following answer:
In programming, instantiation is the creation of a real instance or particular realization of an abstraction or template such as a class of objects or a computer process.
So to summarize what new keyword does:
- Creates a new object with specified blueprint aka schema
- Binds “this” to the newly created instance - (binding in a more human language means relating, associating, pointing, depends on the context)
- Implicitly returns “this” - if English is not your main language, implicitly in this context means that the operation return this was done for us automatically in the language implementation, we don’t need to manually (explicitly) do it
- Links (connects aka adds reference aka pointer) to the Object’s Prototype - This is the last one for a reason and at this point, you are not suppose to understand it. We are going to talk about Prototypes just now so be patient for next few paragraphs and you’ll get it
If we pay attention to the code above, we notice that for each newly created instance, a printFruit method is created. While this is not a big issue today due to amounts of RAM, computation power and all of the sexy hardware, we should still remove this redundancy and make only one method for that all our instances will reuse.
Let’s make some slight modifications and add our printFruit method to the Constructors prototype:
As you can see, our code doesn’t differ too much from the initial one but a new keyword “Prototype” is introduced. Prototype is simply an object to which all instances of a specific Constructor point to (in this case, our two instances apple and orange both point to Fruit.prototype). Prototype can hold both, methods and properties so if we wanted to have a shared-property across our instances, we could simply add it like this:
We can add as many methods and properties as we want to the Constructor’s prototype and they will all be “globally” accessible to their instances. Note that adding properties to a constructor is not recommended. If you want to define a default value for a property of an instance, define it in the constructor function.
Reason for this is simple:
As you can see, the fruits array we created is now shared among members, therefor, each time we mutate the state (e.g. .push(‘watermelon’)), change will reflect to all members.
Prototype Chain (commonly known as inheritance in Object-Oriented Programming)
Prototype Chain is ability of one Constructor to inherit methods and props from another one. To illustrate this, imagine we are building a Vehicle factory project and we want to abstract methods and props that all vehicles share in common.
We’ve created a Vehicle constructor and we assumed that all other vehicle types e.g. Car, Truck etc. are sharing those 3 props. But before we actually “inherit” those props, let’s first instinctively approach this problem assuming we don’t know that inheritance even exists.
Naturally, we would create identical constructor just with different name.
As you can see, I created a new constructor named Car but what I did is I copy/pasted those same props Vehicle constructor has and I broke one of the golden rules in programming, DRY (Don’t repeat yourself). If I needed a Truck type for instance too, I would pretty much do the same and we would duplicate same props every time.
So, this is where inheritence comes to a rescue. Instead of duplicating our props, we do a little trick using .call method.
Call method will invoke Vehicle constructor on every new instance we create off of Car e.g.
To be continued…