TFA doesn't mention or acknowledge this aspect of the issue, but it did surprise me that they considered a version bump from 7.0.8 to 7.3.3 to be innocent looking.
In fact, these 'minor' releases actually appear to be quite significant and the issue in question in TFA was explicitly documented. [0][1]
I hate to say it but this was just a case of sloppy work on the startup's part. It took me less than 5 minutes to find that info.
[0] https://docs.mongodb.com/mongoid/current/tutorials/mongoid-u... [1] https://github.com/mongodb/mongoid/releases/tag/v7.1.0
Expecting programmers to audit all of their code before a minor update is ridiculous.
It's not the responsibility of OSS maintainer to ensure your software still functions after an upgrade if you're not even willing to spend a modicum of effort to hold up your own end of that bargain. This isn't a big ask, it's why there are changelogs and release notes in the first place; they make it so you don't have to audit the code every time the version changes.
If you're not willing to do that and want unattended upgrades for all dependencies, then this is where the 'no warranty' aspect of that OSS license comes in.
The OSS maintainer has no responsibilities at all so you are right. But if anyone was to blame, it's certainly the library. It's outrageous to radically change a function while keeping the name the same. Because of exactly this issue. If they renamed it you would get an exception which is much nicer.
Some deps you can trust the owner and just carefully review the change log. Even that would have caught this issue, though I'm not sure I'd count this gem as trustworthy.
Maybe you are a very careful developer, but the vast majority out there is not.
Shipping an udate that will corrupt data if you don't read the changelog is very very dangerous.
I see why they did it. Having a method with the same name as in Active Record but with different behavior is also dangerous.
But they really could have handled this better.
These days, it's more a case of updating one thing at a time, and doing the research up front to see what I'm gaining from it or if I might as well stay on the current version. No point updating for the sake of it.
That's 5-10 minutes of up-front, preventative effort that might otherwise become hours of reactive firefighting, and as much time spent on damage control, if it got into production unchecked.
However, you can't rely on this. Many open-source projects fill a niche and become popular when it isn't the intention of the author. This causes a disconnect where the users expect the project to be for them, when the project is really for the author. Mongoid seems to be more in the former category (for the user).
Because some libraries are badly managed, you need to audit all of them.
That said, strong types can be a godsend for catching accidental breaks, even if it wouldn’t necessarily have helped here. A strongly typed language that has a more disciplined ecosystem is less likely to run into these kinds of issues.
It’s one of the tradeoffs you pick when deciding between languages. I decided the tradeoffs didn’t work well for me and left for compiled languages, for now.
This would not be caught by compiling, strong types or anything else - this is a change in behavior which has been arbitrarily done by the maintainers of the dependency.
> Certainly it has something to do with the ecosystem, if the most popular MongoDB driver in the ecosystem is making breaking changes in minor versions.
How should this be handled? Should a "good" ecosystem vet every single change in every single library that gets updated? Or should there be no libraries and only stdlib instead (wait, I think I know a compiled language which did just that for quite a few years, let me think which one that was again...)
> How should this be handled? Should a "good" ecosystem vet every single change in every single library that gets updated? Or should there be no libraries and only stdlib instead (wait, I think I know a compiled language which did just that for quite a few years, let me think which one that was again...)
This isn’t really about Ruby vs all compiled languages, I mean, Brainfuck is a compiled language and that doesn’t mean I was endorsing Brainfuck to replace Ruby. However I would certainly endorse Go to replace Ruby. Rust too, although using Rust to do web development stuff feels like using a nuclear warhead to open a door.
Anyway, the reason why types is relevant to this discussion is because types are contracts that are statically enforced and the break that occurred happened due to a contract change. This change illustrates that even if you do have types it doesn’t guarantee you won’t have breaking contract changes. However, eliminating entire classes of accidental or intentional contract breaks is an obvious win/win. If it was as complex and obtuse as C++, nobody would bother. But C++ isn’t the only game in town anymore for fast compiled strongly typed languages.
Am I to believe that you hold every other language to this same standard? A single maintainer of a reasonably popular project makes one boneheaded decision in a release, and that's enough reason to denounce the entire ecosystem?
> That said, strong types can be a godsend for catching accidental breaks...
Ruby is a strongly typed language.
You probably mean static types, but even that wouldn't have helped here. This was a behavioral change and did not affect any of the (implicit, in Ruby) type signatures of the function. It would not have affected any of the explicit type signatures of the function in other languages. I say this as an enormous proponent of Rust and static typing.
You are tilting at windmills.
> Generally, a strongly typed language has stricter typing rules at compile time, which implies that errors and exceptions are more likely to happen during compilation. Most of these rules affect variable assignment, function return values, procedure arguments and function calling. Dynamically typed languages (where type checking happens at run time) can also be strongly typed. Note that in dynamically typed languages, values have types, not variables.
Just out of curiosity, exactly what do you even think weakly typed could mean by your own definition of it?
No need to address the other points, because we're talking about anecdotes and not scientific data. Yes, I'm using a single data point as an example about a feeling I have to justify my opinion.
But if a change like this doesn't cause some kind of uproar in the Ruby community, then the community has a problem.