People usually call an app intuitive when it does what they expected. The status on screen matches what's actually happening, and if something breaks, they find out early enough to act. That sounds like frontend work, but the whole system has to agree about what is happening and what should happen next.
One experiment, multiple lifecycles
I ran into this while working on self-serve A/B testing at LinkedIn. The flow looked simple: choose two campaigns, decide what you want to measure, set the budget, duration, and audience, then launch the test.
I handled many of the frontend state, logic, and API gaps, led project syncs, and contributed to planning around state-synchronization issues.
Underneath, three related entities had lifecycles of their own. The test owned its duration, budget, criteria, and overall status. Campaign A and Campaign B each owned an objective, audience, placement, schedule, creatives, and delivery state. The test budget was divided between them according to the chosen split.
Validation crossed product boundaries. The A/B flow could validate its own fields, but campaign rules lived in another system and could change. Without bringing those checks together, a test could fail at launch or drift into an invalid state without telling the advertiser what happened or how to fix it.
We stopped treating validation as a final launch check. Current experiment and campaign rules shaped what could be selected, explained unavailable choices, and were checked again before launch.
Launch is only a snapshot
Creating the test only proved that everything lined up at that moment.
After launch, an advertiser could change the test's duration, budget, or criteria. A creative could be rejected, a campaign could be paused, or its schedule could change somewhere else in Campaign Manager. Those changes didn't need to happen inside the A/B testing flow to affect the experiment.
So we kept asking the same questions while the test was live. Are both campaigns still valid? Are they still comparable? Do their schedules still line up? Can the test continue as configured?
The A/B flow owned the experiment rules. We loaded both campaigns, then combined their validation results with our own checks for the test. The interface still needed honest loading, stale, ready, and invalid states without freezing the whole page.
The backend checked the important rules again before creating or updating the test. Once it was running, a lifecycle service listened for campaign events. When something changed, it fetched the latest campaign state, rechecked the experiment, and stored the result.
Updates can arrive late, out of order, or more than once. We had to build it so the system always landed on the right final state, even if the messages tripped over each other.
Make every change explainable
A budget change might be safe to sync. A rejected creative needed attention. A schedule change could mean the test was no longer able to keep running as configured.
On screen, we tried to make those differences obvious. We put issues close to the choice that caused them, blocked only the next invalid step, and kept the rest of the setup intact. If a campaign changed somewhere else, the testing UI still had to explain what changed and what the advertiser could do next.
Some campaign changes could break a live test. We blocked those actions in the regular campaign flow and sent the advertiser back to the A/B testing flow, where the change could be checked against both campaigns and the test before anything changed.
The result has to earn trust
Keeping these lifecycles aligned mattered. A stale campaign state could keep spend running longer than intended. A missed creative rejection or schedule change could leave the two sides out of balance. By the time the test ended and generated results, the comparison might no longer be useful.
The product only earned trust when those rules produced a clear, reliable experience. I like working in that gap.