-
Notifications
You must be signed in to change notification settings - Fork 2
Description
The Code and Contract Evolution section lacks a discussion of "implicit postconditions": observable effects of a function (whether side-effects or otherwise) that a caller empirically discovers. In practice, the tendency of callers to depend on such behaviors significantly impairs our ability to evolve how a function or type is implemented (hence, Hyrum's Law aka "The Law of Implicit Interfaces"). A classic example is a hash container whose callers accidentally depend on the iteration order of its elements, which effectively freezes the implementation of the container (given enough misbehaving users).
The perspective taken by the book might argue that clients depending on a postcondition not part of the contract are not "correct clients". In practice, and especially at scale, it seems inevitable that many clients will not be correct. It therefore seems worthwhile to discuss code and contract evolution in the presence of incorrect clients who lack awareness of their dependence on unpublished postconditions.
One documented means of fighting this tendency is to purposefully introduce nondeterminism into observable effects that are not governed by the contract. In the case of the hash container, for instance, production implementations have been deployed which inject nondeterminism (e.g., timestamp, git commit hash, etc) into the iteration order to guard against callers depending on it. It's not feasible to deploy such tricks for all conceivable postconditions, but I think the valuable lesson is: The observable effects of an interface should hew as closely to the contractually guaranteed postconditions as possible.
In the context of evolving code - especially pertaining to "evolving implementations" and "strengthening postconditions" - this feels like an important topic worth covering.