65 comments

[ 4.4 ms ] story [ 118 ms ] thread
Am I the only one who feels that it's not a terrible thing to use Lodash? It's relatively small gzipped (4kb for core build), a single interface for a developer to learn, and means you don't have to think as much about the target browser. Sure it adds a dependency, but an incremental dependency isn't often an issue.

The .chunk is a good example (a 7 line function in native vs a 1 line function in Lodash).

I imagine some native functions are faster, but often it doesn't matter.

I say this only partially jokingly: maybe there should be a "You don't need javascript," and we should go back to assembly.

The rest it's 7 line versus 1 line is lodash uses itself. A lot of these functions could be rewritten if other functions where there.

I do think it's silly to include 100 functions and use 2. But if we could properly tree shake lodash there should be no problem in using lodash, you would end up around the same as if you did it natively.

But don't we all use a small fraction of library/package and language functionality.

- In C's stdio, I've used a fraction of calls

- In Ruby/Rails + gems, I use a fraction of calls

- In Node/Express, I use a fraction of calls

- In frontend javascript, I use a fraction of the native calls

In frontend dev, I get that this means forcing users to download a library, but for many use cases 4 kb gzipped isn't a big deal (esp if CDNs are involved).

I think it'd be interesting to poll developers on what part of Lodash/Underscore causes them concern:

1. The extra download time/bandwidth

2. The extra costs of packaging (failed builds, extra packaging process)

3. The speed of computation (assuming that some native functions are faster)

