I don't chain everything in JavaScript anymore

(allthingssmitty.com)

30 points | by AllThingsSmitty 2 days ago ago

27 comments

  • another-dave 27 minutes ago

    > Chaining nudges you toward “process everything,” even when that’s not what you meant to do.

    It feels pretty clear that the chains in that example (filter/map) are meant for operating on collections. And that if you're searching for a single item then chaining isn't the way to go?

    Personally, if I knew I wanted only a single item I wouldn't feel more "nudged" towards appending a [0] on the end of a long chain rather than doing a refactor to the find().

    As to:

        data
          .transform()
          .normalize()
          .validate()
          .save();
    
    here the problem isn't that you've done method chaining, it's that you've named your functions with terse names that you're going to forget what they do later on e.g. a generic "normalise" vs a "toLowerCase()" or whatever.

    As apples-to-apples unchained equivalent isn't really any better

        const transformedData = transform(data);
        const normalisedData = normalise(transformedData);
        const validatedData = validate(normlisedData);
        save(validatedData);
    
    Is not more readable or understandable
    • kakacik 10 minutes ago

      One benefit of the more verbose lower example is, that when it fails somewhere you get a clear line where it failed so can focus already deeper. In chain, unless I am mistaken here (maybe mixing java and javascript so sorry if I am off), its just a general error somewhere in that chain.

      Nothing earth-shattering, but who never had to debug something someone saw in production once and never again, then any additional useful info is weighted in gold.

  • jrimbault 27 minutes ago

    Note that for little while now lazy iterators have been available:

    - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

    - Array.prototype.values https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

    This addresses a few criticisms here, and the main criticisms I had.

  • kalaksi 15 minutes ago

    > Yeah, it’s more lines. But each step is just sitting there. No decoding required.

    I actually think the first code block is easier to read. It's a familiar (to me) and simple pattern that is quick to read. I don't get how it would require more "decoding" than the second example which is more disjointed and needs more "parsing" for such a trivial case.

    I agree there are downsides to chaining. With more complex operations it can complicate debugging, and readability can suffer, so chaining is not a good fit there.

  • t0mpr1c3 2 days ago

    The point of chaining is generally to avoid making intermediate objects.

    • recursivedoubts 37 minutes ago

      the intermediate objects are still created, they just aren't given names/saved to a specific memory location somewhere

      do you mean like streaming APIs where intermediate data structures aren't created? Is that what javascript does w/map() etc?

      • azangru 24 minutes ago

        > the intermediate objects are still created

        Yeah; this is what the new iterator methods were intended to solve

        https://x.com/MozDevNet/status/2029527411424219254

        • zamadatix 7 minutes ago

          Basically?

            // This type of usage creates intermediates
            array.map().filter()
            // But these would not?
            array.values().map().filter().toArray()
            array.values().reduce()
        • phpnode 4 minutes ago

          unfortunately iterators have their own set of overheads and it's not clear that these new methods are any faster for most use cases.

  • ramon156 31 minutes ago

    What a high-level boring list of examples. Why not have one complex example that clearly shows your "take". (Quotations, because these "I stopped doing X, and now doing Y" posts are stupid. They're also easier to write now with LLM's.)

    I'm sure there's a case to be made for either, this post just doesn't do it.

  • l5870uoo9y 27 minutes ago

    Kinda feels like a code smell having to optimize your code this way. Normally, data state would be abstracted away in a data store (e.g., Redux), and then specific sub-selections are pulled out using pure functions, e.g., `getActiveUserNames`, `getActiveUsers`, `getTop5ActiveUsers`.

  • takihito 34 minutes ago

    When I see a magnificent series of functions, I feel a strange, indescribable feeling. However, it's difficult to feel the desire to actively engage with them.

  • prismatix 2 days ago

    Not trying to sound snarky, but this is just part of transitioning from a junior/mid to a more senior developer: realizing that code readability matters more than terse-ness.

  • plumbees 2 days ago

    I agree that debugging these pipelines are a nightmare sometimes. It's something that frustrates me sometimes because even though in OOP it won't be terse the action would be clearer. OOP can at times also introduce less cognitive load as well. I wonder if the issue is the mixing of paradigms. Although I don't think everything should follow purity boundaries: functional must always be functional and OOP languages should just be OOP but perhaps the mixture of doing functional programming in a OOP paradigm introduces unintended quirks that are cognitively taxing when bugs occur. (I've written 10 drafts and I'm not sure what I want to say so I'm going to just land it here and see what happens)

    • plumbees 2 days ago

      I guess I'm struggling because I also do like the IDEA of the unix commands being text that is piped around through commands so I do enjoy the concept of the purity of that mechanism.

      • shaftway 2 days ago

        This is the difference between a command (which is discarded after it's executed), and production code (which you probably want to keep around for a little bit).

        But I'm in the same boat. I love the expressiveness of chaining a whole thing into a single call, but I have to break it apart for my own sanity.

  • efilife 2 days ago

    I read two paragraphs of this and was already sure this article is AI generated. Read more, and "This isn’t just about..." there we go

    • me_vinayakakv 33 minutes ago

      Yeah, nowadays I'm finding more and more of such things and not wanting to read the article further. Sometimes I feel we ignore some good pieces because of LLMification!

      When I write, I now use LLMs as an alternative to Grammarly and explicitly instruct it to not to rewrite. Sometimes the choice of words are very intentional and LLMs dont "feel"/understand the emotional reason behind that.

    • mpawelski 29 minutes ago

      Yeah, and the content is not really thought provoking by any means.

      I was surprised to see such obviously low quality slop here on HN.

  • recursivedoubts 39 minutes ago
    • k4rli 30 minutes ago

      Which part in OP article indicated AI? Probably is, but hard to tell exactly.

  • mekoka 2 days ago

    This is what tends to happen to code when your focus starts to shift away from how expediently you can write it and closer to how readable/maintainable it really is.

  • joshstrange 2 days ago

    Agreed, while chaining can look very pretty, it's a pain to re-parse and a pain to modify.

    It's the same reason I don't like this style of function:

        .map(var => var.toUpperCase())
    
    Sure, it's great today but but I want to debug it I need to add `{}` in and/or if I need to add a second operations I need to add the curly braces as well. That's I prefer explicit:

        .map((var) => {
            return var.toUpperCase();
        })
    
    Since it's much easier to drop in a debug line or similar without re-writing surrounding code. It also makes the git diff nicer in the future when you decided to do another operation within the `.map()` call.

    I've asked many people to re-write perfectly functioning code for this same reason. "Yes, I know you can do it all in 1 line but let's create variables for each step so the code is self-documenting".

    • nottorp 2 days ago

      Don't forget your humble ifs. Add the {} even if it's one line and the language makes the block optional. You'll thank yourself in 1 year when you come back to that piece of code.

  • khelavastr 2 days ago

    Name return variables bro.

    This is a solution that people fixed 25 years ago with detailedReturnObjectNames.

    • jfengel a day ago

      Can you elaborate on that? I'm not following. What makes return variables special?

      I'd expect that much of the time, the return variable is closely linked to the name of the function. So closely linked that it risks being redundant.

      • foobarian 39 minutes ago

        Not JS but I like having explicit return var assignments because it's easier to break on and inspect. I don't know why tools don't make this easier.