My take: SemVer is the worst thing to happen to software engineering, ever.
It was designed as a way to inform dependents that you have a breaking change. But all it has done is enable developers to make these breaking changes in the first place, under the protective umbrella of “I’ll just bump the major version.”
In a better universe, semver wouldn’t exist, and instead people would just understand that breaking changes must never happen, unless the breakage is obviously warranted and it’s clear that all downstreams are okay with the change (ie. Nobody’s using the broken path any more.)
Instead we have a world where SemVer gives people a blank check to change their mind about what API they want, regularly and often, and for them to be comfortable that they won’t break anyone because SemVer will stop people from updating.
But you can’t just not update your dependencies. It’s not like API authors are maintaining N different versions and doing bug fixes going all the way back to 1.0. No, they just bump majors all the time and refactor all over the place, never even thinking about maintaining old versions. So if you don’t do a breaking update, you’re just delaying the inevitable, because all the fixes you may need are only going to be in the latest version. So any old major versions you’re on are by definition technical debt.
So as a consumer, you have to regularly do breaking upgrades to your dependencies and refactor your code to work with whatever whim your dependency is chasing this week. That callback function that used to work now requires a full interface just because, half the functions were renamed, and things you used to be able to do are replaced with things that only do half of what you need. This happens all the god damned time, and not just in languages like JavaScript and Python. I see it constantly in Rust as well. (Hello Axum. You deserve naming and shaming here.)
In a better universe, you’d have to think very long and very carefully about any API you offer. Anything you may change your mind on later, you better minimize. Make your surface area as small as possible. Keep opinions to a minimum. Be as flexible as you can. Don’t paint yourself into a corner. And if you really, really need to do a big refactor, you can’t just bump major versions: you have to start a new project, pick a new name (!), and find someone to maintain the old one. This is how software used to work, and I would love so much to get back to it.