Skip to content

Latest commit

 

History

History
executable file
·
29 lines (15 loc) · 2.1 KB

adr-006.md

File metadata and controls

executable file
·
29 lines (15 loc) · 2.1 KB

ADR 6: Use pure functions, avoid hidden side effects

Context

It is common in Object Oriented Programming to have methods that modify the instance that uses them. For example, adding an item to a set would directly modify it. This even can be beneficial for re-using memory and other optimisations. However, this implies that the exact behaviour of a function depends on some state of the machine that is external to the function itself.

On the other hand, Functional Programming prefers pure functions where the functions are solely defined by their input-output relationship and no external state changes how it runs. For example, adding an item to a set would return a new, different, set with the item added; while the old set would remain unchanged.

Pure functions do not prevent changing a state, but the state has to be kept local to the code using it. This makes the side effects explicit and reduces the risk of unstable and hard to investigate behaviour due to a specific state.

Moreover, pure functions are easier to write unit tests for, since there is no need to set up the correct state before calling the function, and tear it down afterward. It suffices to provide the wanted inputs and observe the output.

Decision

We will use pure functions as much as possible. We may still use side effects where it makes sense, e.g. for performance optimisations.

We will keep properties in objects private and only accept changing them via selected methods that create new instances. This limits the risk of code modifying an instance of an object that might be shared elsewhere.

When getters expose mutable data structure (e.g. native Array), we will make sure to expose them as ReadOnly to avoid external mutation of instances.

Status

Accepted.

Consequences

The mix of classes with pure functions as methods can be a bit unsettling for new developers. Read more about it in the API design section.

The use of pure functions ensures referential transparency which in turns allows more optimizations and eases writing of unit tests.