Google Groups

Re: [nodejs] peeves & current best practices?


Tim Caswell Oct 10, 2012 1:07 PM
Posted in group: nodejs
Great writeup!  Most these points are right on.  I take issue with a
couple of them and have a different opinion.  (That's right, this is
my opinion, not saying you're wrong)

> ## Inconsistent sync/async
>
> When functions are sometimes sync and sometimes async lead to hard to
> use apis, subtle bugs and more error handling wrapper code. Always wrap
> callbacks in process.nextTick if they're not behind an async operation.
> Simple.

I used to preach this.  It does make it safer for users of your
library to not have to worry.  But I've also been severely bitten by
the performance and race-condition implications of this.  Waiting till
nextTick to call a callback when you know the answer right away is
extra effort.  I don't think a blanket rule that you should always do
this is right.  I've seen many cases where it's better and simpler to
just call right away.


> ## Fear of dependencies
>
> Some developers exhibit a reluctance to use modules due to the
> 'overheads' of managing dependencies, which is probably a stigma carried
> from other non-nodejs environments. It's not nearly as big of an issue in
> node, so don't hesitate to `npm install` with reckless abandon.

When developing a library please be aware of the cost of depending on
a library.  Especially if that library in turn depends on 10 other
libraries.  Your library will be just one of the many in my app.  I've
seen many cases where pulling in just one library causes my `npm ls`
output to be completely useless.  I'm only using 3 libraries directly,
but I have several screen-fulls of stuff.  And stuff I know I'm not
using like 5 different kinds of option parsers, Ansi color libraries,
logging frameworks, and sometimes even testing frameworks.

Please be aware of the person using your library.  Every dependency
you have will be yet another dependency for every person using your
library.  I shouldn't have to install 5MB of javascript code in
dependencies just to use your simple library.


On Wed, Oct 10, 2012 at 2:17 PM, Mark Hahn <ma...@hahnca.com> wrote:
> OK, I realize now that all your points were about writing good modules.  I
> took your point from the view of the module user, not the author.  I really
> should read more carefully.
>
>
> On Wed, Oct 10, 2012 at 12:14 PM, Tim Oxley <sec...@gmail.com> wrote:
>>
>> > Always wrap callbacks in process.nextTick if they're not behind an async
>> > operation. Simple.
>>
>> Oh, of course… to clarify:
>>
>> If a module is possibly going to execute an async operation, ensure any
>> otherwise synchronous callbacks are inside in process.nextTick. i.e. If it's
>> sync it should always be sync. if it's async, it should always be async.
>>
>>
>> On Thursday, 11 October 2012 05:09:26 UTC+10, Mark Hahn wrote:
>>>
>>> That's pretty awesome.  There's a couple of items I'd like to discuss,
>>> the first one being ...
>>>
>>> > Always wrap callbacks in process.nextTick if they're not behind an
>>> > async operation. Simple.
>>>
>>> This doesn't seem necessary to me and it seems inefficient and dangerous.
>>> I make sure to write in a style that will work whether the callee is sync or
>>> async.  Your scheme will break if the callee ever adds some async.  Writing
>>> in a style that isn't affected by sync/async has these advantages ...
>>>
>>> 1) I don't have to know whether the callee is sync or async.  I'm lazy.
>>>
>>> 2) As I said above, I don't have to worry if it changes.
>>>
>>> 3) It makes it easier to add my own async to stuff.  I can just split the
>>> code with the editor.
>>>
>>> 4) Also as I said above it is efficient.
>>>
>>>
>>> On Wed, Oct 10, 2012 at 11:51 AM, Tim Oxley <sec...@gmail.com> wrote:
>>>>
>>>> So, here's part of a totally subjective, non-comprehensive list of
>>>> frustrations and "best practices" I've been collecting. Some are based on
>>>> personal experience and others are ideals from the node community that I'm
>>>> trying to incorporate.
>>>>
>>>> I'm looking for more tips like this. Please share your knowledge or vent
>>>> your frustrations here.
>>>>
>>>> Stream-like apis
>>>> If your code is emitting data/error events but not inheriting from
>>>> Stream, your module becomes inoperable with other streams, e.g. can't
>>>> pipe(). This severely reduces your module's flexibility.
>>>>
>>>> Inconsistent sync/async
>>>> When functions are sometimes sync and sometimes async lead to hard to
>>>> use apis, subtle bugs and more error handling wrapper code. Always wrap
>>>> callbacks in process.nextTick if they're not behind an async operation.
>>>> Simple.
>>>>
>>>> Prematurely optimising
>>>> e.g. choosing to avoid readable, semantic iteration with
>>>> Array#map/forEach/reduce/filter… instead using for loops 'because they're
>>>> faster'.
>>>> Unless you're writing a database driver or something similar, focus on
>>>> writing maintainable, clean code. Optimising your io and designing to scale
>>>> horizontally rather than tuning individual code paths will reap far more
>>>> benefit and is more inline with node's focus (io bound tasks over cpu bound
>>>> tasks).
>>>>
>>>> OO is an implementation detail
>>>> Rather than exporting constructors as the primary API of a module, just
>>>> give me a factory method please.
>>>>
>>>> Fear of dependencies
>>>> Some developers exhibit a reluctance to use modules due to the
>>>> 'overheads' of managing dependencies, which is probably a stigma carried
>>>> from other non-nodejs environments. It's not nearly as big of an issue in
>>>> node, so don't hesitate to `npm install` with reckless abandon.
>>>>
>>>> Duplication of effort
>>>> Creating new modules instead of improving existing modules dilutes the
>>>> quality of the module ecosystem. Diversity is great, but only when there’s a
>>>> meaningful reason for that diversity to exist. "All the other modules for X
>>>> were broken or buggy", sounds like a good reason to start a new module, but
>>>> perhaps you're throwing baby out with bathwater… the fix may have been a
>>>> simple task but instead of 5 functionally similar, sparingly maintained
>>>> modules, we’ve now got 6, and more surface area for bugs. Nice work.
>>>>
>>>> Another reason new modules are created is because the consumer didn't
>>>> appreciate the module's api; this is a trickier issue as people love
>>>> bikeshedding over this kind of stuff. I've found it's often easiest to just
>>>> wrap modules with an api you prefer rather than starting from scratch or
>>>> arguing with the author.
>>>>
>>>> Learn to npm
>>>> npm contains a great amount of functionality and information that many
>>>> people don't seem to know about. For example you should rarely have need to
>>>> edit your package.json (especially when installing/updating modules) as npm
>>>> has commands to create and update your package.json for you. 'npm help' is
>>>> an excellent source of answers to many questions. There's plenty to learn
>>>> about npm, please share any tricks.
>>>>
>>>> npm scripts vs readme
>>>> If you encapsulate all the knowledge about how to build/boot/test your
>>>> app into your package.json scripts, that's less information you need to put
>>>> into the readme and keeps things consistent. For example, if you setup a
>>>> test script, I only need to know to run `npm test`, rather than hope you've
>>>> included information about how to run your tests. If you change your test
>>>> tool, or change the arguments, I don't even need to know since that
>>>> information is embedded in the package.json.
>>>>
>>>> Tagging releases
>>>> If you don't tag releases, it's a pain to find the commit that
>>>> corresponds to a release. Use npm version to generate tags.
>>>>
>>>> Deep abstractions
>>>> Having many layers and long breadcrumb trails makes understanding and
>>>> debugging your module difficult, raising the barrier to participation (and
>>>> maintainability). Complexity is often presented as 'architecture'.
>>>> Simplicity is key. If your system is becoming complicated, it's probably
>>>> doing too much or you're going about it in the wrong way.
>>>>
>>>> Refrain from building/using all-in-one frameworks
>>>> This is not in keeping with the nodejs aesthetic. Node isn't Rails.
>>>> Having code coupled to a framework creates duplication of work,
>>>> fragmentation and interoperability. This is bad. The trend towards
>>>> modularisation is one of the best things node has got going for it over
>>>> other environments, don't ruin it by creating silos.
>>>>
>>>> MVC
>>>> Usually overkill. If your app is modular enough, you likely won't need
>>>> much/any of it. MVC everywhere makes it more difficult to isolate features
>>>> and break them into decoupled components, as well as encouraging some
>>>> utterly ridiculous solutions (when all you have is a hammer…). Frameworks
>>>> that dictate application architecture should be avoided as architecture
>>>> should be determined by the problem at hand not a framework. Moving away
>>>> from MVC everywhere also gives you the ability to experiment with different
>>>> patterns and evolve your architecture toolset. You'll be surprised at how
>>>> simple some problems are if you don't contort everything to fit into the MVC
>>>> mould.
>>>>
>>>> Supply usage examples in modules
>>>> Most of TJ's and Substack's modules include working examples
>>>> demonstrating various use cases. Showing how to use the module is far, far
>>>> more important than narratives and lengthy api documentation in a readme.
>>>> Code is a concrete explanation and usually uses less words (if not perhaps
>>>> your code needs refactoring).
>>>>
>>>> Supply usage examples upfront in readmes
>>>> Please put a usage example at the top of your readme.
>>>>
>>>> Write tests
>>>> Tests help other developers have confidence they haven't accidentally
>>>> broken anything when contributing to your project. Tests can also serve as
>>>> usage examples in lieu of comprehensive examples/documentation.
>>>>
>>>> What else? Teach me of your ways.
>>>>
>>>> This part of some research for a presentation I'm putting together on a
>>>> similar topic.
>>>>
>>>> --
>>>> Job Board: http://jobs.nodejs.org/
>>>> Posting guidelines:
>>>> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
>>>> You received this message because you are subscribed to the Google
>>>> Groups "nodejs" group.
>>>> To post to this group, send email to nod...@googlegroups.com
>>>> To unsubscribe from this group, send email to
>>>> nodejs+un...@googlegroups.com
>>>> For more options, visit this group at
>>>> http://groups.google.com/group/nodejs?hl=en?hl=en
>>>
>>>
>> --
>> Job Board: http://jobs.nodejs.org/
>> Posting guidelines:
>> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
>> You received this message because you are subscribed to the Google
>> Groups "nodejs" group.
>> To post to this group, send email to nod...@googlegroups.com
>> To unsubscribe from this group, send email to
>> nodejs+un...@googlegroups.com
>> For more options, visit this group at
>> http://groups.google.com/group/nodejs?hl=en?hl=en
>
>
> --
> Job Board: http://jobs.nodejs.org/
> Posting guidelines:
> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
> You received this message because you are subscribed to the Google
> Groups "nodejs" group.
> To post to this group, send email to nod...@googlegroups.com
> To unsubscribe from this group, send email to
> nodejs+un...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/nodejs?hl=en?hl=en