An API is a sort of a promise–“You can always interact with our program this way, safely and exactly like we said.” When you release a new version of your product that doesn’t support the API from your old version, you’re breaking that promise.
Above and beyond any vague philosophical or moral considerations about this, the technical problem here is that this creates complexity.
Where once users of your API only had to call a simple function, now they have to do a version check against your application and call one of two different functions depending on the result. They might have to pass their parameters a totally different way now, doubling the complexity of their code if they keep both the old way and the new way around. If you changed a lot of functions, they might even have to re-work their whole application just to fit with the way your new API works!
If you break your API several times, their code will just get more and more and more complicated. Their only other choice is to break their compatibility with old versions of your product. That can make life extremely difficult for users and system administrators trying to keep everything in sync. You can imagine how quickly this could spiral out of control if every piece of software on your system suddenly broke its API for interacting with every other piece of software.
For you, maintaining an old API can be painful, and getting rid of it can make life so much simpler. But it’s not complexity for you that we’re talking about particularly here, it’s complexity for other programmers.
The best way to avoid this problem altogether is don’t release bad APIs. Or, even better (from the user’s perspective), create some system where you promise to always maintain the old APIs, but give access to more modern APIs in a different way. For example, you can always access old versions of the salesforce.com API merely by using a different URL to interact with the API. Every time you interact with the SalesForce API, you are in fact specifying exactly what version of the API you expect to be using. This approach is a lot easier in centralized applications (like salesforce.com) than in shipping applications (like Bugzilla), because shipping applications have to care about code size and other things. Maintaining old APIs is also very difficult if you only have a small team of developers, because that maintenance really takes a lot of time and attention.
In any case, releasing an unstable or poor API is going to either complicate your life (because you’ll then have to maintain backwards compatibility forever) or the life of your API users (because they’ll have to modify all of their applications to work with both the “good” and “bad” API versions).
If you choose to break your API and not provide backwards-compatibility, remember that some API users will never update their products to use your new API. Maybe they just don’t have the time or resources to update their code. Maybe they are using a tool that interacts with your product, but the maintainer of the tool no longer provides updates. In any case, if the cost of fixing their code is greater than the value of upgrading to new versions of your product, they could choose to remain with an old version of your product forever.
That can have a lot of unforseen consequences, too. First they keep around an old version of your product. Then they have to keep around old versions of certain system libraries so that your product keeps working. Then they can’t upgrade their OS because the old version of your product doesn’t work on the new OS. Then what do they do if some unpatched security flaw is exploited on their old OS, but they’re still tied to your old product and so can’t upgrade their OS? Or some security flaw in your old product is exploited? All of these situations are things that you have to take responsibility for when you choose to break your API.
And yet, having no API can lead to the same situation. People create crazy “hacks” to interact with your system, and then they can’t upgrade because their hacks don’t work on the new version. This is not as bad as breaking your API, because you never promised anything about the hacks. Nobody has the right to expect their hacks to keep working. But still, if management orders them to integrate with your product, those clever programmers will find any possible way to make it work, even if it sticks them with one version of your product forever.
So definitely make an API if you have the development resources to do it. But put a lot of careful thought into your API design before implementing it. Try actually using it yourself. Survey your users carefully and find out exactly how they want to use your API. Generally, do everything in your power to make the API as stable as possible before it’s ever released. It’s not a matter of spending years and years on it, it’s just a matter of taking some sensible steps to find out how the API should really work before it’s ever released.
And once it’s released, please, please, if you can help it, don’t break the API.