The confusion almost always comes from treating the sequence and driver as one conversation when they're acutally two independent things that only meet at the sequencer. Once that clicks, the rest gets easier. Here's the flow in its simplest form. Your sequence doesn't touch the driver at all. It calls start_item and finish_item on a transaction, and those calls go into a queue on the sequencer. Meanwhile the driver, in its run_phase, sits in a loop calling get_next_item, drives the pins on the interface, then calls item_done. That four-call handshake is the entire mechanism. If your transfer test feels bloated, it's usually because people wrap extra layers of sequences and virtual sequences around it before they need them. For a simple test, one sequence, one sequencer, one driver is enough.
The other thing that trips people up is phasing. Sequences don't participate in the build or connect phases at all. They only exist during the run phase. Your test or env kicks them off from its run_phase, usually with something like seq.start(sequencer). That's it. If you find yourself trying to start sequences anywhere earlier, that's the sign you've tangled the hierarchy.
My practical rule: write one base sequence that sets up default transactions, then extend it for each scenario rather than building inheritance towers. Keep the driver dumb, it just turns transactions into pin wiggles and knows nothing about the scenario. All the scenario logic lives in sequences. When people end up with a monolithic mess, it's because scenario knowledge leaked into the driver or the test started doing the sequence's job.
For reading, the Siemens Verification Academy material is free with a work or school email and has a good step-by-step env build. The UVM Cookbook is denser but solid once you've got the handshake down. And honestly, writing a tiny two-transaction test from scratch without copy-pasting is the exercise that made it stick for me.