Skip to main content

How AI-Driven Refactoring Cut a 2-Year Legacy Code Migration to 4 Months

Lilach Nachmias
Dec 01 - 5 min read
How AI-Driven Refactoring Cut a 2-Year Legacy Code Migration to 4 Months featured image

By Ishay Dahan, Lilach Nachmias, and Adi Vaknin.

In our Engineering Energizers Q&A series, we highlight the engineering minds driving innovation across Salesforce. Today, we meet Lilach Nachmias, Senior Manager of Software Engineering, who helped migrate the Own Archive managed package, a seven-year-old third-party application, into Salesforce’s Core infrastructure. Own is a company Salesforce acquired a year ago, and this effort modernized thousands of Apex files into Core-compliant Java. The team adapted to a monolithic codebase, which typically requires months of onboarding before engineers ship production code.

Discover how the team overcame undocumented legacy Apex patterns that made manual migration a two-year effort, resolved deep dependency chains that prevented AI from translating files in isolation, and redesigned static logic into multi-tenant Java that could run safely on Core, ultimately delivering a fully native product in just four months.

What is your team’s mission migrating the Own Archive managed package into Salesforce Core?

Our mission focused on transforming Archive from a third-party managed package into a fully native platform capability. Before migration, customers installed Archive externally, which introduced compliance friction and limited their ability to rely on platform-level security guarantees for core archival data flows. Running inside Core ensures Archive inherits native security scanning, permission enforcement, and platform-controlled deployment pipelines instead of relying on isolated infrastructure.

Migrating into Core also integrated the product into unified development workflows, shared environments, and centralized ownership models used across the platform. This reduces operational burden, enables tighter alignment with platform roadmaps, and allows engineers to apply consistent architectural patterns rather than maintaining package-specific logic. The goal was not just to move code — it was to elevate Archive into a first-party experience built for enterprise-grade trust and reliability.

What static legacy Apex patterns and undocumented dependencies made migrating this large codebase into Core a planned two-year effort?

The original codebase, designed for a standalone managed package, presented challenges in a shared multi-tenant platform. Over seven years, extensive logic accumulated across numerous files, lacking documentation and featuring heavy use of static methods and tightly coupled class designs. This made behavior difficult to trace, requiring manual interpretation of business logic and restructuring to fit Core conventions.

Historically, migrations of this nature demanded engineers rewrite code file-by-file, translating Apex into Java patterns and refactoring design decisions. Even minor migrations took months of manual effort, as each file needed re-understanding, re-implementation, and re-testing. Applying this manual approach to thousands of interdependent files introduced significant regression risk and slowed delivery cycles due to evolving dependencies.

A two-year plan reflected the estimated effort for manually translating a legacy architecture, ensuring behavior preservation and platform compliance without automation.

Redesigning the data model.

Why couldn’t Apex files be translated independently at scale, and how did deep dependency relationships complicate refactoring?

Translating individual files demanded a complete understanding of shared logic across the codebase. Many classes relied on lower-level utilities, shared constants, or static method chains that were only meaningful within the context of other implementations. Generating Java equivalents without these dependencies resulted in incomplete method signatures, ambiguous return values, or partial rewrites that appeared syntactically correct but deviated from expected runtime behavior.

This limitation escalated as the migration progressed. While translating a few isolated files was feasible, migrating 275 Apex classes and total of 3537 files hundreds or thousands required a structural awareness of how logic interacted across modules. Without a holistic mapping, translation produced code that appeared correct locally but performed unpredictably under multi-tenant execution. To address this, we first analyzed dependency relationships to identify classes for co-migration and those requiring upstream context. This approach shifted from translating isolated files to executing layered transformations based on architectural hierarchy.

How did dependency-graph–driven leaf-to-root refactoring enable large-scale Apex-to-Java migration?

We generated a complete dependency graph of the managed package to determine the conversion order based on reference direction. This identified leaf-level classes, such as constants and utility helpers, that had no dependencies. Migrating these first provided stable reference points that AI could reuse when converting higher-level classes later in the sequence. Each layer built upon verified implementations, ensuring consistent signatures and behavior throughout the codebase.

This iterative leaf-to-root process prevented cascading translation errors and allowed us to resolve ambiguity by referencing validated code instead of relying on assumptions. We repeated this cycle across the entire codebase until we reached root classes that composed broader workflows. The structured migration pipeline enabled us to translate thousands of interdependent files predictably and consistently. This approach transformed a multi-year manual effort into a four-month delivery while maintaining architectural alignment across layers rather than piecing together isolated rewrites.

How did AI help rewrite static Apex designs into scalable, multi-tenant Java with service-layer architecture?

The managed package heavily relied on static classes and shared global state. This worked when each customer ran the package independently but conflicted with Core’s multi-tenant environment where code must safely handle multiple tenants sharing infrastructure. Directly converting syntax would have reproduced these limitations, causing potential memory, isolation, and performance issues.

We defined transformation rules that instructed AI to generate object-oriented service layers with dependency injection and clear separation of state. Engineers reviewed output to ensure alignment with Core patterns, adjusting rules iteratively as deeper refactoring needs surfaced. Instead of migrating Apex unit tests directly, we extracted their logical intent and rewrote test suites in Java to validate new behavior rather than legacy structure. After migration, the total code surface doubled, supporting both the legacy managed package and the new Core version. This resulted in approximately 14,000 files maintained by the same engineering team, demonstrating how AI-assisted refactoring scaled development capacity without expanding headcount.

How did the team validate AI-generated code and prevent regressions during Core migration?

Migration required multiple layers of validation beyond automated conversion. The initial deployment revealed functional gaps that surfaced only through hands-on testing. Engineers manually validated flows end-to-end to ensure functional parity with expected outcomes, uncovering issues that ripple across components when architectural assumptions shift.

We conducted bug bashes with engineers outside the project team to broaden coverage and identify scenarios not immediately visible to core contributors. Early cycles surfaced many issues, while later phases uncovered only a few as the release stabilized. We rewrote tests based on signatures and logical intent rather than directly migrating Apex tests so validation aligned with new architectural boundaries.

Teams also plan to automate UI paths using Selenium to surface behavioral issues earlier. AI accelerated translation and reduced development overhead, but correctness required systematic test strategy, human review, and iterative refinement.

Learn more

Related Articles

View all