Overview

1 Making programs safer

Programming is riskier than it looks: small defects can cause outsized damage, so professionals must prioritize safety by acknowledging human limits, favoring simplicity, and confining danger. Instead of seeking impossible bug-free software, the focus is on practices that remove whole categories of errors and isolate the rest: avoid mutable state and ad-hoc control flow, restrict effects to narrow boundaries, and avoid throwing exceptions. Kotlin helps with null safety and concise data modeling, but the core aim is predictability—programs that behave the same way every time for the same inputs.

The key idea is to handle effects safely by composing pure, referentially transparent functions that depend only on their inputs and don’t mutate or rely on external state. When real-world interactions are necessary, represent them as data and evaluate them at the edges. This yields deterministic, self-contained code that doesn’t hide failure modes and is easier to reason about. Because pure expressions are equivalent to their values, the substitution model applies: you can replace calls with results to reason about behavior, which simplifies testing (often without mocks), strengthens confidence, and improves maintainability.

A concrete example refactors a “buy donut” operation: instead of charging a credit card inside the function (a side effect), return the purchased item alongside a Payment description. This enables deferring, batching, or grouping payments and composing behavior via Kotlin’s collection operations (grouping, mapping, reducing). Pushing abstraction further with general operators like reduce and fold lets you write reusable building blocks once and rely on them widely, reducing bug surface. The result is modular, composable, and inherently thread-safe code built on immutability and pure functions, with unsafe effects isolated at the boundaries and a simple, reliable core.

Figure 1.1. A flow chart representing a program as a process that occurs in time. Various things are transformed and states are mutated until the result is obtained.
Fig01 01
Figure 1.2. Three buggy versions of the same program
Fig01 02
Figure 1.3. Comparing a program that’s referentially transparent to one that’s not
Fig01 03
Figure 1.4. Replacing referentially transparent expressions with their values doesn’t change the overall meaning.
Fig01 04

 Summary

  • You can make programs safer by clearly separating functions, which return values, from effects, which interact with the outside world.
  • Functions are easier to reason about and easier to test because their outcome is deterministic and doesn’t depend on an external state.
  • Pushing abstraction to a higher level improves safety, maintainability, testability, and reusability.
  • Applying safe principles like immutability and referential transparency protects programs against accidental sharing of a mutable state, which is a huge source of bugs in multithreaded environments.

FAQ

Why does the chapter call programming “dangerous,” and why do bugs matter so much?Because bugs can be extremely costly and sometimes catastrophic. Historical failures (like Y2K and the Ariane 5 crash) show how small defects can cause huge losses. Day-to-day, nondeterministic programs erode reliability: the same input may yield different outputs due to hidden dependencies, making systems hard to trust—especially critical ones (aviation, autonomous driving, etc.).
What are “effects” and “side effects,” and why are they risky?Effects are interactions with the outside world (I/O, DB calls, network, logging, mutating shared state). A side effect is any observable effect that happens in addition to returning a value. They make code harder to reason about and test, introduce hidden dependencies, and can fail for reasons unrelated to input data (e.g., a slow network or unavailable device).
What is referential transparency, and what benefits does it bring?Referentially transparent code neither reads from nor mutates the external world; its output depends only on its inputs. Benefits: it’s self-contained, deterministic, easier to reason about, does not unexpectedly break other code (no hidden mutations), avoids external device coupling, and typically does not throw recoverable exceptions.
How can I keep effects while making APIs safer (e.g., charging a credit card)?Return a description of the effect alongside the pure result instead of performing the effect immediately. Example: return a Purchase that contains the Donut (result) and a Payment (effect description). You can then evaluate effects at the boundary (immediately or later, even batching them), which improves testability and flexibility.
How does the substitution model help reason about programs?With pure functions, any call can be replaced by its return value without changing program meaning. This lets you reason algebraically about behavior. If a function performs effects (e.g., logs), replacing the call with the value changes observable outcomes—revealing impurity and potential surprises.
Which everyday language features are “programming traps,” and what’s the discipline advised?- Mutable references (shared state) - Control-flow by branching/looping used imperatively - Null references - Throwing exceptions for control flow Discipline: avoid or abstract them. Prefer immutability, higher-order operations instead of raw loops, Kotlin’s null-safety, and effect-restricting designs that don’t throw exceptions for expected cases.
How do safer (pure) programs improve testing and modularity?- Testing: no effects means no mocks/stubs are needed to isolate components; given inputs yield predictable outputs. - Modularity: functions compose cleanly because they only accept inputs and produce outputs—no hidden context mutation, no shared state, fewer interleavings to manage.
What’s the difference between reduce and fold, and when should I use each?- reduce: combines a non-empty list using an operation; no explicit initial value; result type matches element type. Fails on empty lists. - fold: takes an explicit initial seed and can produce a result of a different type; works for empty lists. Use fold for safety and flexibility; reduce when you’re sure the list is non-empty and the operation is closed.
How can I safely group and combine effect descriptions like payments?Collect Payments, group them by a key (e.g., creditCard), then combine each group (e.g., summing amounts) using a total function (like a combine method). This lets you batch external calls later (one charge per card), reducing fees and failure points while keeping core logic pure.
Why is abstraction central to making programs safer?Abstract shared patterns (loops, combining, grouping, error handling) into reusable, well-tested components (map, groupBy, reduce/fold). Writing these once and reusing them shrinks the bug surface, boosts reuse, aids parallelization, and encourages immutability and thread safety.

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$399.99
only $33.33 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • The Joy of Kotlin ebook for free
choose your plan

team

monthly
annual
$49.99
$399.99
only $33.33 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • The Joy of Kotlin ebook for free