Many find the bigger picture of Ethereum Smart Contracts Lifecycle not clear enough. In this short article, I will try to explain in a simple way how someone new to the Ethereum eco-system or smart contracts could understand it clearly.I believe blockchain developers are familiar with object oriented concepts. Thus, I will take this as an analogy to explain the life cycle of Ethereum Smart Contracts.
To begin with, one could consider a contract as a class in object oriented terms, which is a template for objects. A contract may be deployed to a network multiple times, and each instance would have a distinct address, which could be used to interact with that particular instance of the contract at a later point. Therefore, each deployment of contract could be considered as an object instance in OO concepts. To clarify further, each instance is independent and has its own state (persistent data).
Constructor of the contract is invoked when deploying a contract to the network, and that is the only time it is invoked. So any initialisations you would do in the constructor, would execute only once and that is at the time of deployment. An address would be available at the end of creation of a contract, and that could be used to interact with it for the lifetime of the that particular contract instance. You could leave provision within the contract to destroy the contract by calling a method, which encapsulate selfdestruct. This termination maps with the destructor of an object in OO concepts.
If your solution needs more than one contract to conduct its tasks, it is necessary to deploy each of the contract independently. Only way for contract A to communicate with a contract B, is by knowing the address of the contract B. Both these contracts are first class citizens in the network even though one depend on the other. If contract A requires interaction with different instances of the contract B, then it is sensible to pass the contract B instance address whenever the relevant function is invoked. In contrast, if the contract always communicate with a single instance of the contract B, it would be easier to pass the contract B instance address as constructor parameter to the contract A and save it as a state variable.
If method fooA in contract A, invokes a method fooB in contract B, in the context of fooB, msg.sender has the address of the contract A as the value. If you want to identify the absolute message initiator, then you have to use tx.origin within the context of fooB. If you are calling fooA1, another method within contract A from fooA, then msg.sender is still the original sender who initiate the transaction, not the address of the contract A.
multiple_contract_test is a sample project which illustrates what has been described above. Please go through the README.md for more details.