1. Developers learning that running code is not the same thing as reliable code. Certain things must be put in at design time to allow for operations.
2. Operations people supporting development by formalizing/streamlining the deployment process to have changes occur faster, safer, and more often.
3. Aligning goals and attitudes in such a way that prevents conflict between teams. Development doesn't get to shift the costs of outage prone unmaintainable code onto an ops team. Or that ops doesn't roadblock/veto all changes.
In the bad old days, it was common for developers to act with little care for operational outcomes. The responsibility was far removed, and bugfixes didn't win many accolades. Managers want wish fulfillment and pushed developers to toss new features into the mix as fast as possible, resulting in tremendous pressure against ops teams to deploy despite increasingly crufty and debt laden code bases causing unpredictable problems. Ergo, ops teams who blocked all changes for trivial issues because they were judged only based on outages, not feature delivery.