Skip to content
This repository has been archived by the owner on Nov 30, 2022. It is now read-only.

[WIP] - New Versioning #284

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft

[WIP] - New Versioning #284

wants to merge 2 commits into from

Conversation

Yawolf
Copy link
Contributor

@Yawolf Yawolf commented May 22, 2020

New Versioning

We want to offer better versioning in Compendium, more clear and robust than what we have right now. In this PR I present a new way of versioning.

References

I used this post as a guideline.

How is it defined?

This new versioning is quite similar to classic SemVer, but with a few changes. The format is this:

model.revision.addition

In then post they propose this format:

model-revision-addition

But I don't like it and find it less intuitive than the one I used.

  • Model: it is equivalent to Major in SemVer. A modification that break interaction with all previously existing data has to increment this value.
  • Revision: Equivalent to Minor in SemVer. A modification that may, o may not, break interaction with all previously existing data has to increment this value.
  • Addition: Equivalent to Patch in SemVer. A modification that does not break interaction with all previously existing data has to increment this value.

The default, or first, version of a schema must be 1.0.0.

Show me the bowels!

Although in DB and HTTP Responses the version will appear as a String with the format I exposed above, in the code, a Version is a case class with this shape:

ProtocolVersion(model: ModelVersion, revision: RevisionVersion, addition: AdditionVersion)

Where ModelVersion, RevisionVersion, and AdditionVersion are Tagged Types, of type Int with Eq, Show, Decoder, Encoder, and Monoid instances.

In this way, it is much easier to handle a version or update it. That part of the code is a little bit documented.

@@ -1,6 +1,6 @@
CREATE TABLE protocols (
id CHARACTER VARYING(255) NOT NULL,
version INTEGER NOT NULL,
version VARCHAR(20) NOT NULL CHECK (version ~ '^(\d+\.)?(\d+\.)?(\*|\d+)$'),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did this here because of the tests, but I guess the correct way would be to create a migration?

@@ -3,5 +3,5 @@ CREATE TYPE idl AS ENUM ('avro', 'protobuf', 'mu', 'openapi', 'scala');
CREATE TABLE metaprotocols (
id CHARACTER VARYING(255) PRIMARY KEY,
idl_name idl NOT NULL,
version INTEGER NOT NULL
version VARCHAR(20) NOT NULL CHECK (version ~ '^(\d+\.)?(\d+\.)?(\*|\d+)$')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

/** An String that matches with format xx.yy.zz, xx.yy, xx */
type ProtocolVersionRefined =
String Refined MatchesRegex[W.`"""^(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$"""`.T]
object ProtocolVersionRefined extends RefinedTypeOps[ProtocolVersionRefined, String] {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we don't need this anymore... I have to give it a deeper look

VALUES ($id, $idl_name::idl, 1)
ON CONFLICT (id) DO UPDATE SET version = metaprotocols.version + 1
VALUES ($id, $idl_name::idl, $protocol_version)
ON CONFLICT (id) DO UPDATE SET version = ${protocol_version.incRevision}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Revision is updated by default, but this can be changed

@juanpedromoreno
Copy link
Member

Thanks @Yawolf ! I believe @BenFradet used this in the past, I'd like to know his thoughts. Also, the other thing is that we may miss compatibility with Schema Registry at API level 🤔

@BenFradet
Copy link
Member

yes, I think the idea in the post has several flaws especially regarding user interaction: people don't know what version to choose when they change their schema.

I think a simpler dichotomy would be:

  • major: when you break compatibility
  • minor: when you don't break compatibility

Regarding the api compatbility with schema registry, we can still do:

  • /v0/protocol/shop?version=1
  • /v0/protocol/shop?version=1.2

so it will still be mostly compatible

@Yawolf
Copy link
Contributor Author

Yawolf commented May 25, 2020

Thanks @Yawolf ! I believe @BenFradet used this in the past, I'd like to know his thoughts. Also, the other thing is that we may miss compatibility with Schema Registry at API level 🤔

@juanpedromoreno I gave a fast look to this last Friday. Maybe I'm wrong but in schema registry the versions are Ints. Check this:
https://docs.confluent.io/current/schema-registry/develop/api.html#get--subjects-(string-%20subject)-versions-(versionId-%20version)

version (versionId) – Version of the schema to be returned. Valid values for versionId are between [1,2^31-1] or the string “latest”. “latest” returns the last registered schema under the specified subject. Note that there may be a new latest schema that gets registered right after this request is served.

@Yawolf
Copy link
Contributor Author

Yawolf commented May 25, 2020

yes, I think the idea in the post has several flaws especially regarding user interaction: people don't know what version to choose when they change their schema.

I think a simpler dichotomy would be:

* major: when you break compatibility

* minor: when you don't break compatibility

Regarding the api compatbility with schema registry, we can still do:

* `/v0/protocol/shop?version=1`

* `/v0/protocol/shop?version=1.2`

so it will still be mostly compatible

Does Schema Registry accept versions such as 1.2, or 2.7? If so, then much better, but I thought it does not.

@BenFradet
Copy link
Member

no it doesn't but what I meant is that we can work around compatibility, we already abstract routing for compatibility reasons we can also abstract versioning 🙂

@Yawolf
Copy link
Contributor Author

Yawolf commented May 25, 2020

no it doesn't but what I meant is that we can work around compatibility, we already abstract routing for compatibility reasons we can also abstract versioning 🙂

I was thinking to create a function to generate new Schema Registry compatible versions from this new versioning. Something like:

1.0.0 -> 100
17.69.15 -> 176915
17.70.0 -> 177000

But this is only an injective relation, given a Schema Registry version that does not exist in our service, the only thing we could do it to set the current version in Shema Registry as the Model Version in out versioning:

1 -> 1.0.0
37 -> 37.0.0
123 -> 123.0.0

@juanpedromoreno
Copy link
Member

I'm fine with the Ben's proposal here

Regarding the api compatbility with schema registry, we can still do:

  • /v0/protocol/shop?version=1
  • /v0/protocol/shop?version=1.2
    so it will still be mostly compatible

👍 Thanks both!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants