[The] principle of locality states that an object is directly influenced only by its immediate surroundings.
[...]
The concept is that for an action at one point to have an influence at another point, something [...] between those points [...] must mediate the action.
— from Wikipedia: Principle of locality
The concept is related to that of continuity: any change is mediated by a path without abrupt jumps.
We illustrate the concept of locality on many examples of non-locality in programming.
Side-effects are spooky action at a distance, thus non-local.
Callbacks are necessarily side-effectful, thus non-local.
Mutations are side-effects, thus non-local. Instead, interact through a typed protocol.
Runtime type errors are largely spooky action at a distance: providing a value of the wrong type at one place causes a type error at a different place.
Unchecked exceptions can pop out of nowhere and are therefore non-local.
Leads to non-locality of reasoning: code can be proven correct only after considering larger context.
The path connecting the meaning of the tested boolean to the respective branch of if-then-else is absent.
The translation (i.e. path) of the error from the domain where it originated to the domain where it surfaced is missing (i.e. a discontinuity).
The path between the problem and the observer is missing.
The gap between the source code and its typechecked version is too big (i.e. a discontinuity). The reader has to re-do type inference in their head.
Also, a code change at one place can cause a type error at a distant place (i.e. non-locality).
The gap between the source code and its explicit version is too big (i.e. a discontinuity). The reader has a hard time to reason about what value gets resolved.
Also, when a code change breaks the implicit resolution, a clear path from the change to the error is missing.
That is, when instances are constructed by "magic" (e.g. runtime reflection or compile-time macros).
The gap between the source code and its explicit version is too big (i.e. a discontinuity). The reader has a hard time to reason about what instance gets constructed.
Also, when a seemingly innocent code change causes construction of a wrong instance (i.e. a bug), it can easily go undetected.
There is a big gap (i.e. discontinuity) between the code and convincing oneself of its correctness.
For example, an actor implementation making an assumption that the actor will be supervised by its parent.
The path from the place where the assumption is made to the place where it is satisfied (if at all) is missing.
The environment is e.g. the file system, environment variables, Java system properties, ...
By concealed we mean not communicated in the component's interface (reading config from an explicitly given file is by itself OK).
It is non-local, because the path from the config (file, env variable, ...) to its use is missing.
Paradigm switch means an abrupt jump (i.e. a discontinuity) in the used mental and technological tools.
Paradigm switches often appear between:
- client and server,
- program and database,
- application programming and DevOps.
We believe the need for paradigm switches at these boundaries is not fundamental, but rather accidental.