its low quality, breadth but no depth
more important is to deeply understand the basics of working with immutable data. try writing applications with no for loops or forEach (and actually use the array methods as they are intended), no cloneDeep hacks and obviously no direct property mutation, always create a new object.
in real world you still use for loops plenty, but as a junior its good to see what its like to live without it for a while.
Immutable.js has similar data structures but it's not the standard way of doing things and uglier to debug.
Using standard objects, immutability is not enforced in JS and throwing a few Object.freeze calls won't change that so we lose half the benefits that Clojure would bring: parallel/concurrent programming benefits, easier deep equality checks, performance...
If the code is not performance sensitive and can run in a single thread, simply "not mutating some of the mutable data" is a start for someone interested in immutability. That's what ramdajs does, it doesn't invent new data structures or freeze objects but simply returns new ones.
Only a few functions from ramdajs are actually useful in 2025 since JS has evolved with things like array/object destructuring and "..." but in any case it's an inspiring library.
One thing to note, i was very excited that we have a bunch of lazy methods on Iterator protocol, but they are slow as shit as of earlier this year.
I wrote a parser a year ago with extreme use of .map (every step of processing was cloning the tokens), and i thought, let's migrate it to lazy iterator - it got ~10x slower :(. The compile time was fine for my use cases, so i didn't give immutable-js a try, but it was a surprise
I did some benchmarks on map+filter vs mutable for of + push, and on firefox up to 200-300 elements map+filter is actually faster (unforunately not on chrome).
Of course, its not the best, but my experience is that modern js engines are fast enough for most use cases to not have to bring in any libraries anymore
It looks like `addBook` is using the spread operator, which always creates a shallow copy of the book instance properties, thus nullifying any benefits of the flyweight pattern. It also attaches extra arbitrary properties, but still assigns the result to a `book` variable. I don't think this is a great example.
[1]: https://www.patterns.dev/vanilla/flyweight-pattern/
Edit: I forgot to give you kudos for all the effort it must have taken to create all this content, and I appreciate that you're making it available for free.
No, the opposite: it highlights the benefits of the flyweight pattern. The shallow copy saves memory. That's the point. You have two identical books. Rather than wasting memory with a deep copy, you make a shallow copy, where all your props point to locations in memory where values are located, and then you modify whatever is different. Now your shallow copy only consumes a small bit of extra memory.
And if those props are all primitives, then you can then modify that shallow copy, and it won't affect the original.
> The shallow copy saves memory....
Versus not making a copy? A shallow copy of primitives still copies them and uses additional memory. Maybe there's some low-level optimization that makes it more efficient than that, but it's not relevant here. And there isn't any deep cloning happening in the example.
Might as well get rid of the complexity and instantiate a new Book class every time. And maybe stop shallow-copying class instances into new plain objects. It works for the example but has footguns.
Conveniently, there are other patterns on the site that would help you avoid creating an amalgamation of random merged class instances and objects.
The whole example is a mess.
For example, prototype pattern is for languages that don't have a way to express interfaces/traits etc as something that can be attached to other language entities.
Anything that reliably shortens that loop is “good tech,” even if it’s ugly, uncool, or built on last decade’s stack.
I tend to advocate for people to study design patterns. Not for the purpose that you will necessarily ever use most (or even any) of these exact patterns in your software, but just that you've strengthened your mental muscle for software design in general. I encounter lots of engineers who simply aren't able to think "outside the box" when building something new.
Personally, I prefer to learn FP patterns, which tend to be backed with nice mathematical properties behind them.
I was hoping for more high-level architecture based on war stories and experience. This is pretty basic stuff, which has it's value for people earlier in their journey, and does seem to have effort put in from a quick peruse