Skip to Content
🇫🇷 🇪🇺 Looking for experienced guidance on Lean software delivery? We'd be glad to explore how we can work together. Contact →

Parse, Don’t Validate

Alexis King ’s article, published in 2019, crystallized an intuition that many functional programmers carried without necessarily knowing how to articulate it.

The Central Thesis

The thesis is crystal clear: validation is an operation that inspects data and responds with a boolean, then immediately forgets everything it just learned. Parsing, on the other hand, transforms weakly typed data into strongly typed data, thus preserving the acquired information in the type system.

This seemingly subtle distinction has profound architectural consequences.

The Non-Empty List Example

King illustrates her point with the example of a function that verifies a list is non-empty before extracting its first element.

  • The validating approach returns a boolean, forcing the calling code to then blindly trust again or re-verify.
  • The parsing approach directly returns a NonEmptyList type that structurally proves the list contains at least one element.

The head then becomes a total operation, with no risk of exception. We no longer ask “is this valid?” but “what is the typed representation of this data?”, and failure becomes explicit via a type like Option or Either.

This philosophy is a direct continuation of Yaron Minsky’s Make Illegal States Unrepresentable, but addresses the dynamic aspect.

Where Minsky speaks of type structure, King speaks of the system’s boundary: that moment when untrusted data (user inputs, API responses, configuration files, etc.) enters our domain. Parsing constitutes this translation membrane that transforms external chaos into first-class citizens of our domain model, with all the guarantees that implies.

Trust Layer Architecture

In practice, adopting this approach leads to rethinking architecture in terms of trust layers:

  • At the periphery, we accept unknown or broad types like string
  • As soon as possible, we parse toward precise business types: UserId, PositiveInteger, ValidatedEmail
  • Once in the domain core, we exclusively manipulate these refined types

The compiler then guarantees that no unvalidated data can slip in. Smart constructors and opaque modules become the preferred tools for this strategy, exposing only parsing functions that return guaranteed types.

Impact on Maintainability

The impact on maintainability is considerable. Code becomes correct by construction rather than correct by convention:

  • We no longer need to wonder if a given function was called after a certain validation: the type attests to it
  • Tests can focus on business logic rather than defensive verification of preconditions
  • Refactorings become safer: if we forget to handle a case, the compiler signals it immediately

Alexis King thus reminds us that types are not just a convenience for autocompletion: they are a formal language for expressing and verifying our system’s invariants.

Want to dive deeper into these topics?

We help teams adopt these practices through hands-on consulting and training.

or email us at contact@evryg.com

Last updated on