Let's define backwards compatibility as follows:
If the user doesn't change anything, then the system behavior shouldn't change.
The user should not have to change their software to accomplish an upgrade.
In many ways this seems pretty obvious. Don't change API signatures unless you leave the old API in place. Don't change the program name or library location unless you're making a symlink to it. Basically, if it's an interface the customer uses, don't take anything away from it. (We can talk about deprecation separately).
All changes should be additive: offer the new way and make sure the old way works.
A big part of the consideration of defining backwards compatibility concerns is defining interfaces the customers might use. Make sure you consider the following:
- GUIs (form field order, workflow, accomplishable tasks)
- program names
- library names and locations
- file layout on disk (does your user use the number and names of these for monitoring?)
When you're thinking about backwards compatibility, it's up to you whether to preserve it or not. Just take some time to consider your interfaces with the customer so you can make the appropriate choice.