This following image helped me understand how decentralised applications fitted together. I'm typically a Java developer so I'm more familiar with writing middleware for some J2EE-server and hosting the application like that. I'm keeping this explanation somewhat very high-level.
I'm currently opting for the approach of:
- Replacing Java (backend code) with an Ethereum smart contract written in Solidity.
- My application would usually be coupled with a database for persistent storage. In order to reflect this with my new DApp, I'm opting for the usage of IPFS.
- IPFS stores the static content which is hosted throughout a network of nodes. e.g. images, front end code, data.
- Once we have the static content, i.e. HTML, JS, CSS we can then interact with our local Ethereum node. i.e. the blockchain (even more specifically, the smart contract that was deployed to the network via its contract address and the contracts 'abi'.)
- In the image we can see that there is an arrow pointing from Ethereum to IPFS. This is explained simply. We can store the hash of a file that was published to IPFS in the smart contract. With this reference we can retrieve it by using our IPFS node at any time.
IPFS NODE ----> REQUESTS
with content #
IPFS NODE <---- RECEIVES
corresponding content from network
- New shiny content file now included into the DApp for the user to play with!

I have a standard web application that allows users to upload their profiles. The extent of the Java code is reading in the data via endpoints and storing to a database. The application server would also server the static content to a user hitting a certain URL.
The decentralised version of this simple application would be as follows:
- Solidity back end to accept user data in the form of a hash (replacing Java back end). Changing the applications "Global state"
- IPFS holding webpage, will serve it upon request.
- IPFS holding more data relating the hashes stored in the smart contract.
A lot of logic in the application has migrated to the front end code. Note, this is a fictional application and has only been used as an example.
Here's a great example of connecting IPFS with a Solidity contract and querying both through the JS console in your browser.
Thank you, I hope this helps!