The language adopts certain design principles to make contracts tractable and hence easier to reason about:
Separation between computation and communication: Every in-contract computation (e.g., changing its balance or computing a value of a function) is implemented as a standalone, atomic transition, i.e., without involving any other parties. Whenever such involvement is required (e.g., for transferring control to another party), a transition would end, with an explicit communication, by means of sending and receiving messages.
Separation between effectful and pure computations: Any in-contract computation happening within a transition has to terminate, and have a predictable effect on the state of the contract and the execution.
Separation between invocation and chained contract calls: The language only allows tail-calls, i.e., every call to an external function (i.e., another contract) has to be done as the absolutely last instruction.