One great way to have stability is to rebase old code against new code
Say, you have the first function, with a specific signature and it does its stuff
Then later, you improve the stuff and the signature changes with a breaking change
Do not do that
Instead, create a new function (with a new signature) and push in it the whole code
And rewrite the old function to use your new function
This way, you keep one "production code": the new function. And you keep one interface-to-legacy code: the old function (which is nothing but a compatible gateway to the new function, and can be easily forgotten)
Old users have no breaking, new users have features, you keep a single code and are only burdened with a small compatible layer
Say, you have the first function, with a specific signature and it does its stuff
Then later, you improve the stuff and the signature changes with a breaking change
Do not do that
Instead, create a new function (with a new signature) and push in it the whole code
And rewrite the old function to use your new function
This way, you keep one "production code": the new function. And you keep one interface-to-legacy code: the old function (which is nothing but a compatible gateway to the new function, and can be easily forgotten)
Old users have no breaking, new users have features, you keep a single code and are only burdened with a small compatible layer