Two weaker promises
Pub-sub makes two promises weaker than newcomers expect, and both bite you in production instead of in testing.
Take ordering first. A system that partitions or fans out has no global order at all, so messages you published a millisecond apart can reach a subscriber the wrong way round.
What brokers actually give you is order within a lane. A Kafka partition keeps order for messages sharing a key, and the FIFO queues do the same per group.
Choose the key that matters, then, because that is the whole design move. Key your events by order and each order's created, paid, shipped sequence stays intact. That events for different orders interleave is fine, since no promise spans them.
Choose badly, or add partitions to a topic without thinking, and a subscriber sees shipped before paid.
Carry a version number or a timestamp in the payload anyway, and ignore anything stale. Rebalances and retries can still shuffle things at the edges even when your keys are right.
Delivery
Take delivery second. Almost everything durable is at least once, so every subscriber sees occasional duplicates, most often around restarts when acknowledgements are in flight.
Reach for the same remedies as with queues: handlers that can run twice safely, and deduplication on the event identifier. With several subscribers the duplicated work multiplies, because each one deduplicates on its own.
Know your broker's floor before you rely on it. A fire-and-forget broadcast delivers only to whoever is connected, so a subscriber restarting during your deploy silently misses everything published in the gap.
Summarise it the way you would in an interview. Pub-sub gives you order within a lane and at-least-once delivery at best, so write every subscriber as though messages will arrive late, twice, or slightly shuffled. Eventually they will.
Worked example
Jae builds shipment tracking on a Kafka topic where warehouse systems publish scan events. To spread load, the producer team partitions by warehouse station ID, so one package's scans, arriving through different stations, land on different partitions. Two percent of packages start showing out-for-delivery before arrived-at-facility, and support tickets follow. Repartitioning by package ID would fix future events but the topic already has consumers depending on its layout, so Jae fixes the subscriber instead: each scan carries the warehouse's monotonic sequence number, and the tracker stores the highest sequence applied per package, discarding any event at or below it. Late and duplicate scans now update nothing. When a consumer group rebalance during a deploy redelivers 4,000 already-processed scans, the dedup check absorbs all of them, and the tracking page shows every package's timeline in the right order.