When we have conversation about API design, or more generally about fragments of code that we write or we think customers will write, we often talk about reasoning about code. We typically mean that someone reading the code will be able to understand the implications of making an API call for example, and write clean code accordingly. There is always a component of simplicity in code someone can reason about.
For example, someone might say that functional-style code is easier to reason about, because there are no side-effects and so you can concentrate on whatever local computation a given function does. Or someone might say that it’s hard to reason about code that deals with an object that has entered an error state, because the results of operations are undefined and it’s hard or impossible to keep track in your head about what the consequences of any given API call might be.
I think that beyond simplicity, the core of code you can reason about is predictability. To the extent that you can predict the behavior of a fragment of code, and it’s straightforward enough, you can reason about what the code does and what the impact of changes would be.
Going back to the previous examples, functional-style code is easier to reason about because once you predict what it does locally, you understand the complete picture – there are no other, off-to-the-side effects. When an object is in an error state, you can’t use it anymore (“you can’t touch it”, you might say) if you can’t predict what it will do – the core of the problem is that you can no longer infer things about its behavior and put it together with other concepts to use it.