Small Modules: Tales from a Serial Module Author
Sindre Sorhus is the author of over 600 modules on npm. He recently wrote a long GitHub comment about why we should use small modules, and I asked for permission to reproduce the text on DailyJS. Read on to learn about why small modules make programming easier, and why it's not really about lines of code.
People get way too easily caught up in the LOC (Lines Of Code) argument. LOC is pretty much irrelevant. It doesn't matter if the module is one line or hundreds. It's all about containing complexity. Think of node modules as lego blocks. You don't necessarily care about the details of how it's made. All you need to know is how to use the lego blocks to build your lego castle.
By making small focused modules you can easily build large complex systems without having to know every single detail of how everything works. Our short term memory is finite. Other people can reuse these modules and when a module is improved or a bug is fixed, every consumer benefits.
Imagine if PC manufacturers all made their own CPUs. Most would do it badly. The computer would be more expensive and we would have slower innovation. Instead most use Intel, ARM, etc.
Small modules are made possible by how npm works. The beauty of being able to use nested dependencies means I don't have to care what dependencies a dependency I use have. That's powerful.
Some years ago -- before Node.js and npm -- I had a large database of code snippets. I used to copy-paste these snippets into projects when I needed them. They were small utilities that sometimes came in handy. npm is now my snippet database. Why copy-paste when you can
require? Packaging and naming a module also has the benefit of having a clear intent. Furthermore, fixing a bug in a snippet means updating one module instead of manually fixing all the instances where the snippet is used.
As an example, I have a module called negative-zero. Its job is to tell me if a number is
-0. Normally you wouldn't have to care about this, but I've found it useful. How do you figure out if a number is
-0? Well, that's easy:
x === 0 && 1 / x === -Infinity. Or is it? Do you really want to have to know how and why this works? I would rather require
negative-zero and focus on other things.
Another example. Chalk is one of the most popular modules on npm. What you might not realize is that it's actually a collection of modules. It depends on a module for detecting if the terminal supports color, for getting the ansi escape codes, etc. All of this could have been just embedded in the main module, and it probably is in many cases. But that would mean anyone else wanting to create an alternative terminal string styling module would have to reinvent the wheel. By having supporting modules, people can easily benefit from Chalk and maybe even help improve Chalk by improving one of the dependencies.
Yet another example. I have a module called user-home which gets the user's home directory. You might think it would be simpler to just do
process.platform === 'win32' ? process.env.USERPROFILE : process.env.HOME. And most people just that. But first, why force everyone to know how to get the home directory? Why not use a "lego block"? What you also might not realize is that this check is incomplete. On Windows you should also check
process.env.HOMEDRIVE + process.env.HOMEPATH and you might also want to do additional checks. Lego blocks.
Do you make your own shoes? No, you buy them in a store. Most don't care how the shoe is made. Just how good it fits.
I want programming to be easier. Making it easier to build durable systems. And the way forward in my point of view is definitely not reinventing everything and everyone making the same stupid mistakes over and over.
Written by Sindre Sorhus, reproduced with permission and republished with edits by the DailyJS authors.