Programmers rely on models and abstraction to manage the complexity of software. If we can’t easily reason about the program, we struggle to understand bugs, we are prone to add accidental complexity, and we take longer to build features. To mitigate this, we use abstraction to hide details behind simpler interfaces and we use models that define clear rules about how a process should behave.
Learning to use models and abstractions productively is a key challenge of software engineering. This idea is not new. The pursuit of better programming languages, patterns, libraries, and frameworks are all expressions of this. The broader our repertoire of such tools, the more likely we are to identify ones that fit the problem and circumstances well.
What I suspect is less appreciated is that easy-to-reason-about is not the same thing as easy-to-learn or even easy-to-write. For example, if language A takes more up-front effort to learn than language B, but is easier to reason about once learnt, learning it could pay off handsomely. As Russell said in his History of Western Philosophy:
The civilized man is distinguished from the savage by prudence, or, to use a slightly wider term, forethought. He is willing to endure present pains for the sake of future pleasures, even if the future pleasures are rather distant.
Thanks to Jan Sramek for commenting on drafts of this post.
Bertrand Russell, History of Western Philosophy (New York: Simon & Schuster, )