How do BIP8 and BIP9 differ, how are they alike? With Taproot on everyone's lips, people have started discussing activation approaches. The debate is currently seems to favor BIP8. Previous soft forks used BIP9. How are the two related and what are the differences between the two?
Early soft forks each had their own activation method included in the proposal which relied on flagdays or block version signaling. The latter only allowed a single proposal to be considered concurrently as it relied on incrementing the block version.
BIP9 proposed an activation standard which allowed multiple proposals to be considered at the same time. Soft forks that were activated using BIP9 were coordinated by having a supermajority of hash power signal readiness for the upgrade (traditionally 95%). Miners are tasked to assess the network's uptake of the proposal and signal readiness by setting specific bits in the version field of their blocks. The miners readiness signal is measured over the last difficulty period at each retargeting height. For example, the segwit soft fork and the CHECKSEQUENCEVERIFY soft fork that activated BIP68, BIP112, and BIP113 used BIP9-based activation.
BIP8 is a variant and the successor of BIP9. BIP8 uses block heights rather than timestamps to bound the signaling window, and gives the option to either fail or lock-in the upgrade at the end of the signaling window. When lockinontimeout: true is set, nodes running the activation code only accept blocks that signal readiness in the last difficulty period before the timeoutheight. This forces the upgrade to lock-in to the end of the signaling window. In contrast, BIP9 would always fail after the signaling window passed without activation, so BIP9 worked equivalently to BIP8 with lockinontimeout: false.

via BIP8
Per BIP8, a proposal would get activated via the following steps:

The signaling period commences at start_height by switching from DEFINED to STARTED. The start_height would be set at least a month after release of the activation code. Note that the timeout_height must be the end of a difficulty epoch.

At each difficulty retargeting, every node running the activation code independently checks whether the signaling threshold was met in the concluded difficulty period. There are three possible state transactions from STARTED:

If the threshold is not met at timeout_height, the
proposal settles in the final FAILED state at the end of the signaling period.
If the signaling threshold was met, the proposal transitions to the
LOCKED_IN state.
If the proposal forces activation via lockinontimeout: true and
the last difficulty epoch of the signaling period is reached with
the proposal in STARTED state, the proposal transitions to MUST_SIGNAL. This causes upgraded nodes to reject any blocks that don't signal readiness.


The proposal remains in LOCKED_IN
state for one difficulty period and then transitions to the final ACTIVE state. Upgraded nodes now enforce the soft fork rules on the network.