Legacy .NET to AWS: What I Would Tell My Past Self
I have now been part of two large .NET-to-AWS modernizations. The first was a public safety product suite moving to AWS GovCloud, working with AWS ProServ. I led teams on the early planning and execution phase before leaving for a different company, so the lessons here are from getting that program off the ground, not from carrying it to completion. The second is an on-prem-to-EKS migration I am leading at my current company.
Different decades, different domains, different teams - but the patterns repeat enough that I would write them down for someone about to start one.
1. The interesting decisions are about what not to move
Every modernization program I have seen starts with someone wanting to rewrite something at the same time. Resist this. The point of a migration is to move the system you have. The rewrites can come after, on their own schedule, when you have observability and rollback paths in place. Doing both at once is the most common way these programs fail.
In the GovCloud program we made an explicit list of things we were not going to change. The list was uncomfortable - there was code we all wanted to fix - but it kept the program scoped to "we are on GovCloud now" rather than "we have redesigned the system." Same discipline holds on the EKS migration: containers first, redesign later.
2. Sequencing is the actual work
The architecture diagram is the easy part. The hard part is the path between here and there. Which service moves first? What depends on it? What can run in both places? What is the rollback if it does not work? Most modernization plans I have reviewed are weak on this and strong on the destination.
A sequence I trust:
- Inventory dependencies and ownership. Find the modules nobody owns now. Those are the ones that surface during cutover at the worst time.
- Pick a candidate that is important enough to be a real test, but isolated enough that failure is not catastrophic.
- Build the deployment, observability, and rollback path for that candidate before you migrate it.
- Migrate it. Run both versions. Verify.
- Use the lessons to refine the path. Move the next candidate.
3. Observability before cutover, every time
The single biggest mistake I have seen is migrating a service before there is enough observability in the new environment to debug it in production. If you cannot see latency, errors, and traffic in the new place at parity with the old, you cannot migrate. You cannot even decide whether the migration worked.
This is unglamorous work. It also pays for itself the first time something goes wrong at 2am.
4. Deployment time changes what teams do
On the EKS migration I am leading now, the biggest improvement so far has not been Kubernetes. It has been getting deployment time from roughly 45 minutes down to under 10. That single change altered what the team is willing to ship on a Friday afternoon. Modernization programs that only think about architecture miss this. The deployment loop is the engineering culture.
5. ProServ is a sounding board, not a delivery team
In the GovCloud program AWS ProServ was useful because they had recent AWS expertise we did not. They were not useful as a substitute for our own application judgment. The teams I have seen waste these engagements treated the partner as a delivery resource. The ones that got value treated them as a technical second opinion. Keep ownership inside.
6. Customer cutover is engineering work
Especially in regulated industries - public safety, healthcare, claims - the customer migration runbook is as much an engineering artifact as the architecture. Data verification scripts, rollback procedures, on-call coverage during cutover, decision criteria for aborting and rolling back: treat these as deliverables, not afterthoughts.
What I would tell my past self
Spend more time on the path and less on the destination. Migrate the boring things first. Resist the urge to rewrite. Get observability in place before you cut anything over. And keep a written list of what you are explicitly not doing. It is the most useful document in the program.