At my company, we work directly with clients. Our project requirements drastically vary from project to project and are highly unstable.
It seems like whenever we finally get a handle on what the requirements are and begin planning/working on the features a new requirement comes in that turns the existing understanding upside down.
It's extremely frustrating to keep having to throw away work when we're told for the umpteenth time that "ok the requirements are locked in", and a week later we're hearing of brand new requirements.
I get that as developers we have to be "agile", but moving the metaphorical goalposts really sucks and 100% slows down progress.
Any tips or advice?
It’s hard to know what your product or products are from this, and if it’s one product per client, so it is “theirs” and you are doing custom development, or if you have a couple of products and clients set the roadmap on new features.
Regardless, know this isn’t unique. Many companies with direct customer input to roadmap or prioritization run into this. It gets more difficult when a few customers are responsible for significant chunks of revenue. The less diverse revenue sources, the less control the company has over its own destiny.
So are you just doomed and you should give up and be blown by the wind every time a user changes their mind? Eh, probably not, but it isn’t a dev-only fix. There are a lot of forms of discipline that can help, but if your account managers/sales support folk/executive team aren’t on board and willing to push back, have requirement freezes, have a minimum time between last change and development start, and so on then what dev does may not matter too much.
One possible system is to grant individual customers with a certain number of work units per quarter or half or whatever. Whenever you start doing any kind of work, it counts against their credit even if they back out or change their mind, and how they use their work units is committed by half, etc. Ideally there is still some number of weeks/months between their commit to the work and when you start work so you’re not starting on things they aren’t really committed to. Again, lynchpin is this being committed and enforced.
It may be the case that the sales engineers or technical account reps or product managers or business analysts or whomever gathers requirements and finalized them on your side is really bad at their job, too. If they aren’t asking the right questions, presenting options to narrow possibilities, and getting sign-off from an executive on the client’s side, then clients shifting their asks isn’t really their fault. They may not have expertise to do this themselves.
Some possible things you might do from the dev side that could be more “self-determined” is to be more deliberate about the ordering of implementation, doing some things “just in time” instead of significant pre-planning, making late-binding decisions as late as possible, and moving more functionality to a rules engine or other dynamic system that is flexible and easier to modify than core code. If you are told that the slate of incoming features requires new document storage, two new event types, and a new interface to an external system. All of the proposed features have user-facing UI components, and a few have new admin options. There are tough calls to make, often a new interface to an outside system may take months. It could be that you say you cannot commit to the user-facing work until the quarter or half after that is completed, and it may take 1-2 quarters to onboard. Some of the other things, like event types, may be trivial to add so you can wait until the last minute to start adding these in parallel with the associated UI work. New document storage may be expensive to add, but you may choose to create the data access layer that uses a memory-only mock of the storage first, and only when you have had unchanged requirements for a quarter or something so you actually add the new storage and swap a real implementation in the access layer while in parallel the code that uses the new storage can be written against the already-in-place data access layer.
All of this is, of course, hypothetical. In terms of managing team morale, be sure that any good designs or implementations are celebrated and recognized, and are considered for perf and promo. Something shipping when that often gets derailed by clients should not be the only work that “counts”. When there is a change, allow engineers to continue to work to a reasonable stopping point, commit the work, have it disabled, and move on. If it is revisited later, great. If it is abandoned it can be removed when that is high confidence.
This isn’t easy, a lot is out of your control, so taking baby steps and minimizing the impact is probably best.
This sucks, sorry you have to deal with it :/ My first instinct here is to reflect - have you (or someone on the team) documented how much the requirements change, and the impact that has in terms of added work or communication?
If you have that, it's extremely powerful to summarize that across multiple projects. e.g. create a 1 pager of the major instances of this happening across a 6 month stretch.
In my experience, you'd be surprised how many people in the organization don't even realize that this is a problem. Doing this reflection + summarization work goes a long way in getting everyone aligned.