This is a placeholder for a longer article I want to write about this fascinating topic - but I don’t want to be distracted from writing Mood Badge post :)
Here’s a TL;DR then:
Every communication protocol regardless of medium (it can be copper - STP cables, it can be fibre, it can be radio waves) is a stream of 0s and 1s and only the higher OSI layers make sense from it. You could then, if you had a very fast hand, emulate any protocol by flipping a bunch of switches on and off in a correct order - very, very fast.
The problem here is that sometimes it needs to be really fast - and it’s not only about the data transmission speed but also all the control bits that have to be transmitted along; control bits whose values need to be calculated for each byte sent. Putting manual switch flipping aside, this can be done then in software - by switching digital pins in a correct order. With SPI it’s easy as there are no control bits, it only has the clock (but at the same time SPI is very sensitive to timing); for I²C it’s even easier as it only has two wires; things get complicated for UART as sometimes you have to calculate parity (but you don’t have clock), while things like USB are far too complicated to be calculated by software (that is: you can, of course, but that is taking up limited MCU resources). Hence why most of the MCUs have several SPI, I²C, USB and UART interfaces whose control is being handled by hardware parts of those ICs. Those are black boxes that take data from the MCU and do the switch-flipping unattended.
Of course it’s not a new idea and there are even ready-made libraries for Arduino - like SoftwareWire. Check out the examples there and the Wikipedia entry while I am trying to write this post in a way that’s not another bit-banging manual, as we have plenty of those already :)