We need them to be reusable. Even when doing completely custom sites, similar problems and demands arise. In these cases, one can either start from scratch by writing a new solution, or copy code from a past project. It is important to build modules that solve recurring problems and satisfy periodic demands.
We need them to be flexible. One pitfall in creating a reusable module is not preparing for change. In the past, popular jQuery plugins were known to have a massive amounts of options. The more popular the plugin got, the more demands were put on the plugin. In the end, we have a plugin that did way more than we needed it to do, but also not quite what we had in mind in the first place.
We need them to be simple. The more simple the solution, the more flexible and reusable the module will be. This is a similar idea to the "single responsibility principle" in object-oriented programming, as well as the Unix concept of "do one thing and do it well."
How do we make custom and complex stuff then?
Take, for example, a video gallery in a modal window. This could be something that is wanted on multiple sites being built, so why not create a reusable module? First, we check the internet to see if this has already been done. It has. But, when we try to implement their solution, it's not quite right. Our client wants the videos to slide instead of fade. They also want their videos to automatically load from their existing YouTube playlist. And even though our client didn't ask for it, we know that the existing module wasn't built with accessibility in mind. By now we've looked at the code behind this third-party plugin and it's hard to read.
Frustrated, our next step may be to start from scratch. This will be used on all of our sites going forward, so why not? Carefully, we construct the whole reusable module from scratch. It is much smaller and better than the third-party module since we didn't need to create an option for every scenario ever conceived. The video gallery works great.
Even better, the next client wants it for their site. The trouble is that it's not as reusable as we thought it was. This client doesn't like the videos sliding, and they use Vimeo instead of YouTube. Since we wrote the code, it's easy for us to make these changes for the new client. But now we have two incompatible giant modules. When a bug is discovered on our module, we have to fix it on both sites as carefully as a surgeon.
Our original site is getting messy as well. Our clients liked the video gallery so much they want it on another template, but without the modal. To save time, we can just copy out the gallery menu and YouTube API bits for the new template. This does the trick, but leaves us with a similar problem as the new client with the new site. We have very similar code in multiple places that becomes a nightmare to maintain.
To take our example and solve the flaws, let's instead think of our video gallery modal as a collection of smaller modules. A module to handle opening and closing modals. A module to talk to the YouTube API and give us the playlist data we want. A module to transition between videos. If we break up our giant module into smaller modules that can be reused without updating code we gain significant benefits.
Breakdown of small module benefits
By semantic versioning of the modules, we can apply fixes and updates easily across different sites. The version number can tell us if the differences are minor fixes, new features or incompatible breaking changes.
These modules are easily testable. By breaking our module out into its own small project and defining a single purpose, we can add tests to the project to make sure that it still serves its purpose even after enhancements or fixes.
Modules can be shared and depend on other modules. A "complex" module, such as a video gallery modal, can become a simple module because its purpose may be to combine a number of others together.
But how can modules talk to each other without changing code?
The biggest help I've found in creating small, reusable modules is to implement an event system. Instead of adding a line of code to the modal module that turns off any videos in the video gallery when it closes, the modal module instead emits a "close" event. The video gallery or any other module can listen for these events and act accordingly.
Preferred module system
By using NPM and Browserify, we can tie our modules together and package them for the web. Ampersand.js is developed by &yet and is touted by them as a non-frameworky framework. Their "framework" is built on this concept of small modules that can work together to build big complex web sites.
At The C2 Group
We've also built our own small modules to reuse on sites. Listed below are a few of our modules that we've put on GitHub and published to NPM:
- modal-handler - Open and close modals with accessibility in mind.
- event-handler - Allow any module to accept or emit events.
- query-string-handler - Read and write to the query-string for any changes to a webpage's state.
- form-handler - Validate, read, reset form input values.
- in-scroll-view - Determine when an element is shown in the viewport.