Skip to content

Compatibility Considerations

Steve Ebersole edited this page Aug 9, 2014 · 7 revisions

Compatibility refers to the ability of one version of a software component to work in place of another version of the same software component. When "upgrading" versions we refer to "backwards compatibility": can the new version be dropped seamlessly into a working system in place of the older version and the system continue to work properly. This is especially crucial for libraries, like Hibernate.

In an ideal world, this backwards compatibility would be maintained indefinitely. In the real world, as software is developed over time and evolves it is sometimes necessary to change signatures of methods and constructors or to refactor the code in ways (e.g. package changes) that might be disruptive to this backwards compatibility. Here we will discuss the considerations and guidelines followed by the Hibernate team in regards to this.

There are 2 topics related discussions when discussing .

Versioning Philosophy

The first topic when discussing our view on compatibility is how we name versions and the semantics of that. For the most part we follow the guidelines as defined by JBoss Project Versioning Guidelines, so that is a good background material.

Hibernate, however, applies some additional semantics. As mentioned in the project page the first number is the major version; the second number is the minor version. Hibernate considers the {major}.{minor} combination a release "family". We will discuss the implication of release families on compatibility below.

OSGi/JBoss refer to the next number in the version as the "micro". For Hibernate, this correlates to maintenance/bugfix releases within a release family. Again, we will discuss the implications of this below.

Code Categorizations

We conceptually divide the classes of the codebase into 3 broad categorizations:

  • The API is the set of contracts exposed to the application. For example, Session#save. It represents the intended means for the application to interact with Hibernate. Specifically speaking, this is code that we fully expect to be directly linked to (by the compiler) as part of your application bytecode.
  • An SPI represents an "integration point" with Hibernate and the contracts needed to perform those integrations.
  • The internals are classes and code meant only for Hibernate usage internally.

For the most part we try to denote these distinctions through the placement of classes into packages. Classes in packages with internal in the name are part of that internals categorization. Classes in packages with spi in the name are part of the SPI. Classes in packages with neither internal nor spi in the name are considered part of the API.

Grouping code into packages in this manner is an ongoing process and is still incomplete. The reason we could not do it en masse is, oddly, backwards compatibility.

The use of package names for this is unfortunately not granular enough oftentimes. Ultimately I would envision a better solution (annotations?)

In terms of compatibility considerations, the SPI categorization is unfortunately too broad. We have been working on defining it in a more granular fashion. A good high level break down (good enough for this discussion anyway) is:

  • The contract itself. E.g., the interfaces a "cache provider" would implement to provide caching services as an integration.
  • Inputs and outputs defined as part of those SPI contracts.

The "rules"

With the understanding of versioning philosophy and categorizations, we can now discuss the expectations users should have in terms of backwards compatibility (forward compatibility is not discussed here).

First and foremost, API contracts should be considered stable across all releases in a family. For example, if you develop an application initially using Hibernate version 4.0.0 and the application only uses Hibernate's API contracts the expectation is that you can drop in any newer Hibernate 4.x version and it will JustWork. Newer releases within a family might add to an API, but they should alter or remove.

SPI contracts should be considered stable within a release family, not necessarily across different release families. We do strive to maintain backwards compatibility for SPI contracts across families, it is just not guaranteed.

Users should have no expectations of any kind for compatibility when it comes to "internal" code.