public
Created

how I write modules

  • Download Gist
gistfile1.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
My thoughts on writing tiny reusable modules that each do just one
thing. These notes were adapted from an email I recently sent.
 
***
 
If some component is reusable enough to be a module then the
maintenance gains are really worth the overhead of making a new
project with separate tests and docs. Splitting out a reusable
component might take 5 or 10 minutes to set up all the package
overhead but it's much easier to test and document a piece that is
completely separate from a larger project. When something is easy, you
do it more often.
 
I've observed the biggest gains for splitting something out into a
separate module when I'm completely stuck mucking around in a larger
application. When I isolate the problem down to the scope of a small
module, it's much easier to see how that small piece fits in with the
greater application objective.
 
Another technique is to pick tools and approaches that don't involve a
lot of boilerplate in the first place. My usual flow for writing a new
module is:
 
1. hack up some tiny (<10 line) example file that does just enough to
start experimenting with the api
 
2. start fleshing out an index.js file required by the example file
 
3. make incremental changes to the index file to get the example
further along, updating the example as necessary to reflect changes
 
4. once the example pretty much works, copy it into test/
 
5. `npm install tap` or `npm install tape` for modules I want to test
in the browser. I like simple, imperative tests that I can adapt from
simple examples.
 
6. add some assertions around the example code
 
7. `pkginit` (https://github.com/substack/pkginit) to generate a
package.json (or you could just use `npm init`)
 
8. copy the example file into a readme.markdown since I really like
when packages have code in their readmes when I'm looking for modules
to use
 
9. add a blurb at the top of the readme.markdown, document the methods
(there are only a few to document usually), add a license and install
instructions
 
10. create a github repo
 
11. add travis and/or testling-ci github hooks as appropriate
 
12. `git push` and `npm publish`
 
With practice, I run through all these steps very quickly now. Not all
of these are strictly necessary and sometimes I'll skip a step but
this is mostly the procedure I use for new modules.
 
As much as possible, I try to build large-scale projects using lots of
tiny modules so I just repeat this process whenever I need some
reusable component that doesn't yet exist in quite the form I need it
to exist. As more modules are published to npm I expect I won't need
to write so many modules but there will always be room for new stuff.
 
When applications are done well, they are just the really
application-specific, brackish residue that can't be so easily
abstracted away. All the nice, reusable components sublimate away onto
github and npm where everybody can collaborate to advance the commons.

That's nearly the same way, I do it. The hardest/longest step in this approach is to find a good name for the new module.

Here are some naming tricks:

  • grep through /usr/share/dict/words with fragments of relevant words
  • apt-get install wordnet, then you can do wordnet $TERM -syns{n,v,a,r} to get lists of synonyms

Cool, thanks a lot!

Awesome, I'm going to start doing this.

I wrote kind of a counter argument to this gist while explaining the design decisions behind moutjs: http://blog.millermedeiros.com/mout-and-modularity/

Not only do I completely agree with this advice, but it is also worth noting that besides the npm and index.js specifics, the advice herein is applicable to pretty much anything with a sane packaging system. In other words, once you grok this workflow, it can be re-used everywhere.

At this stage in the game, it is my opinion that any language/environment that is not amenable to this (or a similar) workflow is likely broken. I don't think a better workflow exists at this time. If there is, please fill me in. Always looking to improve.

Nice read - love the last paragraph on "advancing the commons" :-)

thank you for the step-by-step. straightforward how-to's are difficult to find while i'm learning to program :)

i'm looking thru some of your github repos (particularly their early commits), and i recognize some of this list in practice. do you have a single repo that you would recommend as a "shining example" that i can refer to while learning?

I love this!

Does searching for existing modules that accomplish what you want to do fit into your workflow (or your vision of a generalized application or module development workflow)?

In other words, do you wind up using primarily your own modules? If so is it because their purposes are specific to your style of building things, or because they're specific to the things you're building and are fulfilling new purposes? And if not, do you have any tricks for balancing the tradeoffs of getting to know other peoples' modules vs building/remembering your own?

Thanks!

I absolutely look for existing modules first using a bunch of npm searches. These steps only kick in once I've found the existing modules to be inadequate or non-existent. I certainly use my own modules a lot but mostly just because I know their APIs already and am familiar with what they do. I think poking around the github repos of people who have written modules that you've like previously is a good way to find quality modules. I also ask on irc sometimes if npm search isn't turning up anything worthwhile.

Hey James, nice post
Re: Naming modules, on OS X, brew install wordnet, then you can do wn $TERM -syns{n,v,a,r} to get lists of synonyms

Finally, illustrate the readme!

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.