Upgrading Microsoft Dynamics NAV to Business Central is rarely just a technical operation.
The longer a company postponed the upgrade, the more technical debt accumulated in the codebase. What often looks like a “successful upgrade” is, in reality, only the beginning of a much harder journey.
Automatic conversion from C/AL to AL allows the system to compile and run, but it does not make the code modern, maintainable, or extensible. In many projects, the converted AL code still thinks in C/AL — and that is where refactoring becomes essential.
1. C/AL to AL Conversion – A Good Beginning of Something Bad
Microsoft actually provides an official tool for converting C/AL objects to AL:
Txt2Al Conversion Tool, available since Business Central 14.
Documentation: https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-txt2al-tool
The tool converts exported C/AL objects (TXT format) into AL files and, at first glance, does exactly what it promises:
- objects (pagest, tables, codeunits) are converted,
- code is generated
One of the most common examples: object names
Consider a converted codeunit header generated by Txt2Al:
var
SalesPost: Codeunit "80"; # wrong syntaxThis looks innocent, but in reality:
"80"is treated as a quoted identifier, not an object ID,- such code does not compile,
- the compiler expects either:
- a numeric ID:
codeunit 80 - or a proper object name:
codeunit "Sales-Post"
- a numeric ID:
var
SalesPost1: Codeunit 80; # correct
SalesPost2: Codeunit "Sales-Post"; # correctThe conversion tool has no understanding of intent — it simply preserves what it finds in the source TXT. As a result, developers are left with code that is technically converted, but not valid AL.
Other conversion issues include:
However, the conversion is purely mechanical and always introduces problems that must be fixed manually before the code even compiles.
- no extensions
- huge objects converted line by line without structural changes,
- C/AL-era patterns preserved as-is.
In reality, this is only the point where real work begins.
What you get after Txt2Al conversion is not modern AL code —
it is C/AL code written in AL syntax.
2. What Refactoring from C/AL to AL Actually Gives You
To understand why refactoring is necessary, it is important to understand why the conversion happens at all.
In classic C/AL development, there was no concept of extensions. Customizations were implemented directly inside the core application:
- base objects were modified,
- standard logic was changed,
- customer-specific code was tightly coupled with Microsoft code.
This model no longer exists.
In Business Central, extensions are not optional — they are mandatory.
Direct modifications of base objects are not supported, either in SaaS or On-Prem environments. As a result, every upgrade from C/AL to AL is also a forced architectural change.
What can be moved 1:1
Some converted objects can be placed into a new extension almost without changes:
- standalone reports,
- isolated tables,
- simple codeunits with no dependencies on modified base logic.
These cases are the exception — not the rule.
The real challenge: code embedded in the core
In most real-world systems, a significant part of the custom logic:
- was interwoven into standard posting routines,
- relied on direct modifications of base tables and codeunits,
- assumed full control over the execution flow.
This kind of code cannot be moved 1:1 into an extension.
Instead, it must be rewriten. Restructured to work with events, or redesigned around extension points. Or even decoupled from core logic using subscribers or events.
This is the fundamental challenge of refactoring C/AL code to AL: not converting syntax, but changing the way the code integrates with the system.
Why refactoring is unavoidable
Refactoring allows you to:
- extract custom logic from the core,
- reintroduce it through supported extension mechanisms,
- make the solution upgrade-safe and SaaS-ready.
Without refactoring, converted code often remains stuck in a state where:
- it technically exists as AL,
- but cannot be deployed as a proper extension,
- and cannot survive future upgrades.
In this context, refactoring is not an improvement —
it is a requirement.
3. The Most Common Problems After Conversion
Once the code is converted and technically moved into AL, teams quickly discover that most problems are architectural, not syntactic.
Business logic tightly coupled with the core
In C/AL, custom logic was often:
- injected directly into standard posting routines,
- dependent on modified base tables,
- assuming control over the execution flow.
After conversion, this logic still exists — but it cannot legally live inside an extension.
Massive conditional logic
Patterns like:
- large
IF / ELSEchains, CASE TRUE OF,- deeply nested conditions
are extremely common and usually represent:
- missing abstractions,
- missing extension points,
- assumptions that only one implementation will ever exist.
God objects converted as-is
Large “Management” codeunits survive conversion almost untouched:
- thousands of lines,
- unrelated responsibilities,
- hidden dependencies on global state.
They compile, but they block extensibility and testing.
Options instead of extensible constructs
Converted Option fields and variables:
- cannot be extended,
- force modifications instead of extensions,
- keep the logic closed instead of open.
This directly contradicts the extension-based model of Business Central.
4. Concrete Refactoring Techniques
Refactoring C/AL to AL is mainly about changing integration points, not rewriting business rules.
Extract custom logic from the core
The first goal is always the same:
Move custom behavior out of core execution paths and reintroduce it through supported mechanisms.
This usually involves:
- identifying decision points,
- replacing hardcoded logic with events or interfaces,
- restoring the original standard flow.
Replace conditional logic with polymorphism
Instead of branching logic:
- use enums to model intent,
- interfaces to represent behavior,
- implementations inside extensions.
This allows:
- adding new behavior without modifying existing code,
- isolating customer-specific logic,
- clearer responsibilities.
Break down monolithic codeunits
Large codeunits should be split along responsibility lines:
- orchestration vs calculation,
- validation vs persistence,
- infrastructure vs business logic.
This can be done incrementally, keeping the public API stable.
Introduce events intentionally
Events are the primary integration mechanism in extensions:
- publish them at meaningful decision points,
- avoid publishing events for trivial operations,
- never use events to compensate for poor structure.
Events should expose what can be changed, not how it is implemented.
5. Before / After: From Core Modifications to Extensions
Before (C/AL mindset)
- Logic embedded directly in posting routines
- Custom conditions mixed with standard flow
- Changes require modifying base objects
Example:
IF IsSpecialCustomer(Customer) THEN
HandleSpecialCase();After (Extension-first mindset)
- Core logic publishes an event or calls an interface
- Custom behavior lives entirely in an extension
- No base object modifications required
Benefits:
- upgrade-safe customization,
- isolated responsibility,
- easier testing and maintenance.
The business logic may stay the same —
the way it is integrated changes completely.
6. Impact on Testing and Performance
Testing
Refactored code enables:
- unit tests instead of only end-to-end tests,
- fake implementations via interfaces,
- isolated testing of business rules without database side effects.
Code that was impossible to test in C/AL often becomes testable with relatively small structural changes.
Performance
Refactoring often reveals hidden performance issues:
- unnecessary data loading,
- excessive
CalcFields, - inefficient loops over large datasets.
Modern AL features like:
- Partial Records,
- more conscious data access patterns,
- better separation of read vs write logic
help improve performance — but only if refactoring is done with awareness.
Clean code alone does not guarantee fast code.
7. When to Say “Stop”
Not all converted code should be refactored.
You should consider not refactoring when:
- the functionality is stable and rarely changed,
- the risk of regression is high and tests are missing,
- the code is isolated and does not block extensibility.
Refactoring should focus on:
- areas blocking extension development,
- code that prevents upgrades,
- components that are actively evolving.
Refactoring is a strategic investment, not a cleanup exercise.
Closing Thought
C/AL to AL conversion solves a technical problem.
Refactoring solves a long-term architectural problem.
Only when custom logic is fully decoupled from the core and reintroduced through extensions can a Business Central solution be considered truly modern and future-proof.
