1. 23

  2. 10

    I’m really confused by all this hate against small packages. Everyone is talking about microservices, which are effectively a service per function, so why is a package per function so crazy? I would like smaller packages with a more singular responsibility. Maybe 1 package per function isn’t worth it, but I would hardly call wanting that, and doing it where possible, a sign nobody can program.

    1. 14

      Because dependencies are really hard.

      Left padding a string is a problem that can be solved pretty trivially; pulling a dependency for it means you’re spending more bytes doing TLS to download the package then you are just writing the code to pad the string.

      Beyond the overhead, when you rely on an outside dependency:

      • you have to worry about pulling it - is the network alive to accommodate the download?
      • you have to worry about the author making breaking changes, perhaps even maliciously
      • you have to worry about the author deciding to pull it, leaving you in the lurch

      Those worries can be mitigated (vendoring), and sometimes the benefits of getting new features outweigh the risks of changes, but for a dependency that is effectively “finished” I don’t see the benefits.

      That said, I think there’s a really interesting problem that can be solved here: can we find a way to mark certain dependencies as “finalized”? Joe Armstrong (Erlang) had some really interesting ideas around a global function store. In that case we could push left-pad/2 up to the function store and mark it as “frozen” - then a programmer can just call left-pad/2 in their code, have it pulled out of the global function store, and auto-vendored in their code.

      Maybe we can have our cake and eat it too…

      1. 5

        For more in the “interesting ideas” department, Unison is an environment/language which, among other things, uniquely identifies functions by hashes of their code in hopes of supporting distribution without too much trust.

        1. 4

          The approach I’d use to freeze things is to structurally hash their implementations (it would be much better to instead hash their type signatures, in languages where that provides sufficient guarantee of semantics, but it accomplishes the same thing), then import them by referencing that hash. Then there’s no name that can be remapped.

          1. [Comment removed by author]

            1. 3

              Hah, that eerily looks like dependent types.

              1. 2

                Yes, thank you. That explains my idle desire better than I did. Your second paragraph is exactly what I had in mind.

          2. 8

            Depends on the function, I guess. If it takes you so much time to write isArray that you choose to look for and depend on a package for that, well…

            1. 12

              You may be aware of this, but home-grown isArray checks often contain subtle bugs due to JS’s globals being different-per-realm. The naive x instanceof Array is wrong when checking arrays from a different realm. Often, JS developers are aware that there are complications, but don’t remember exactly what they are. So rather than reading pages of language documentation, they go with a known-reliable single-function module.

              I tend to prefer relying on a utility collection like LoDash, but when you’re trying to keep client-side bundles small, single function modules make sense.

              Unfortunately, the sorts of complications I mentioned above are pretty common in JavaScript, so these single-function modules are actually useful across a lot of circumstances..

              1. 11

                In this case, I would read the entire line of source code, and copy it into my code. I understand JS is bullshit and this stuff is hard, and I might end up referencing that single line of source code multiple times for other projects, but I don’t need to make it a dependency.

                1. 4

                  Exactly. JS is a weird language with plenty of quarks (and really should have a better stdlib), but adding a whole dependency for something that should be copy/pasted is ridiculous. A function doesn’t deserve it’s own file, and a function definitely doesn’t deserve a whole package with multiple files and metadata.

            2. 7

              I’m really confused by the amount of controversy this is causing especially to people that don’t use Node. Most of the people that have been using npm correctly have just been like well that sucks to the idiots out there but my build isn’t broken. Now I have to turn around and see blog posts about “DAE think javascript programmers are dumb” while sniffing their own farts and auto fetching dependencies from search.maven.org.

              Edit: Sorry that’s an unfair characterization for David Haney, he probably writes his blog post while sniffing his own farts and autofetching with NuGet. ;-)

              1. 6

                I don’t think the point is to say every JS dev is an idiot, because that’s obviously not true (I know plenty of great JS devs who are great at it and have built some awesome projects). However, the fact that people are arguing for one line libraries is over the top. Util libraries are worth using (and JS definitely needs them), but fragmenting a util library into thousands of inter-dependent pieces is a poor idea. It’s not helping to hide complexity, it’s just shifting the problem to dependency management which is almost certainly worse.

                1. 3

                  Totally agreeable, it’s just that magically because at one point someone who is arguably a bad dev did this, everyone in the JS space is bad because all of the top tier projects were affected. This piece is like 90% veiled circlejerk against JS.

              2. 3

                Microservices cause pain and overhead that is counterbalanced by process improvements that only apply when your organization reaches substantial scale. Micromodules cause pain and overhead (at least they would if you were taking them seriously by investigating their provenance and checking the change log when you update them) that isn’t counterbalanced by much at all.

              3. 5

                No, more code reuse is what we should strive for. Having every programmer constantly reimplementing the same boilerplate logic again and again is unsustainable. If you constantly repeat yourself then you’ve deprived yourself of the thing that got us all into programming into the first place: automating away repetitive tasks.

                1. 3

                  Jonathan Blow claims that code reuse is not necessarily good, because we don’t know how to build things on top of each other.

                  1. 2

                    We do if we build software around strong types and algebraic laws. JavaScript is just terribly uncompositional because you have to use tests to verify that things compose as you’d expect.

                  2. 2

                    The point here is that there’s a tradeoff. More code reuse is good, but using dependency management to get it is bad. There’s a line of simplicity below which the benefit of code reuse doesn’t outweigh the cost of the dependency management to achieve it.

                    The most recent tongue-in-cheek example of this I’ve seen is https://github.com/jezen/is-thirteen, which is obviously not an appropriate dependency to pull in. (It appears to have had some feature-creep in the past day, making it slightly less deadpan.)

                  3. 2

                    Cross-post from the left-pad.io post:

                    I can see the same thing happening everywhere from JavaScript, through Ruby and Racket to Haskell. We are slowly moving towards a distributed maintainership of the base library. I consider this to be a good thing, but we currently do not have the tools required to organize such a large system.

                    In the Haskell world the libraries are getting organized according to their meaning and function, rather than their name. Observe for example the contravariant package.

                    We could adopt the proven Linux distribution system:

                    • integrate and ship everything every n months;
                    • maintain at least n*2 months;
                    • automate the dependency discovery.

                    Or we could start bundling things. It’s our choice.

                    1. 1

                      left-pad to become the new #FizzBuzz.

                      I think you should have to send a manually written implementation in order to get access rights to using the dependency.