I spent a lot of time recently looking into NodeJs and how my PHP experience translates. From performance considerations to traditional PHP esq Interfaces and how to tackle them. Now I’m at the point of how to structure a full-blown application and how traditional design patterns like Service Location, Inversion Of Control, and Factories fit in with the module driven architecture of NodeJs.
It’s interesting to see there are frameworks out there that pay homage to PHP based frameworks, most notably AdonisJs which is like Laravel for NodeJs.
Being an avid user of the Laravel framework which pretty much centres around the IOC container that’s the pattern of being using the most, but Larvel also offers up some other patterns as well like the Factory pattern with its Manager style classes allowing you to access “drivers”.
I don’t claim to be an evangelist of design patterns, this post isn’t about the patterns themselves, it’s an investigation of how to, at its core structure an app in NodeJs.
First I’m investigating how to fetch/reuse an object throughout the app in different locations. But not just a plain un-configured object, I’m talking about an object that need “something” passed to them when there used, for example a db connection.
In Laravel its well documented, you create your Service Provider, register the service in the container with its required attributes and add the Provider to the boot process. Then when you want it you simply fetch it from the container anywhere you want (by reflection, facades or directly from the app instance). The IOC container will make an instance with what it needs and give it back to you.
It interesting for me that an IOC container and a service locator are pretty similar and cross over a lot. For me I see an IOC container as a circular service locator.
With NodeJs following the module pattern you don’t really need to build a service locator as that’s pretty much what the
require function does for you. So how should we require the db module?
In this way you know the export will need to be instantiated, so you require the aspects in needs and instantiate it. If you need this service in multiple locations you doing a lot of duplication and duplication is the easiest way to run into problems. Whats interesting here as well is that requiring modules causes it to be cached, but when you only export the class, not the actual object to be used whenever you use it this way you will be using an instance unaware of the rest of the app and previous usage.
In this way you are creating a module which returns a fully created instance of another module, this implies requiring the facade type module gives you a ready to use instance. This object becomes cached and as such the same instance is used across your app whenever its required.
This method is pretty similar to the facade example above, except you have created a single point of truth which abstracts the
require functionality giving you the get/register interface for fetching invocated object.
Turning the above example into an IOC is also pretty simple, just pass the factory instance to the register callbacks and you get any easy way to fetch other services from the factory within a factory definition.
I deliberately haven’t looked at any of the existing NodeJs frameworks like sails or meteor so far. I wanted to look at how coming from PHP I would tackle this. Before eventually looking at methods others have to come use successfully and see how they differ later on. I’m sure with the years of development they have had, they have something similar which is more refined, or maybe even something totally different I’ve overlooked.