reducecombine / fridge

Ideas for awesomer Clojure development
0 stars 0 forks source link

A spec-backed protocol for inter-service communication #9

Open vemv opened 5 years ago

vemv commented 5 years ago

Brief

Given a microservices architecture where services communicate via e.g. Kafka, I advocate that those Kafka messages should be:

Rationale

Specs

The usual reasons apply: contracts reduce the chance for misunderstandings, which often translate into bugs.

This particularly applies to ever-evolving, distributed systems.

Namespaces

I advocate that both message names, and those messages' attributes are heavily namespaced.

Versioning

As part of the namespacing strategy, version numbers should be part of each message/attribute namespace.

An additional benefit is that unit-testing has guaranteed correctness:

How

Monotonically increasing, natural version numbers

i.e v1 -> v2 -> v3 -> ...

Message specs are decoupled from model specs

Immutable, centralized message schemas

Closing thoughts

Specs in production

It would be unfortunate to do all this effort, and then disable spec checking in production.

I have created https://github.com/nedap/speced.def/issues/70 accordingly.

Zero-downtime + exactly-once processing

A usual problem in event-driven architectures is:

With my recipe, this problem disappears altogether:

jwkoelewijn commented 5 years ago

I see the appeal of this approach. I have one minor challenge regarding this approach, and that is that this approach seems to be Clojure oriented, in that it is heavily relying on namespace support of keywords and spec. Not saying that this is a problem, however, ideally we would like to have the same advantages for our Ruby consumers. Any thoughts on that?

For reference, at the moment we use https://github.com/nedap/postman/blob/master/bin/generators/ruby_generator.rb (which uses xsd2ruby under the hood) to build Plain Old Ruby Objects for the different messages we have defined using an XSD (see https://github.com/nedap/postman and https://github.com/nedap/postman/blob/master/models/Message.xsd). This approach, however, does not benefit from any checks and specs, however, being able to automate the classes is a nice feature.

Do you see any possibilities to generate the same using the approach you described for how to best deal with our messaging formats?

I know it is a lot to ask, however, I would like to think of an approach to migrate our current Postman messages to incorporate some of the ideas you mention as well, so consider these questions more as a hammock-time-trigger :)

vemv commented 5 years ago

Do you see any possibilities to generate the same using the approach you described for how to best deal with our messaging formats?

Yes. I'd keep using XSD in a quite similar manner, while adding:

That versioning could be achieved either using some or other official XSD feature, or in an ad-hoc manner by convention.

Out of this XSD, we'd emit both Ruby classes, and Clojure specs.

So, XSD remains canonical, while the goals of this issue seem still met.

One also could do it in the opposite direction (making specs canonical, emit Ruby out of those), but it seems an approach bound to give issues.