Skip to content

Commit 609cb16

Browse files
committed
Remove presence tracking from default values
This commit removes the recommendation for using presence tracking default values, and instead advocates for serializing default values. This ensures that whatever an implementation thinks the default value is currently is unambiguoulsy honored by anything that deserializers the message later at any point in time, including if the default value for that member has since changed in the model. This also removes the large amount of complexity that presence brings with it. While this does make it harder for a default value to change, changing defaults is meant to be very rare anyways. So the tradeoff here seems worth it given changing defaults was and continues to be so strongly discouraged.
1 parent b2b952a commit 609cb16

File tree

2 files changed

+46
-57
lines changed

2 files changed

+46
-57
lines changed

designs/defaults-and-model-evolution.md

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -328,12 +328,10 @@ The default value of a member that targets a shape with a default value
328328
MUST NOT be removed (by changing the value to `null`) since that would
329329
transition the member from non-optional to optional in generated code.
330330

331-
The default value of a member that targets a shape without a default value
332-
SHOULD NOT be changed. However, it MAY be necessary in extreme cases to change
333-
a default value if changing the default value addresses a customer-impacting
334-
issue or availability issue for a service. Changing default values can result
335-
in parties disagreeing on the default value of a member because they are using
336-
different versions of the same model.
331+
The default value of a member SHOULD NOT be changed. However, it MAY be
332+
necessary in rare cases to change a default value. Changing default values can
333+
result in parties disagreeing on the default value of a member because they are
334+
using different versions of the same model.
337335

338336

339337
### Readers MUST NOT differentiate from omitted or defaulted
@@ -368,21 +366,12 @@ an appropriate default value for the member:
368366

369367
### Default value serialization
370368

371-
Authoritative model consumers like servers SHOULD always serialize default
372-
values to remove any ambiguity about the value of the most up to date default
373-
value. However, to avoid information disclosure, servers SHOULD NOT serialize
374-
default values if the member is marked with the `@internal` trait.
375-
376-
To allow servers to change default values if necessary, clients SHOULD NOT
377-
serialize default values unless the member is explicitly set to the default
378-
value. This implies that clients SHOULD implement a kind of "presence tracking"
379-
of defaulted members.
380-
381-
A member that is both `@default` and `@required` SHOULD always be serialized,
382-
and implementations SHOULD NOT use any form of presence tracking to omit a
383-
member if the member is not explicitly set to the default value. It is a
384-
protocol-specific decision whether this is enforced in serialized messages;
385-
some protocols follow this strictly, whereas others may not.
369+
1. All default values SHOULD be serialized. This ensures that messages are
370+
unambiguous, and ensures that messages do not change during deserialization
371+
if the default value for a member changes after the message was serialized.
372+
2. To avoid information disclosure, implementations MAY choose to not serialize
373+
a default values if the member is marked with the `@internal` trait.
374+
3. A member that is both `@default` and `@required` MUST be serialized.
386375

387376

388377
### Impact on API design
@@ -671,8 +660,7 @@ then it would be possible to omit far more default values on the wire, because
671660
any time a required member is missing, a deserializer can safely assume the
672661
member transitioned from `@required` to `@default` and fill in the default
673662
zero value. This helps to avoid unintended information disclosure and can
674-
reduce payload sizes. The other major benefit is that presence tracking isn't
675-
needed because default values can never change.
663+
reduce payload sizes.
676664

677665
However, only supporting default zero values means that service teams will need
678666
to add confusing enum values like `""` and `0` to enums and intEnums. It also
@@ -684,19 +672,35 @@ processes to ensure that a service team understands the implications of
684672
changing a default value.
685673

686674

687-
### Always send default values
688-
689-
Always sending default values would be a big simplification to clients because
690-
it removes presence tracking. Always sending defaults would make it explicit
691-
as to what each party thinks the default value is. However, this would remove
692-
the ability for a service to change a default value if ever needed. While the
693-
service can change the default value and wait their consumers upgrade their
694-
clients the change will take effect, there is usually an extremely long-tail of
695-
users that will not upgrade to the latest version. If a service needs to change
696-
a default value due to an operational or customer impacting issue, then that
697-
change needs to take effect across all currently deployed clients as soon as
698-
possible, hence the need for presence tracking in clients to only send default
699-
values if they are explicitly set.
675+
### Omit default values or implement presence tracking
676+
677+
If clients omit default values, then the default value for a member becomes
678+
the complete discretion of servers. This allows services to change default
679+
values for members and see the change take effect immediately with all
680+
previously generated clients. This can be achieved by always omitting the
681+
serialization of default values or through presence tracking.
682+
683+
If clients simply omit the serialization of default values, then it could be
684+
problematic if a client actually wants to use whatever it thinks the current
685+
default value for a member is instead of an updated default value on the
686+
service. For example, if the client wants to use the default value of `10`,
687+
but the service has since updated the default value to `11`, the client will
688+
omit the serialization of `10` because it thinks that is the default, and the
689+
server will use the newly updated default value of `11`. Until the client
690+
updates to the latest version of the client, it is impossible for the client
691+
to use the previous default value with the service.
692+
693+
Presence tracking is the act of tracking which structure members were set
694+
explicitly to a value vs which structure members were set by a default value.
695+
If a member was set by a default value, the client can omit the serialization
696+
of the member and delegate the default value to the server. If the member was
697+
explicitly set to a value, including the default value, the client will send
698+
the default value to the server, ensuring that even if the default is changed,
699+
the server will honor the client's choice. The major issue with presence
700+
tracking is that it has steep complexity and size tradeoffs because it
701+
requires tracking internal state changes on what could otherwise be stateless
702+
types. Implementations are free to use presence tracking, though it isn't a
703+
requirement of integrating with Smithy's default values.
700704

701705

702706
## FAQ

docs/source-2.0/spec/type-refinement-traits.rst

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -142,27 +142,12 @@ of a member because they are using different versions of the same model.
142142
Default value serialization
143143
---------------------------
144144

145-
Authoritative model consumers like servers SHOULD always serialize default
146-
values to remove any ambiguity about the value of the most up to default
147-
value. However, to avoid information disclosure, servers SHOULD NOT serialize
148-
default values if the member is marked with the :ref:`internal-trait`.
149-
150-
To allow servers to change default values if necessary, clients SHOULD NOT
151-
serialize default values unless the member is explicitly set to the default
152-
value or marked with the :ref:`default-trait`. This implies that clients
153-
SHOULD implement a kind of "presence tracking" of defaulted members so that
154-
the member is only serialized if it is explicitly set to the default value.
155-
156-
157-
Default and required
158-
--------------------
159-
160-
A member that is both ``@default`` and ``@required`` SHOULD always be
161-
serialized, and implementations SHOULD NOT use any form of presence tracking
162-
to omit a member if the member is not explicitly set to the default value.
163-
It is a protocol-specific decision as to whether this is enforced in
164-
serialized messages; some protocols follow this strictly whereas others may
165-
not.
145+
1. All default values SHOULD be serialized. This ensures that messages are
146+
unambiguous so that messages do not change during deserialization if the
147+
default value for a member changes after the message was serialized.
148+
2. To avoid information disclosure, implementations MAY choose to not serialize
149+
a default values if the member is marked with the :ref:`internal-trait`.
150+
3. A member that is both ``@default`` and ``@required`` MUST be serialized.
166151

167152

168153
.. smithy-trait:: smithy.api#addedDefault

0 commit comments

Comments
 (0)