AI-Driven Development Series
Modernizing crm-api
A BVD Story
Jon Leahy | Staff Software Engineer | Pismo/Visa
Personal exploration - not an official initiative
AI-Driven Development Series
A BVD Story
Jon Leahy | Staff Software Engineer | Pismo/Visa
Personal exploration - not an official initiative

Case Study
A BVD Story

One of the earliest APIs. Built before the company had standards.
Built for our first major clients. And it worked.

And with them went the knowledge of what actually mattered.

calls per day
Itau had no idea where it was called in their own organisation.
Can't shut it down? Modernize it.

Groovy to Go. Like for like. Invisible to clients.
Work with clients to move to newer, supported routes.
Both had to succeed.

100 endpoints documented. We only needed 10.
The 10 we needed were the most complex.
Groovy to Go. Different paradigms.

Groovy runtime. Cannot be patched.

def calculateTax(amount) {
// TODO: review this later
return amount * 0.0825
}
8.25% - Why that specific value? Nobody could tell us.

Signal lost in noise.

Uncertainty doesn't shrink with headcount.

Out of a hundred.

Hidden business logic. Undocumented edge cases. Magic numbers with no explanation.

More budget. More time. More developers.
Same result.


The running system IS the specification.

Reverse-engineered from the external system. Real data. Real relationships.

Each response becomes a golden test case.

Ports. Adapters. Clean separation. Proper engineering.

100% hands-off. The system iterated on itself.

Found a difference? Investigated both systems.
Got the local system running on its own.
Identified what needed refactoring. Then refactored it.
Ran the comparison again. Until it matched.

crm-api
ext-gateway
deploy-scripts
Like onboarding a senior dev. Brilliant, but cuts corners.
You review. You push back. It doesn't get tired.

Tagging
Auto-create tags
CI/CD
Trigger pipelines
ArgoCD
Deploy to prod
Grafana
Query logs, feed back
Plus canary reports — error rates and traffic matching verified before every switch.
But these are all stories for another talk.

Like-for-like means bugs too. We weren't fixing the system.
We were replicating it exactly.

Testing: /calculate?amount=1000
Legacy: { tax: 82.50, total: 1082.50 }
Modern: { tax: 82.50, total: 1082.50 }
EXACT MATCH
Testing: /invoice/lookup/INV-2024-001
Legacy: { status: "paid", amount: 5000 }
Modern: { status: "paid", amount: 5000 }
EXACT MATCH


Traditional
BVD Method

No full user data. Test data wasn't enough.
To be 100% confident, we needed production traffic.

The old system served. The new system proved it could.

Shadow compare with production data means real customer data
in comparison logs. That needed careful handling.

The Strangler Pattern.
Get the new system running on production first.
Migrate route by route. API by API.
Gradually strangling the old system until nothing's left.

When test data isn't enough:
Run both systems on production.
Compare everything. Log the differences.
Build confidence from reality, not assumptions.





The running system was the specification all along.

The path wasn't as smooth as this story makes it sound.

Before that? Patchy. Experimental.
Not something you could build a migration plan around.

Replace the live API. Like for like.
No differences. No visible switch.
Users should never know it happened.
Complete continuity.

The old system stopped. The new one started.
Nobody noticed.

Old System
No docs
New System
Complete Swagger
Generated from captured behavior. Weeks of work, done in hours.

Same REST server. Same spec. Same tests. Same prompt.
GPT-3.5
Early 2023
Claude 2
Mid 2023
GPT-4
Late 2024
Claude 4
2026
Four models. Four rewrites. One report.

CRITICAL SQL injection in /api/users — unsanitised input
CRITICAL Hardcoded DB password in config.go
HIGH No input validation on POST /api/orders
HIGH Missing rate limiting on all endpoints
HIGH Error messages expose stack traces
5 critical/high issues found
Tests: 12/12 passed ✓
Tests passed. Security failed.


The Old Way
Audit → Find → Fix → Test → Repeat
Weeks of security remediation
The BVD Way
Regenerate with latest model
Same spec. Same tests. Zero issues.

Regenerate → latest dependencies. No upgrade treadmill.

We don't live forever. We have children.
They carry our genes. Our knowledge. Our specifications.
But they're born fresh. Better adapted.
The spec is the DNA. The code is the organism.
Each generation, born fresh. Carrying everything that mattered.

Models improve week by week.
Prompts improve week by week.
If the product is disposable...
Regenerate it.
Better code. Better architecture. Same spec. Same tests.

90% of that is slop.
Throwaway projects. Demos. Prototypes nobody maintains.
The difference? We have specs. Tests. A process.
Our regenerated code is production-grade, validated, and reproducible.

End to end. Tested. Documented. Proven once.
Scale to every legacy repo. Start with the critical ones.
Re-clone and regenerate as models improve.
The map is drawn. We just need to walk it.

crm-api. Like planet Earth in the Hitchhiker's Guide...
A minor microservice. But the process proved the approach.
And this is how we'll keep modernizing.

Weeks of validation
Solutions Architecture sign-off
Security Engineering review
Documenting every process
Full Pismo microservice infrastructure
The governance was the real work.

The process validates that BVD works.
No formal way to store the test data and contracts long-term.
Contract X-ray might be a solution — area of investigation.
The approach works. The tooling around it still needs maturing.
