Something I've seen a lot of supposedly Agile teams fail with is releases at the end of a project. Everything up to that point ticks along nicely, but the final sprint is a monstrous combination of time extensions, shifting scope, last-minute changes and unexpected problems. I've seen all sorts of ways of trying to mitigate it - "hardening" sprints, under-committed release sprints with a ton of slack in them, or just an organisational acceptance that developers spend an undefined amount of time running around headlessly while the release date slips ever into the distance.
The reality is that these problems are highlighting shortcomings in the way the company (not just the developers or the tech crew; the entire operation) approaches Agile development. There are a few key principles they're missing which prevent the nightmare release scenario.
1. Projects and releases are not a 1:1 ratio
I've put this first as it's the concept people really, really struggle with when they come to Agile development. In the old-fashioned waterfall world, "release" was a box right down the bottom end of the chart, which you did after everything else was finished and signed off. The whole point of Agile is that you don't do that. The ethos is to deliver working software as soon as possible - how else are you going to get feedback on whether what you're doing is the right approach?
The point at which you ought to be releasing is when you have a minimum viable product, of any shape. Your API isn't finished, but has enough functionality to be useful to someone? Get it out the door. You have a website that works, but doesn't have the shiny social media integration? Doesn't matter, get people using it. Lock things down to a beta group if necessary, but get some code on production servers. (This is one reason why the microservice approach fits neatly into the Agile world; you can have viable individual products well before the connected whole is available.)
The trick is that by releasing early and often, your environment and process becomes a known quantity. Yes, there will be disruption when you find a live server doesn't act the way you expected, or being pinged by health checks causes odd behaviour. But you're getting that out of the way early on, before you've decided on a release date or final scope. By the time it's critical, releasing should be a formality - ideally, no more work than clicking "promote" in your CI/CD system.
2. Get feedback
So, another key tenet of Agile development that people struggle with. Or rather, they get the idea of showing someone the software, but not the idea that every sprint, without fail, you invite a bunch of stakeholders into a room and show them what the current state of progress is. Sometimes that'll be the run through of a polished bit of functionality that usually comes to mind. But sometimes it'll be a proof of concept in a console application, or a rough and ready prototype, or even a few slides about how the production environment is put together. Sometimes it's no more than an apology from the team that everything has gone wrong over the past two weeks and they've got nothing to show.
This is one of the parts where Agile and the business have a hard time getting on, because here it needs commitment from everyone and not just the developers. I've had people get irrationally angry about being shown work-in-progress software, and act as if being shown a signup and registration process before the animations and gradient effects get applied is some tremendous personal affront and a waste of their time. The saving grace is that in most companies you can find at least a few people who are prepared to get involved in the process, and when their projects are much more stable, cost-effective and predictable than the norm the rest of the business starts to pay attention.
The benefit of getting this feedback early on is you don't run into the situation where you're a day away from go-live and it transpires that the application has the wrong text, the wrong graphics, and several workflows in need of urgent changes. Not only is that disruptive, but it also leads to the kind of short-term hacks and technical debt that cause bugs and make further development hard work.
3. Solve problems early
I once worked on a project that had a huge data reconciliation problem, to the point it simply didn't work unless one of the developers went and played with the database before any demo. This had been raised quite early on, but the general attitude was that the problem would somehow magically get fixed (ideally by someone else) or otherwise become trivial. I stepped in, and upset the team by insisting it was their biggest blocker and they needed to fix it now, before building anything else. Of course, the problem turned out to be far from trivial, and the solution didn't work in the way the team had been expecting. This added further work to correct code where they'd made those assumptions.
This may seem disruptive, but that work would always have needed to be done. The reason the team had been avoiding it was that they were trying to bring their finish date in as close as possible... but that's pointless. Had they proceeded in this way, they'd have discovered there was more work than they expected too late to meet that date, with no ability to reduce project scope to compensate. This is why blockers are your top priority to deal with - as you approach the end of the project, you should be working with purely known quantities, especially if you've promised a delivery date.
There's an overall theme to each of these three points, and it's about the way an effective Agile organisation works; which is an effective pipeline for turning the unknown into the known as soon as possible. That's not just technical unknowns like what your deployment environment looks like, but things like what your stakeholders and customers are going to think. If you're trying to hurtle towards a release date with a storm of unknowns gathering on the horizon, then you're lining yourself up for a turbulent experience.