React sets a pretty good example here: react 17 is the most boring release in the world. The react team are not bad API designers that made 17 major mistakes. They may be the most considerate and pleasant API designers in all of frontend, actually.
React Native is on 0.64.4 (?) not because it‘s unfit for production but because they know the level of guarantees they can make about version upgrades is zero.
1: We made something that we think is good, but we don‘t know if others will and how they will use it. We tested it well in one scenario but not much else.
2. Now we actually understand how people use this and why they like it. We have collected all of their biggest problems and it‘s time to fix them.
3. Everyone loves our thing and it‘s very productive for them. That must mean we‘re geniuses. Let‘s fuck around and change the world.
4, 5, 6… Both we and our users understand that sometimes we need to make a breaking change. They already went through the terrible 2->3 migration so every other upgrade will be fine by comparison.
In an enterprise context there are probably enough layers that keep everyone in check so the step 3 where you run wild with your ideas never happens.
Although TBH it's not all bad; all anybody has ever really cared about is "are there breaking changes or not?"
In any case, it doesn't matter except to consumers of the API who need to know the level of backward compatibility.
In American culture (in my experience) everyone takes pride in learning from their mistakes - but no-one likes to think of them as failures.
We like more nuance on HN than Twitter seems to.
Which is why I think it is bad semantics to say changing an API is an indication of failure.
It's impossible to ship a perfect product. So perhaps we shouldn't use "failure" to denote not doing the impossible, and reserve it for cases where "success" is even possible.
You can add new APIs, etc, instead of breaking existing ones. Anytime you do a major rev because your changing an API or removing one, you could also ship new APIs instead and keep the major version the same.
Everything becomes a mistake eventually.
Also OpenGL 1.x didn't map to the underlying hardware even considering SGI, a lot of stuff was done on the CPU. The only time OpenGL matched the underlying hardware was around GeForce 2 and AFAIK that was really matching Nvidia's hardware - before and after that little window, OpenGL was its own abstraction.
But of course OpenGL is a very good example of an API done right (especially before Khronos took over and made a mess out of it): it did a reasonably good prediction for the future while providing a good API for the present (at the time) and even when the underlying hardware changed considerably, it still remains a very useful API with a reasonable mapping and its extension system allows it to take advantage of new hardware features without breaking existing code.
While i do not think Khronos did a good job on OpenGL, at least they did the right thing by making Vulkan a separate API instead of calling it "OpenGL 5", allowing the two APIs to coexist and not break any existing code. After all Vulkan is fine (even if not to my taste, it is unnecessarily oververbose and pretends to be a low level API when it isn't) if you absolutely want the best performance from a hardware abstraction API while OpenGL is still around when you do not need that and want something more user (programmer) friendly instead (though do not get me wrong, depending on what you do, you can extract a lot of performance out of OpenGL, though after some point you may need to switch to Vulkan).
A failure isn't always a bad thing. Sometimes it's the best thing possible.
Is this true? Maybe, maybe not, I'm neither a GPU driver write or a hardware writer, but I suspect no software writer in 1997 was going to predict the hardware of 2008.
You can get everything right and still intentionally introduce a breaking change in a future release.
Mistake/Failure both imply an extra level of judgement "Oh, if only you'd worked harder you would have had the right API design the first time and you'd never need a new version".
Sometimes the world changes around an API.
Sometimes there is data that can only be gathered from real world usage.
Sometimes there's new use cases to handle.
In short, I think OP's observation is that of a pessimist's.
If not "MAJOR.MINOR.BUG" (which needs no improvement IMO) I'd go with...
TECTONIC.FEATURE.FIX.
I mean, that's clever for a tweet, but I hope nobody takes that seriously.
It's pretty counterproductive to view design through the lens of getting something wrong or right. There's just iteration in the direction of improvement. It didn't start out wrong -- it was your best first attempt with what you knew at the time. Then you learned more and so it improved. But it'll never be "right", just incrementally "more useful".
API's aren't mathematical proofs.
Just in case anyone needs to hear it ;)