In a previous life, I worked with continuous-maintenance systems, as used by the Linux glibc libraries team, the Sun binary stability team, and historically, the Multics kernel team.
In all there cases, we managed a codebase so that while there were changes, they were evolutionary, not revolutionary.
Others tried to avoid change
Other companies, famously Microsoft, try to prevent any incompatible change, while still fixing bugs. Languages designers do the same, so, C, Perl and Python claim to be backwards-compatible.
They all tried to avoid changing the “major number.”
They Failed a lot
In Microsoft’s case, they ended up releasing entirely new versions of their programs.
Windows 3 was entirely replaced by Windows 95. Windows 98 was replaced by NT 3, and NT 4 was replaced by XP.
The Perl authors released a series of slightly-incompatible changes. The Python team? Oopsie, Python 3!
Trying to avoid all change forced them all into massive change. Symbolized by a major number change.
Don’t Do That!
Sun, Linux, Multics and my current employer don’t do it that way.
We upgraded our architecture at work by running bits of both at the same time.
There was no ‘flag day” when we “shut down Windows 98 and booted NT on all our machines”. Instead we supported bits of the old architecture as we introduced new code and new functionality. And then we retired the old.
We mutate our databases, too, with a specific process for adding new columns and retiring old ones, something that almost everyone uses.
Google does mutation too: have a look at their gRPC schemas, which allow deprecation, retirement and replacement.
Systems with shared libraries use controlled mutation a lot. I learned how to to that on Multics (and yes, it still existed when I was in university), and saw it independently re-invented by David J Brown of Sun, and again by the Glibc team of Linux. Linux does it to this day, to protect end-users from being surprised with changes that should only affect the innards of the system.
Instead, make versioned changes, and maintain just enough backward compatibility to keep code running while we replace it.
As Paul Stachour notably said “In software, adding a six-lane automobile expressway to a railroad bridge is considered maintenance, and it would be particularly valuable if you could do it without stopping the train traffic”. (See You Don’t Know Jack about software maintenance in the Communications of the ACM. I was Paul’s editor (:-))
We do that every day.
We continuously maintain a codebase, and manage the change through compatible changes, followed by deprecating the old code and retiring it.
Major numbers in version identifiers are from an older era and a failed process. Don’t have catastrophic flag days, and don’t have the major numbers used to organize them.
Major numbers are good for marketing architecture changes, not implementing them.