I'd like to explain what we do on theto preserve backward compatibility of our Java APIs. We've done several iterations and we now have a process that is working quite well, even though there are still some issues but they're unavoidable with Java for the time being.
So here it goes:
- We start by having a internal package. For example: org.xwiki.instance.internal.* and everything we put in there is considered implementation details and should never be used by users of our APIs. We're allowed to modify anything at any time in the
- We also use a internal package). , which forces us to separate interfaces (which are public) from implementation (which go in the
- We have defined an which allows us to move deprecated code that we no longer use to legacy maven module (using Aspects with AspectJ) that can be optionally installed at runtime, and which we never use at build time. This prevents us from using any deprecated legacy code and it allows us to push away the cruft under the carpet (without breaking backward compatibility!)
- We have the notion of @Unstable annotation to signify to users that this API is unstable for the moment and can change at any time. We only allow an API to remain unstable for a full . We've recently introduced a that enforces this! and when a new API is introduced, the developer can (and should) use the
- Last, we use the to make sure we never break an API unintentionally (it fails our build). This allows us to . It also allows to us to mention what we break in our Release Notes ( ).
The important point IMO is that we have automated tools to ensure that our strategy is applied, namely:
- Our Unstable Annotation Checker (a custom checkstyle rule)
This is working pretty well for us even though we do break backward compatibility from time to time, when we judge that the code touched is unlikely to be used and working around the breakage would be too complex and would take too much time (for example adding a method in an interface requires writing a new interface and modifying all code accepting that interface). Luckily this is going to be made somewhat simpler in Java in the future with(introduced in Java 8). It won't fit all cases though.
Another example of backward compatibility aspect that we don't handle is when someone changes what an API returns or what a API does. A simple example is if a method returns an object of type X but the implementation changes to return another implementation of type X that behaves differently... This is a tough one to detect and prevent.
WDYT? Are you doing something else in your projects? (I'd be curious of ways to improve even further what we do!).