-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: Distinguish the different meanings of a "message" #156
base: merge-main-into-3.0.0
Are you sure you want to change the base?
Conversation
82674e6
to
7e4a2d8
Compare
@lmars @SimonWoolf — added you as reviewers because I thought you might have opinions, but feel free to ignore. |
my thoughts:
|
7e4a2d8
to
8a1d221
Compare
8a1d221
to
1dd532b
Compare
Is your concern literally about the fact that there would be two classes, or the fact that there would be two classes whose definitions are almost identical? If the latter, how would you feel about, for example, having incoming and outgoing message classes which subclass some common class?
These languages could choose not to implement two different classes, and just have one?
Given that the IDL does represent nullability, would this not need to be
Thanks, I've updated my changes.
I'm not sure what you mean here. Is it that in order to specify how the client library should be implemented (i.e. what's currently described by the feature spec) one must necessarily describe how the Realtime service behaves and some ways in which a client must behave in order to correctly interact with it? That's true, for sure. But what about the other way round — do you believe that it's possible to describe the protocol in a manner that is more concise and understandable than describing exactly how the client library must be implemented? And if so, do you believe that there is value in that — perhaps, for example, from a didactic point of view, to help people understand the motivation behind the implementation requirements described by the feature spec? The feature spec definitely has a "handed down from the gods" vibe at the moment, and I wonder whether empowering developers to understand why it is the way it is might be a good thing. |
The context for this suggested change is ably-js#1398. There, I pointed out that the specification’s current signatures for `publish` (specifically, the overloads that accept a `Message` or an array thereof) do not seem to match how we’re expecting these methods to be used in real life. This is because `Message`’s `id` and `timestamp` properties are specified as non-optional, meaning that a user calling `publish` would need to populate these properties. In reality, we do not expect a user to populate these properties — they are usually generated by the Ably service. The easiest way to solve this would be to be to make these properties optional. However, doing so would unnecessarily remove some useful type information for _recipients_ of messages — the type system would no longer communicate that these properties are guaranteed to be populated in a message emitted by the library. In this PR, I’m proposing that we distinguish between three separate concepts of a "message", which I think are perhaps currently being incorrectly conflated: 1. The data type that a user of the library passes to the `publish` methods 2. The data type that the library emits from methods that expose messages published on a channel 3. The data type that describes a serialized message that is transmitted over the wire I’ve named the first one OutgoingMessage, the second one IncomingMessage, and I believe that the third belongs in the documentation for the Ably protocol, not the library specification. OutgoingMessage and IncomingMessage differ from the existing `Message` type in the following ways: - OutgoingMessage’s `id` and `timestamp` properties are now optional - OutgoingMessage does not have `fromEncoded*` methods - IncomingMessage does not have constructors I have not yet introduced spec points for these two new types — I will do so if there is a consensus to move forwards with this approach. For now, see the changes to the IDL. Other thoughts: - I think that, similarly to the Message wire type, the ProtocolMessage type should also only be described by the protocol documentation, and not the feature spec. - If we do choose to start leaning more heavily on the protocol documentation, then we’ll need to bring it up to date — it looks like it hasn’t been touched in quite some time and still mentions `connectionSerial`, for example. - I’ve kept the exact same list of properties in IncomingMessage and OutgoingMessage, since my reading of RSL1j is that a user publishing a message should be able to populate any of the properties of the message that eventually gets sent over the wire. But if that’s not the case, then we may be able to remove some properties from `OutgoingMessage`.
1dd532b
to
028c94f
Compare
We're addressing this in ably-js in line with your suggestion, @SimonWoolf: ably/ably-js#1515. |
The current type of `any` for an outgoing message is overly permissive and doesn’t help users understand the shape of the object they need to provide. So, we: 1. change the Message class to an interface, which represents a Message-shaped object; 2. make Message’s `id` and `timestamp` properties optional (since we’re going to also use this interface for outgoing messages, which don’t necessarily have these properties), and compensate for this loosening of the Message type by introducing an InboundMessage type to represent messages received from Ably; 3. update the signature publishing methods to accept a Message object. Note that we deviate from the feature spec in that, in the feature spec, the publishing methods accept a Message instance. There are a couple of reasons for this deviation: 1. Accepting a Message-shaped object instead of a Message instance is consistent with our usage of the library in all of our existing example code and our tests, and is, I think, how things tend to be done in JavaScript. 2. The types in the feature spec are wrong; as things stand there, a user needs to provide a Message to the publishing methods, but Message has non-optional `id` and `timestamp` properties even though a user is not expected to populate them. We haven’t yet figured out how to address this error in the feature spec (i.e. do we introduce an InboundMessage type like we have here, or do we add some comments and leave it for library authors to figure out?); I started a dicussion about it in [1], but we’ve decided that we’d like to proceed with this ably-js change (which, since it’s a breaking change, we want to get into v2) without waiting for it to be addressed in the feature spec. Resolves #1472. [1] ably/specification#156
The context for this suggested change is ably/ably-js#1398. There, I pointed out that the specification’s current signatures for
publish
(specifically, the overloads that accept aMessage
or an array thereof) do not seem to match how we’re expecting these methods to be used in real life. This is becauseMessage
’sid
andtimestamp
properties are specified as non-optional, meaning that a user callingpublish
would need to populate these properties. In reality, we do not expect a user to populate these properties — they are usually generated by the Ably service.The easiest way to solve this would be to be to make these properties optional. However, doing so would unnecessarily remove some useful type information for recipients of messages — the type system would no longer communicate that these properties are guaranteed to be populated in a message emitted by the library.
In this PR, I’m proposing that we distinguish between three separate concepts of a "message", which I think are perhaps currently being incorrectly conflated:
The data type that a user of the library passes to the
publish
methodsThe data type that the library emits from methods that expose messages published on a channel
The data type that describes a serialized message that is transmitted over the wire
I’ve named the first one
OutgoingMessage
, the second oneIncomingMessage
, and I believe that the third belongs in the documentation for the Ably protocol, not the library specification.OutgoingMessage
andIncomingMessage
differ from the existingMessage
type in the following ways:OutgoingMessage
’sid
andtimestamp
properties are now optionalOutgoingMessage
does not havefromEncoded*
methodsIncomingMessage
’sconnnectionId
property is now non-optional (i.e. we are now able to provide stronger type information for this property) — I need to double-check whether this property is actually guaranteed to be populated by the library; my reading of TM2c and RTL6f suggested that it is, but I’m not sure if TM2c’s "the @connectionId@ of the encapsulating @ProtocolMessage@" is guaranteed to be populated.IncomingMessage
does not have constructorsI have not yet introduced spec points for these two new types — I will do so if there is a consensus to move forwards with this approach. For now, see the changes to the IDL.
Other thoughts:
I think that, similarly to the
Message
wire type, theProtocolMessage
type should also only be described by the protocol documentation, and not the feature spec.If we do choose to start leaning more heavily on the protocol documentation, then we’ll need to bring it up to date — it looks like it hasn’t been touched in quite some time and still mentions
connectionSerial
, for example.I’ve kept the exact same list of properties in
IncomingMessage
andOutgoingMessage
, since my reading of RSL1j is that a user publishing a message should be able to populate any of the properties of the message that eventually gets sent over the wire. But if that’s not the case, then we may be able to remove some properties fromOutgoingMessage
.