On Libraries, Reusability and Composability

Posted on March 25, 2016 by Richard Goulter
Tags: programming.nodejs

There’s been a lot of brouhaha and schadenfreude regarding the recent failures in the NodeJS/NPM community.

Essentially the problem / schadenfreude focuses on two aspects:

Here’s a prominent post, Haney Codes’ “Have We Forgotten How to Program?”, which criticises NodeJS/NPM for having packages such as “isArray” or “isPositiveInteger”; along with many other examples any non-Node programmer will find absurd, horrifying, and hilarious.
My favourite bit:

if you cannot write a left-pad, is-positive-integer, or isArray function in 5 minutes flat (including the time you spend Googling), then you don’t actually know how to code. Hell, any of these would make a great code screening interview question to determine whether or not a candidate can code.

(Of course, some applicants [and self-described programmers!] fail Fizz-Buzz, so).

The NodeJS/NPM crowd in response point to this comment from sindresorhus (who, apparently, curates the very popular awesome-nodejs list), defending one-line packages. – The defense, essentially, is that these are versioned ‘snippets’, which provide a reusable abstraction.

Composition

A fun thing is. Haskell kids take this idea, and do kindof the opposite thing. Where NodeJS says “here’s a snippet we can use everywhere”, Haskell is more like “here’s a typeclass which is used everywhere”; e.g. semi-group or monoid or any of that.

– From the Category-Theory side of things, computation/programming is much more about composition (than simply naming/abstracting complexity, per se). e.g. FRP as a ‘fundamental’ solution to the problems of event-handling callbacks; FRP is basically composing streams.
(“A monad is a monoid in the category of” blah blah blah – Monads are a way of composing things).

I understand Haskell in particular runs into ‘cabal-hell’, ’cause of poor handling of transitive dependencies (it can’t have two copies of the same-package/same-version/different-dependency-version); and so when code is re-used so often, conflicts arise fairly often. (Moreover, since it’s compiled, it’s the ABIs conflicting, rather than a more forgiving dynamic-language interpretation like in Ruby or Python).

– So I wonder how “use a good type system” allows composition; & how that compares/contrasts to Node’s.
Haskell’s typeclasses allow a benefit which you can’t really get easily in the more mainstream languages.

Purpose of Libraries

Here’s a post from Benjamin Sandofsky, “When to Avoid Libraries”, arguing for prudence as to when to use external libraries; that programs should build their own abstractions unless they shouldn’t. (Ah, the ol’ “it depends” really is the answer to all topics in programming).
In comparison to the above, Sandofsky agrees that functions shouldn’t be packages. Sandofsky argues (interestingly) that frameworks make a good starting point, but that programmers should iterate towards proper abstractions/models for fitting the problem domain they’re trying to solve. Sandofsky concedes that a library should be used if a complicated task needs to be done, and you’re not interested in the details.

Aside from saying “iterate towards a domain”, the other cute insights are “DRY code/libraries are quite difficult to debug”, and “if an abstraction leaks, no one cares which package is at fault in your program”.

Other Thoughts

I can kindof agree with the idea of “reusable snippets of code” being a good thing. Usually the collections of snippets get called “Utils”. It’s common enough on various Java answers to see answers of “Oh, just use Apache Commons for that string encoding task”.
OCaml’s core library is infamously lacking in features.
– But since packaging systems aren’t more granular than ‘packages’/projects, I don’t see that the above ethoses can reconcile.


Newer post Older post