Side Effects & Immutability

Pure computation versus I/O and mutation, the functional-core / imperative-shell split, and what immutability buys and costs.

Side Effects

Computation returns a value; an effect changes something. Database writes and network calls are the obvious ones — clocks and randomness are the two that make a function look pure and behave otherwise.

Q · What counts as an effect in my code, and which of them are hiding inside functions that look like calculations?
Functional Core, Imperative Shell
▶ lab

Gather the inputs, decide with pure logic, then perform the effects the decision asked for. It makes the interesting part trivially testable, and it charges you for fetching data you might not need.

Q · How do I get the decision logic out of the I/O without ending up with a slower system and a worse database access pattern?
Immutability

A value that cannot change is a value you can reason about once. That buys local reasoning and cheap change detection, and it charges copying, allocation and awkwardness in the places that genuinely want to mutate.

Q · What do I actually get from making a value immutable, and when is the copying not worth it?
Mutability, Used Deliberately

Mutation is not the problem. Mutation of something with no clear owner is. Local ownership, a stated lifecycle and a boundary it does not cross make it the right design surprisingly often.

Q · When is mutable state the correct design, and what has to be true for it to stay correct?
Hidden Global State
▶ lab

A value reachable from everywhere is a dependency nobody declared. It shows up as tests that pass alone and fail together, functions whose behaviour depends on what ran first, and a concurrency bug you cannot reproduce.

Q · What does a global actually cost me, and how do I remove one without rewriting every caller?
Purity and Testing

A pure function needs no setup: you call it and assert. Every line of setup a test requires is the design telling you what that code depends on, which makes test friction the cheapest design signal available.

Q · What is my test setup telling me about the dependencies of the code under test?
Effect Boundaries
▶ lab

Push effects to the edges so the middle can be reasoned about — and know the limit: some domains are effects all the way down, and there the honest design is to make each effect a modelled step rather than to pretend there is a pure core.

Q · How far can I push effects outward before the pushing costs more than it buys?