Types are the basic tool of software design. One of my pet peeves is when someone makes like they’re going to talk about software design, and then… talks about comments. Or they focus on the details about how functions get written. At the risk of using a tired metaphor, this is a bit like when an architect wants to do interior design. It’s not that the insides of a room don’t matter—a poor architect can absolutely create rooms humans have no use for—but it’s also not the important part. Furniture can be rearranged, load-bearing walls cannot. A function is the quintessential abstraction boundary. It’s one of the few cases where we should be able to ignore the details. We can write better and worse quality functions, but the internal details aren’t really relevant to the software’s overall design. It should be isolated. I think design is about everything that’s leftover after we remove all the function bodies. It worth taking a moment to think about what that looks like. Everything that’s left is just types. Even in dynamic languages, they’re just less detailed types: classes that have certain methods, functions that take a certain number of arguments, and the documentation associated with these things. Classical proscription against global state is largely about ensuring those types are meaningful. Any global state is something that could be used anywhere, and so it’s harder to guess how any function works as a result. Absent global state, the only things a function is working on are in its type signature. More modern aversions to deeply chaining method calls (e.g. “Law of Demeter”) are likewise attempts to meaningfully communicate what a function works with. I’m not a strong fan of these rules because they get misapplied. (Note to self: write a future post on this.) But there’s a solid kernel of a good idea here: a function should tend to operate on its actual stated arguments more than “literally anything it can possibly get to from its arguments.” Humans like to give names to things. It’s part of how we go about understanding the world. In one of Feynman’s books he jokes about the uselessness of just knowing the name of something, but I think he was quite wrong there. The name is the start: it’s the idea you start attaching your understanding to. It’s the tool for communicating with other people, and looking things up. And in programming, everything we give a name to is, or is associated with, a type. I was recently helping a kid learn to write some Python. They came across a situation where an interface was called for—but Python doesn’t really have interfaces. Inheritance wasn’t called for, as there was not even any shared implementation to speak of. After feeling a bit stupid for a minute (and after a quick google, deciding abc was too much to introduce), I ended up advising they just write up a “template” class in a comment. At least that gave them something to copy & paste, to start each new implementation of that not-interface. It’s really irksome when you can’t give a name to something important. Of course, it’s equally irksome when you have to provide a name for something that’s more structural. Java’s lack of function types comes to mind. Thinking about design