From 4259dba37a59af1ce4ebafa842cee8a300736c40 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 7 Dec 2023 16:34:07 +0900 Subject: document versioning --- taler-developer-manual.rst | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/taler-developer-manual.rst b/taler-developer-manual.rst index ecee786f..12be5335 100644 --- a/taler-developer-manual.rst +++ b/taler-developer-manual.rst @@ -118,6 +118,55 @@ There are other important repositories without code, including: Fundamentals ============ +Versioning +---------- + +A central rule is to never break anything for any dependency. To accomplish +this, we use versioning, of the APIs, database schema and the protocol. The +database versioning approach is described in the :ref:`Database schema +versioning ` section. Here, we will focus on API and +protocol versioning. + +The key issue we need to solve with protocols and APIs (and that does not +apply to database versioning) is being able to introduce and remove features +without requiring a flag day where all components must update at the same +time. For this, we use GNU libtool style versioning with MAJOR:REVISION:AGE +and *not* semantic versioning (SEMVER). With GNU libtool style versioning, +first the REVISION should be increased on every change to the respective code. +Then, each time a feature is introduced or deprecated, the MAJOR and AGE +numbers are increased. Whenever an API is actually removed the AGE number is +reduced to match the distance since the removed API was deprecated. Thus, if +some client implements version X of the protocol (including not using any APIs +that have been deprecated), it is compatible for any implementation where +MAJOR is larger or equal to X, and MAJOR minus AGE is smaller or equal to X. +REVISION is not used for expected compatibility issues and merely serves to +uniquely identify each version (in combination with MAJOR). + +To evolve any implementation, it is thus critical to first of all never +just break an existing API or endpoint. The only acceptable modifications +are to return additional information (being aware of binary compatibility!) +or to accept additional optional arguments (again, in a way that does not +break existing users). Thus, the most common way to introduce changes will +be the addition of new endpoints. Breaking existing endpoints is only ever +at best acceptable while in the process of introducing it and if you are +absolutely sure that there are zero users in other components. + +When removing endpoints (or fields being returned), you must first deprecate +the existing API (incrementing MAJOR and AGE) and then wait for all clients, +including all clients in operation (e.g. Android and iOS Apps, e-commerce +integrations, etc.) to upgrade to a protocol implementation above the +deprecated MAJOR revision. Only then you should remove the endpoint and reduce +AGE. + +To document these changes, please try to use ``@since`` annotations in the API +specifications to explain the MAJOR revision when a feature became available, +but most importantly use ``@deprecated X`` annotations to indicate that an API +was deprecated and will be removed once MAJOR minus AGE is above X. When using +an API, use the ``/config`` endpoints to check for compatibility and show a +warning if the version(s) you support and the version(s) offered by the server +are incompatible. + + Testing Tools ------------- @@ -583,6 +632,8 @@ prepared. $ buildbot-worker start worker/ +.. _DatabaseVersioning: + Database schema versioning -------------------------- -- cgit v1.2.3