4. The concern that libraries should only be used when they are highly utilized (e.g., at least 20% of a library's code should be used before it is appropriate to include it)

> In frontend dev, I get that this means forcing users to download a library, but for many use cases 4 kb gzipped isn't a big deal (esp if CDNs are involved).

How about 0kb?

Whatever happened to shared-resource URLs, where there was a good chance the library was already cached?

Your breaks or has minimal functionality if the CDN is down.

Your site loads slowly if the CDN is under load

Your users are now leaked to the CDN (privacy issue)

Of course, if the resource is cached, it's less of an issue, but it's still an issue. If you don't care about those things, go ahead.

I agree, also. The code in lodash is arguably better than mine, and they are more experienced than I.
and surely extremely battle tested
I introduced this to our team and after a few months I have mixed feelings. Practically, it's a micro-optimization.

Lodash is convenient, consistent, well-documented, readable, and maintainable. Yes, there's some pretty needlessly redundant methods (isNull for example), but it provides a nice API to do it. The trade-off of a few microseconds is worth it.

Omitting lodash from your entire codebase is not going to magically fix all your problems; there are much more important things you can be doing with your time, such as delivering features or eliminating technical debt.

To reduce the amount you're requiring, you can just get a specific method like require('lodash/omit'). If overhead is a concern, that helps mitigate it.

We have set it to warn, not to error; it's good to raise awareness that you're doing something that has a potential performance cost, but for things like omit the recommended native alternative just isn't worth it.

What I do find it useful for is small projects (like a lambda function) where micro-optimizations DO count.

I agree with this. I think using lodash is a 'use boring stuff' decision in javascript. It feels kind of clunky and outdated in some ways, when new native APIs are covering more and more of what it can do year by year, but at the same time it 'just works' in the most obvious way possible.

With native APIs, you're essentially just doing the same things with a slightly different syntax and sure, it feels cleaner. It is cleaner - where those native APIs actually exist. But if you have to support anything but the latest versions of evergreen browsers, now you're worrying about polyfills, build targets, etc etc.

It's not that hard, but it's just one more thing to worry about and one more thing to be surprised by when it fails on a corner case in production. Meanwhile, if you'd just used boring old lodash, it would be working and you could be paying attention to something more important.

I don't understand the continuous backslash against such a useful tool like lodash, we add 4kb and have all the utility functions that we will ever need, what's wrong with that?

I feel that most people repeating this "you don't need lodash" meme are just saying it because they read it somewhere, and think that bashing on lodash makes them sound cool and looking like they know what they are talking about, much like it happened with jQuery.

There is way too much focus on micro-optimizations like handwriting/copy/pasting common utility functions each time to save 3.5kb in a bundle.

It's just one more of those many examples of engineering perfectionism gone counterproductive, which is, unfortunately, an attitude that is pervasive in this profession and that it rarely gets called out.

Out of curiosity is jQuery really that bad ? I am not exactly sure why I would not want to use jQuery and prefer SPAs. What is actually missing in jQuery lodash handlebars combo ?
Managing anything more complicated than only a slight enhanced page quickly becomes a big ball of mud when you use jQuery and handebars (fancy string interpolation) for state management and UI updates.
(comment deleted)
I see. What do you use and why ?
React+Redux. I can focus just on what the structure of the UI should be and not the nitty-gritty of actually updating it (React handles that). State management through Redux so I can consolidate where application state is held, and testing it is straightforward and a feature of the library.
8 years ago I was using jQuery and good self contain JS objects. Each of them had responsibility over specific part of the DOM. The beauty of that is that in that why you can keep thing simple and updates already well optimized by default.

I understand that by default with JS you can write code that in one place touch every part of the page.

But no framework or language protect you from bad code practices and bad abstractions. They may avoid it at a specific abstraction level but unless you are disciplined and you know what you are doing, you are still screwed beyond that.

Component libraries like React did not invent encapsulation, abstractions, separation of concerns, loose coupling and high cohesion, they just enforce them at their level of abstraction but let you paying the "unoptimized" recalculate all by default.

In fact I saw a bunch of code written in React that are big balls of mud communicating together without a good abstraction logic.

Redux, in the React ecosystem, is pretty good at keep the state in one place but pretty bad to hide implementation details to those component that should not be concerned with them... result? Refactoring a reducer can results in refactoring a lot of smart components. And the verbosity of using Redux has always been off the chart.

The best part of React documentation is here:https://reactjs.org/docs/thinking-in-react.html - Especially in steps 3 and 4. Learn that and use it with the framework of choice or just vanillaJS... You do not use that and you will be in trouble with React or any other framework.

All your template-based logic is in one place. Rather than listen to events and then executing actions using a mishmash of selector-fu, you can have a self-contained template that doesn’t care about other parts of your page. It hides a layer of nitty-gritty from the developer.
I think it mostly stems from the meme that "pure JS is best JS" and anyone who relies on "unnecessary" libs is somehow a worse dev than those who implement everything by hand, regardless of if its required or not.

For personal projects, self education, or fun - go ahead and implement the entire lodash lib by hand! But in a business setting a 3.5kb reduction in bundle size and 10 hours spend refactoring the lodash code out of your project is probably a waste of time and money.

I'll agree with the advice that you shouldn't add dependencies until you need them, but saying "you never need lodash" is bad advice IMO. Absolutism is a bad quality to harbor, especially when it's over trivial things.

I know jQuery fell out of favor with the JS community and now is treated like a sign of incompetence but - just as everything in programming holy wars - at the end of the day everything is a tool, and you need to pick the right tool for the job. If the job is "get an MVP up as quickly as possible" and lodash/jQuery/underscore helps you do that, why wouldn't you use it?

Personally one of the biggest red flags for me is when a developer doesn't use libraries and writes everything themselves. That opensource project with many contributors, that has been around for years is probably going to be better than what you can write in couple passes. There are obviously times when you need to do it yourself or the library truly is badly written but those times are rare.

This gets a bit weird in the JS optimization world because it is true that each library and parts of the library you don't use are going to be extra useless bytes the user has to download. With tree shaking removing the parts of the library you don't use I think this becomes less of an issue.

The JS ecosystem has gotten so large that I can't possibly keep track of all the libraries that I could use to save myself trouble. This isn't helped by the fact that few tools & libs in that ecosystem state succinctly the problem they're attempting to solve.
I think the current meme/trend is to drop as many dependencies as possible. Which is probably the overcorrection of the previous trend of using single utility function libraries like "leftpad".

I do agree with this specific instance though, that you should drop lodash.

Historically lodash/underscore was written for a time before a lot of syntax/standard libraries were added. The new javascript features obviously had lodash in hindsight so they are pretty good at making common things syntactically easier to do or just straight up taking the good functions and standardizing it (e.g., spread operators, arrow functions, Object.assign, Array.flat, Array.flatMap, etc, etc)

>I feel that most people repeating this "you don't need lodash" meme are just saying it because they read it somewhere, and think that bashing on lodash makes them sound cool and looking like they know what they are talking about, much like it happened with jQuery.

I feel like this happens for a lot of topics in this industry, positively and negatively. e.g TypeScript has been on the receiving end for both.

I take these "You don't bla" repos with a grain of salt. JavaScript evolves and if there are methods that are now (almost) natively covered by the language why not use them? Also, if you only need a few methods it makes sense to spare the 4kb and simply rely on a native implementation. Such collections then come in handy.
Case in point: "_.compact".

When I see stuff like

    const cleanInput = _.compact(input);
I have no idea what the fuck just happened. I have to open the damn documentation of lodash (or whatever else kind of library the author chose to use) to figure out what's going on.

Now if that was

    const cleanInput = input.filter(elem => !!elem);
I could've gotten on with my day and saved some time. This does not need any documentation or comment.

This might seem like a small issue to you, but damn, I spend a lot of time debugging random projects on GitHub, and the inability of the JavaScript community to write readable code really trips me up every time. Instead of just writing 2-3 lines other people can parse in a second or two, they spend 5 minutes looking up the relevant library function (which doesn't do what they expect half the time) to produce one shitty line of code other people will also spend 5 minutes on trying to decipher it.

> This does not need any documentation or comment.

Sure it does. You've just already read the documentation for filter.

(And frankly, I just had to look up what !! does, despite years of writing JS code.)

> (And frankly, I just had to look up what !! does, despite years of writing JS code.)

It's literally just 2 NOT operators chained together. I won't fault you for never having seen it, but it is curious considering how common it is.

In any case. Looking that up just made you a more knowledgeable JavaScript developer, while looking up some random lodash function won't buy you much at all.

I'm not sure why you'd think learning a little about widely-used JS libraries wouldn't make you "a more knowledgeable JavaScript developer".
Honestly? It probably does. Much less so than learning the actual language built-ins first, but it does. I'm just biased because I consider them more of a pain than anything because of my personal experience with them.

Memorizing multiplication up to 100 will also make you faster at calculating stuff in your head, but I couldn't ever be bothered to do that either.

> I have to open the damn documentation

I don't know if you understand how lucky you are to be able to do this in the first place.

Also, the "compact" method, I don't know if this is the reason it gets its name in lodash etc., exists in the Ruby language and does the same thing.

> exists in the Ruby language and does the same thing.

You just got lodash'd!

Because the ruby method DOESN'T do the same thing. And this is precisely why you have to consult the documentation every single time you see something weird like that.

The difference is that the ruby method doesn't remove stuff like "0" and "false", just "nil".

It has the same fundamental function.

JS just has the concept of "false-ish", which you'll likely already know as a JS developer.

The ruby method removes "nil", not "false". The ruby method has absolutely nothing to do with false whatsoever, while lodash makes explicit reference to it. The ruby method is intended to just remove holes in arrays, not remove values. JavaScript has the concept of holes in arrays, but that's not what the lodash function is about.

They're 2 different functions/methods with 2 different ideas behind them. They're absolutely not each other's equivalent in their respective language.

> It has the same fundamental function.

No, it doesn't.

> JS just has the concept of "false-ish", which you'll likely already know as a JS developer.

Ruby has a concept of false-ish (which is narrower than JS’s), but Ruby’s “compact” isn't about false-ish-ness, Filtering out false-ish values is .select(&:itself), not .compact

Maybe my feelings here are colored by PHP being my primary lang, but I read both functions purpose as "remove the empty values from this array" with a language-level difference on what "empty" is defined as. PHP's "empty" includes both nulls and false-y values.

Whether you want to call it the "same" function or "similar" function, lodash's excellent docs reveal its functionality quite handily if someone's confused by it.

Haha, would you look at that.

Still, I prefer having documentation over the possible scenario where I have a few undocumented functions created by other developers for whatever reason. Maybe multiple functions do the same thing. Not to say this is the only alternative, but it is the more common alternative I've seen years ago, and it's a certain type of hell.

>This does not need any documentation or comment.

I honestly have no more clue what const cleanInput = input.filter(elem => !!elem); means than const cleanInput = _.compact(input); without going to the documentation.

What you meant to say is "This does not need any documentation or comment for myself, because I have already memorized what all the parts of this line of code mean, whereas I have not yet memorized what _.compact means."

The difference is that one thing uses JavaScript fundamentals that (except for the arrow function shorthand) have been part of the language since JavaScript 1.6 and the other is just some random library.
There's nothing to memorize here, or there shouldn't be, because "filter" is a standard array function in JS that I imagine most JS developers have encountered.

Knowing how "filter" works is valuable because now you can use that knowledge in the future on any project that uses JS, unlike "_.compact" which is only applicable in projects that use lodash. You can be relatively confident that you can write "filter(elem => <some function>)" and that other developers will know what "filter" is doing.

The second part is more tricky, but still useful.

The !! operator is just two "!" operators. That's pretty normal too. The first "!" converts an object/number/whatever into the opposite of its boolean value. The second "!" negates the first boolean, thus turning the opposite of the boolean value into the object's original boolean value.

Even if figuring this out on your own is slightly more difficult, it gives you valuable insight into the language (JS is very dynamically-typed and the not operator can cast objects to booleans), which will help you write better/safer/more concise/clearer code in the future.

My job involves overlooking hundreds of internal codebases and I see people doing `import {range} from 'lodash'` every once in a while. One offending line and tada: 70k+ bundle size for no good reason...

I'd say that any argument for/against lodash can go both ways: if one argues that it is a micro-optimization to handwrite `range`, another person could argue that it's also a lazy devexp micro-optimization to use lodash. `range`, for example, can be implemented with a one liner in like 5 mins and tested thoroughly with a couple of asserts.

Maybe one could argue that some of the more compositional stuff is not so trivial to write (e.g. cond and friends), but if one's using those over normal small procedural functions, who's really engaging in engineering perfectionism gone counterproductive?

I think all else being equal (e.x. assuming sufficient browser support or polyfilling), people should prefer using standard / built-in functions, many of which have been added to JavaScript since Underscore was popularized.

However, I don't necessarily agree with this approach of providing snippets for functions which aren't implemented natively. Underscore and Lodash likely have better implementations and much more testing. If you're concerned about bundle size, use tree shaking or individual function imports.

I think one exception to this is if you are writing a library and want to keep dependencies to an absolute minimum.

> people should prefer using standard / built-in functions

I get that, but that's not what this list is: this list is re-implementing lodash / underscore using built-in functions. They're not a 1-for-1 replacement, they're complex implementations which may or may not be correct or efficient. If their solution for replacing _.chunk(...) was some built-in Array.chunk(...) or something, that would be fine. But instead, it's this:

> const chunk = (input, size) => {

> return input.reduce((arr, item, idx) => {

> return idx % size === 0

> ? [...arr, [item]]

> : [...arr.slice(0, -1), [...arr.slice(-1)[0], item]];

> }, []);

> };

That's definitely worse than using lodash.

That's exactly what I said in my second paragraph...
Ah, you did. Sorry about that, you’ve caught me running my mouth off before I finish reading.
You don't need lodash/underscore, you need ramda[0]!

I been using ramda heavily for tasks like merging data from normalized redux stores and it's been really handy, but it's also great for simple tasks as well. I find the resulting utilities really easy to test and since Typescript got much better at higher order type inference, it's become much easier to use ramda in a Typescript project.

EDIT: The version of typescript that improved higher order type inference was 3.4[1]

0: https://ramdajs.com/ 1: https://devblogs.microsoft.com/typescript/announcing-typescr...

We hired a developer for a project and they introduced Ramda into the codebade (in addition to underscore which was already in use).

The resulting code was a mix and match of Ramda and Underscore helpers.

Flipping between Ramda and Underscore documentation the decipher the dozens of helper / utility methods is quite infuriating.

Worse, the Ramda API was previously under heavy development with breaking changes on every upgrade. To stay up to date requires reading through pages and pages of migration guides describing how to migrate off of one deprecated utility method to another.

It definitely had short-term value to the person who wrote the original code with it, but that value quickly faded.

I wouldn't recommend mixing those two libraries as they often do _very_ different things with the same name (eg. `chain` in ramda is `flatMap`) but also because ramda mostly flips the arguments of most functions.

For example, `map` takes the function first and then the collection. That's handy because everything is curried so you can partially apply map:

    const double = R.map(x => x * 2);
and can build up helper functions. Something similar in lodash would be:

    const double = (collection) => _.map(collection, x => x * 2);
which there is nothing wrong with, it's just that the first is more ergonomic with `pipe` (and the potential future feature pipeline operator `|>`).

That said, it took a while to adopt at work. It wasn't until we had a critical mass of people who enjoyed functional programming that it really took off. Before that time, we used a few methods lightly (utils like `pathOr` and `propOr` are so nice when you want to safely traverse an object without `o && o.foo && o.foo.bar`) and were very conscious that it might not be everyone's cup of tea.

The flip side to this argument explains exactly why I use lodash.

> You-Dont-Need-To-Write-And-Maintain-Everything-From-Scratch

I've tried writing some of the lodash functions myself to save on a dependency and usually end up missing some edge case that was already considered years ago by the lodash maintainers. I could have just required lodash and been done with it.

Something about the way both lodash and underscore functions are written/interfaced has always seemed incredibly obtuse and difficult to reason about for me. FP zealotry and ideals seem to have been top if mind in designing these libraries. I prefer the modern native functions hands down.
This has always been my feeling towards lodash, it is heavily overloaded with shorthand functionality that greatly reduce its readability to me.
As I understand it, this repo is also a library, but it's smaller. So, would using something like tree shaking (i.e rollup.js) make everything unused go away anyway (and people could continue using lodash/underscore)?
(comment deleted)
The very first code snippet is a reimplementation of 'chunk' that is at least quadratic. Run away.
To me, these articles are like arguing that your should use Assembly over C or C over something like Ruby. Sure there are cases where lower level makes sense, but the vast majority of modern web development has no need to be at a low level.

I much prefer using Lodash because it's reliable and well documented. Everyone on my team knows what it does, knows where to find the documentation, knows where to find the examples, and knows where to find documentation of edge cases. Lodash also includes some wonderful shortcuts and edge case handling.

Seriously, the best part of lodash isn't the code. It's how freaking easy it is to understand and use. If you want to replace lodash, you need to look at everything the package entails - not just the actual lines of code.

So instead of using a highly tested, modular, versatile tool - you're suggesting we copy-paste the functions we need?

Especially nowadays with tree-shaking and importing by module, I just don't think it makes sense unless you only need one or two functions.

Isn’t the solution just good tree shaking? Why not use something like Lodash and just have a tree shaker in your build step filter out what you don’t need in prod?
Not to mention Lodash has very complete browser support, unlike some of the native solutions in the linked post
(comment deleted)
Another useful aspect of lodash is familiarity. When you see a lodash function name you're familiar with, you can instantly place that piece of code within your mental model. No need to read 10 different implementations of the same filter.
Half the implementations that use "native" (likely polyfilled) APIs are basically the implementation that lodash uses! Not to mention you miss out on lodash's "chaining" API.

The suggestion is basically "don't use this well-tested, popular library, copy/paste all this other code (with no tests) into your source tree directly!" which is just ludicrous

Yeah this is borderline insanity to me. I just don’t get the point. I feel like the use case for this is extremely limited.. most developers don’t have such onerous bundle size requirements that they can’t afford to include lodash.
Nope. you don't. Don't need jQuery anymore either. Almost everything useful is implemented in native javascript now.
I'm not one to prematurely optimize things, but I'd be cautious about blindly copy/pasting some of these solutions unless you want your coworkers to make fun of your O(n^3) set intersection algorithm:

    array.reduce(function(a, b) {
      return a.filter(function(value) {
        return b.includes(value);
      });
    }))
https://github.com/you-dont-need/You-Dont-Need-Lodash-Unders...
So you stand the risk of actually learning something and improving your skillset. I'd say that's a plus.
The principal thing that bothers me about lodash is here's how it usually goes down: one piece of it snuggles itself initially and innocuously into a project for a good use case... only _for the entire bag of tools_ to perniciously grow into all corners. After this happens, some projects become lodash projects instead of JavaScript projects. Those who embrace it thoroughly solve problems differently than those who don't.

It's easy to become allergic to the API design, which subjectively I find old-hat compared to either native implementations or Ramda. (Yes there is lodash/fp, but there's still incongruities). And given the little variances, within the same project you generally don't want to have lodash here, FP or Ramda there - there is a cognitive cost. Dash way or the lo way? I accept that not everyone finds that a problem.

More substantially problematic, if you import all of lodash and you don't enforce an agreed upon subset of its API, you might end up having its broader philosophies imposed upon you.

There are others, but two that really bug me:

- I'd rather not have to grok _.chain when a codebase already has a more idiomatic use of chaining.

- Defensive coding is its own shed of bikes, but lodash applies it liberally, returning an empty array instead of throwing an error when fed undefined. This can obscure root causes, passing problems downstream and imposing an in-the-debugger mindset. Static analysis coverage and type safety can easily fall by the wayside.

(Linters exist to alarm you if you want to prefer native versions, or exclude explicitly specific parts of lodash.)