Editor's note
Most post-mortems on D365 F&O programmes are written by the people who delivered them. That tells you something. The failures we keep seeing aren't really technical. They're governance gaps dressed up as bad luck. The team you signed for isn't the team that shows up. The cutover passes UAT and folds in week three. A pile of custom code starts eating two weeks of every regression cycle. Performance testing gets squeezed out by the deadline.
Each one has a control. None of them is exotic. This issue walks through four of them, in roughly the order they appear in a typical programme.
1. Before the contract is signed: audit the delivery team
The most repeated complaint we hear about D365 F&O delivery is the bait and switch. The senior architect who ran the pitch is gone by week two. You're left with a generic "Senior Consultant", a job title in a SOW rather than a person you've met. About 55% of D365 F&O programmes run over budget or schedule. Partner staffing instability is one of the documented root causes, and it rarely shows up in the post-mortems because the partners write them.
A few things actually work.
Ask for named resources with real CVs. Not "contributed to", full-lifecycle counts, finance implementations specifically. Then write a continuity clause around those names with a minimum tenure.
Run a two-week architecture sprint with the delivery team before you commit. Hand them a real chart of accounts, one legal entity setup, currency and tax and dimensions. If they struggle there, they will struggle everywhere.
At week six, before the first milestone payment, commission an independent design review. Data model, chart of accounts, posting profiles, intercompany setup. That's where the expensive mistakes hide, and they're cheaper to find at week six than month eight.
Call the finance directors from the partner's last three D365 finance implementations. Not the references the partner gives you. Ask about the team that actually showed up.
This isn't adversarial, it's protective. The good partners welcome it. The ones that don't are telling you something useful.
2. Before cutover: a performance testing workstream that earns its place on the plan
Here's the honest version. Most programmes treat performance testing as optional. It gets squeezed near UAT, and what comes out the other side is a small RSAT run rebadged as "performance verification". That isn't performance testing, that's regression testing pretending to be a control.
The distinction matters. RSAT runs single-user regression. PerfSDK runs concurrent UI load. JMeter or Postman exercise integrations. You don't get to swap one for another.
The questions a programme director should be able to answer before UAT closes:
What scenarios actually matter? Not "the system should be fast", something like "fifteen concurrent buyers create 150 purchase orders in 30 minutes, each PO posting in under four seconds, with the EDI sales order import batch running in parallel". That can pass or fail. The other version can't.
Where does the testing happen? A dedicated tier 4 or 5 sandbox, same Azure region as production, populated with production-volume data, run under real security roles (not SysAdmin, which bypasses the overhead real users actually hit), with extensions and integrations active.
How many iterations? At least two. One to find the issues, one to verify the fixes. Three or four is normal on a serious programme. If your plan has one, you don't have a plan.
What does steering see? One page per scenario. Target, observed, p50/p95/p99, pass/fail, blocking defects with named owners. The traces go underneath for the engineers.
A performance bug found in week 8 is a code review. The same bug at week 38 is a recovery exercise with the partner ecosystem watching. The same bug in week 1 of hypercare is the cutover, and possibly the SI.
Hope is not a control.
3. The first 90 days after go-live: stop pretending stabilisation is a different programme
The real D365 F&O problems don't show up on day one. They show up in week three.
Batch contention during month-end close. Intercompany eliminations that don't balance under real volume. Financial reporting trees that worked fine in UAT and now break with production data. By the time these surface, the implementation team's budget has expired, the partner has rotated to the next sale, and a managed services desk with no context on your chart of accounts is being asked to diagnose them.
The fix is structural. You need funded, named support from the people who built the system, for at least 90 days after go-live. Not "the partner is available for a fee". Named individuals, on the budget, with direct continuity from the build team.
Most programmes don't do this because implementation and stabilisation get budgeted separately. That's the bug. They aren't separate. The first 90 days is when the design gets stress-tested in the most unforgiving environment it will ever run in. Plan for that, or plan to fly blind at the worst possible moment.
4. Two years in: rationalise the extension estate before it owns you
We reviewed an estate last quarter that carried 43 bespoke X++ extensions on a two-year-old implementation. Every quarter service update was costing about £25,000 in regression and three weeks of internal capacity. Most of those extensions should never have been written.
That's the actual goal of rationalisation. Not zero custom code, that isn't realistic. Eliminate the code that shouldn't have been there in the first place.
Four buckets.
Remove. The process it served no longer exists. It was a workaround for a Microsoft bug that's since been patched. It duplicates standard functionality the original team didn't know was there. In a mature estate, 15 to 25% of extensions sit here.
Replace with configuration. The partner reached for X++ when D365 already had the capability. Custom workflows duplicating the standard Workflow framework. Custom number sequences re-implementing the Number Sequence engine. This is the highest-ROI bucket, and the place partners most often default to code when configuration would have done the job.
Replace with an ISV or Power Platform. The business need is real, but a productised solution is more sustainable than your in-house extension.
Keep. Genuinely organisation-specific, no alternative. Fewer than you'd think.
A few signals tell you what to prioritise. Extensions touching posting routines, batch jobs, or high-volume forms break most often during service updates. Extensions that need partner involvement to test, debug, or update after every cycle are where the recurring regression cost lives.
Two prerequisites before you start cutting. RSAT regression coverage on your critical finance and operations processes; without that, removing extensions is how you turn a rationalisation programme into a recovery programme. And phased waves, not big-bang. Five to eight extensions per cycle, across two or three service update windows.
Two habits separate the clients who manage their estates well. They run a build-vs-configure-vs-buy check on every proposed extension before X++ gets approved. And they audit the inventory annually, not when an update breaks something.
Closing thought
The pattern across all four of these is the same. The thing that breaks a D365 F&O programme is almost never the technology. It's a governance gap nobody was made responsible for closing, at procurement, at cutover, at handover, at the two-year mark.
None of these are expensive controls. The team audit is a few weeks of procurement effort. The performance workstream is a few hundred grand of testing on a programme spending tens of millions. The 90-day support clause is a budget reallocation. The rationalisation is a quarterly discipline.
What they share is that someone has to put their name on them and run them. If nobody owns it, it doesn't happen, and the programme pays for that omission later. Usually in the worst possible week.
— The Dr Dynamics team
