Types as a design tool

Types as a design tool

There are some programmer that love types and there are others who eschew them. When reasonable people fall on both sides, it's good reason to look for a latent variable that better explains the underlying motivation or cause. Latent variables, by definition, are hard to measure or observe and must be inferred. And when they're the motivation for taking a position, it can seem inscrutable to anyone on the other side of the position.

I think it's the same for types. Granted, there's many dimensions along which someone would or wouldn't like types, such as the design of the types system in the language of their choice or the amount of leeway in the problem domain they're working in. Even the experience of the tooling can affect how people feel about it.

However, I'd like to cover one dimension I haven't heard expressed often: How you think about types has largely to do with how your brain explores a problem space. Do you need to see how entities concretely interact, or do you need to see the structure of their relationships? Which one helps you understand the design space better? This is the latent variable, because the process of thinking is largely unobservable.

The other day, I saw Gordon Brandon talking about his organizational habits, and it got me thinking about how, in the design of many CRUD apps, you're forced to categorize a document in a named project when creating the documents.

A lesson I keep learning in different contexts: don't organize early. Dump it all in a big pile, put it all in one flat folder. Organize only sparingly, and only after things settle.

Gordon (@gordon.bsky.social) 2025-02-23T15:53:36.192Z

This is often an artifact of database schemas. The back end engineer established a foreign key constraint on the document; that it must belong to a project–in the name of consistency and clean data models. The end result is a user confronted with making a decision they're not yet ready to make: what project this document belongs to.

Because sometimes, in a new problem domain, we just have a clutter of information and artifacts in our head. We're not really sure what the big picture is, or if we know the big picture, the middle pieces are somewhat fuzzy.
We need to put it all to paper, document, or canvas in order to spot the generalities, to play with them to understand their properties, or to see how they interact and their algebras.

And as Gordan exemplifies, this is one aspect of why some people don't like types. When we don't even know or understand that these things are, we need to play with it to understand them. We're in no position to categorize things yet, and the type system is forcing me to make decisions when we're not yet ready. [1]

When we're in this mode of thinking, then we treat types as guardrails. It's something that constrains you from falling off the deep end, but it doesn't help in understanding the design space. And if the type system in the language that you use isn't well designed, then it becomes a tool that is supposed to be good for you, but keeps getting in your way of exploring the design space. That's when people start disliking types. It starts feeling like unnecessary ceremony.

However, if we have a decent type system and we have a grasp on the individual entities, we can start thinking more about how all these things relate. Is there a structure to these relationships? If we're this head space, then types can be leveraged as a design tool, rather than guardrails. The constraints in type systems can be used to frame and structure our thinking about the design space.

We can sketch out how all the pieces in the design fit together without worrying about its implementation. We can extrapolate the implications of our design decisions without worrying about the base toppling. Perhaps entities with the same structure of types are actually the same thing. And the tools that use types as a core engine to be useful can now warn us about the bounds and constraints that are violated in our exploration of the design space. But perhaps my constraints don't actually model reality if it keeps getting violated for good reasons. These are all different ways types can help me explore a design space within a structure or framing of thought.

I take the position that if I don't even understand what all the entities are in the space, then just playing with them concretely without worrying about their categories is a productive way to explore a design space to find a solution. But beyond that, it's more fruitful if I stop thinking of types as guardrails, and instead as a design tool. It's a design tool that keeps me honest about my declared bounds and constraints as I explore the design space.


[1] To be fair, it's not just type systems that suffers from this, but also classes in object-oriented programming. How many times have we suffered from the calcified decisions of our uninformed selves from the beginning of a projects that is now too hard to disentangle or undo?

See other threads about types by programmers with different experiences. 🍿