I think I might have read it somewhere, or else I have introduced it myself, but one of my favourite metaphors about programming is:"All computer programs are simulations".
Some are obviously simulations of what happens in reality: aerodynamic flow around an airplane wing, or heat transfer in a nuclear reactor. However, other programs can also be viewed as simulations, but in a more subtle way. I here must exclude games, embedded systems, and real-time systems because I have too little experience to talk about them. However, I think the metaphor really applies to enterprise information systems.
Information systems are not simulations of what actually happens in reality, rather they are simulations of what would have happened had not the system been there. Let us take accounting as an example. In days of yore, the accountant was sitting with a physical leather-bound book, the ledger, and wrote down the transactions - one on each row. Today we have an accounting system that does this for us, so we do not have to do it ourselves. How, we can imagine that inside the box, there sit a little accountant and write those transaction-rows in a little ledger.
In reality, there is of course no little leather-bound ledger inside the computer. Instead there is some List-object on the heap, and other objects calling the add-method of that List, sending transaction data as argument.
However, I have found it most fruitful to embrace the "fantasy world" of a small leather-bound ledger. Because, that List on the heap, it is not any old List. It is a very special kind of List for which there are rules about what data it may contain, rules about what data can go in, and routines of how to handle it: check whether it is balanced, compute turn-over etc. It is not any List, it is a ledger. So, let us view it in that way, and build the class Ledger.
Suddenly it becomes so much easier to think about the code, to actually see if it does what it ought to do, and to see if client objects handle the ledger data in a sound way. Not to mention how much easier it becomes to talk about requirements.
As a result, I try to avoid returning "primitives" (such as int:s, doubles, Strings, and Lists or Maps thereof) from my public methods. Instead I create a class that someway represent this data in the fictive "fantasy world", and return an instance of that instead. My experience is that those methods are more easily understood and that the returned data has a higher chance of getting treated the right way.
It is not a coincidence that this "fantasy world" is very close to what we in Domain Driven Design refer to as our domain model of chosen abstractions.
So, of course not all programs are simulations. But I like to think of them that way; and it has helped me.