In this webinar, Krzysztof Bialowas (KB) — a Business Central developer and architect at an ISV and VAR — walks through the habits, patterns, and real production examples that separate clean AL code from messy code. Moderated by David Singleton, the session covers both the theory behind why messy code happens and a hands-on tour of concrete tips to avoid it. KB draws on code he has encountered in customer databases and AppSource apps, using those examples to illustrate what to do — and what to avoid.
What Does “Messy” Mean?
KB opened by asking what messy development actually looks like. The common characteristics include lack of proper formatting and indentation, absent comments or documentation, spaghetti code, poor naming conventions, and code that is difficult to reuse or optimise. He was candid about having worked with messy code — and having written it himself — emphasising that the point is not to judge developers, but to understand the conditions that produce it.
The reasons behind messy code are often structural: time and budget pressure, lack of experience, technical debt inherited from previous versions, absent organisational standards, working in isolation, poor analysis before development starts, and simply not knowing which tools are available. The time/cost/quality triangle is real — cutting time typically cuts quality — but KB argued that awareness of this trade-off is what makes the difference.
📖 Docs: Best practices for AL code — Microsoft Learn — Microsoft’s official AL coding best practices, covering naming, structure, and AppSource requirements.
The Cost of Messy Code
KB outlined what happens downstream when messy AL code reaches production. For customers, upgrades take longer and can break — especially when deprecated patterns or hardcoded object numbers are involved. For ISVs, publishing low-quality code to AppSource means anyone can read it, and reputation suffers. For colleagues, inheriting messy code wastes time on debugging problems someone else introduced. KB made the point that the credibility cost extends to the entire partner organisation, not just the individual developer.
Tools That Help
KB identified four organisational and individual tools for keeping AL code clean.
Code Review
Even solo developers benefit from code review. KB’s approach is to push to a separate branch and review the pull request himself before merging — a habit that regularly surfaces issues he would not have spotted otherwise. For teams, he recommends a four-eyes principle (at least two reviewers) and automated checks built into the pull request pipeline: a spell checker action, a check for leftover TODO comments, and a label requirement for pull requests that include automated tests. The message is to never skip code review under time pressure, because the time spent fixing post-merge issues is always higher.
Custom Rule Sets
AL supports custom rule sets that override the default severity of CodeCop, AppSourceCop, PerTenantExtensionCop, and UICop rules. KB’s team reviewed all 217 available rules and changed the severity of 114 of them — treating many warnings as hard errors so that builds fail on violations rather than just reporting them. Examples include flagging identical names for local and global variables as an error, and enforcing correct application area order. The rule set is agreed across the whole organisation, not set by individual developers.
📖 Docs: Using the code analysis tools with the ruleset — Microsoft Learn — How to configure a custom .ruleset.json file to promote warnings to errors in your AL project.
An important caution from KB: don’t implement all the rules at once. Rolling out a strict rule set onto existing code generates a flood of errors. Instead, agree the rules as a team, phase the rollout, and treat it as an ongoing refinement effort.
Code Refinement
Code that was written cleanly can still become messy as Microsoft evolves the platform. KB gave the example of ApplicationArea — previously required on every field in pages, now only needed on tables. Existing extensions that still declare it on every field carry unnecessary noise and may produce warnings in future versions. His team plans code refinement cycles explicitly in their product roadmap, so partners can see that the extension is actively maintained. This also applies to performance improvements such as adding SetAutoCalcFields to replace lazy CalcFields calls.
Practical Tips from the Demo
Start Right with app.json
KB sees incorrect app.json configurations frequently in both PTEs and AppSource apps. A proper app.json includes a meaningful name, publisher, brief description, correct runtime and application versions, and the right resourceExposurePolicy. For AppSource apps, at minimum allowDebugging should be true. For PTEs, allowDownloadingSource should be true — though KB acknowledged this can be a business or legal decision rather than a purely technical one.
Always Develop in English
Code written with variable names, procedure names, or comments in a language other than English (KB showed a Polish codeunit with Greek comments as an example) is unmaintainable by any developer outside that language group. Use English for all code, and use AL translation files for UI strings that users see. Mixing languages in code is a maintenance liability that compounds over time.
Use Labels, Not Hardcoded Text Strings
Using text strings directly in Error, Message, or StrSubstNo calls instead of Label variables means the text cannot be translated and cannot be tracked in telemetry. The AL language extension makes this easy to fix: select the string, use the “Extract to Label” code action, and the label is created with a single click. KB mentioned doing this as a habit even when prototyping — write the string, then immediately extract it.
// Messy — hardcoded string
Error('This record cannot be posted');
// Clean — label variable
ErrorLbl: Label 'This record cannot be posted';
Error(ErrorLbl);
Never Hardcode Values
KB showed two real examples of hardcoded values from production databases. In one, a currency code was hardcoded in an UPDATE-style operation against all non-USD invoices with no validation — code that corrupted the customer’s data and took multiple developers and consultants to untangle. In another, a hardcoded table number (such as 15 or 17) was used instead of the object name, which broke compilation after a Microsoft upgrade. Use setup tables to let users configure values, and always reference tables by name rather than number.
// Messy — hardcoded table number in permissions
Permissions = tabledata 17 = RIMD; // table 17 = G/L Entry
// Clean — use object name
Permissions = tabledata "G/L Entry" = RIMD;
📖 Docs: Variable Naming — alguidelines.dev — Community guidelines for naming variables, parameters, and objects consistently across AL projects.
Break Long Procedures into Smaller Ones
Long, complex procedures that do multiple things are harder to read, review, and test. KB demonstrated using the “Extract to Procedure” code action in AL Code Actions (by David Feldhoff): select a block of code, invoke the action, name the new procedure descriptively, and the AL extension automatically moves the code and its required variables. The result is smaller procedures with names that make their intent clear — such as SetCustomerStyleBasedOnBlocked — which makes code reviews faster and bugs easier to locate.
Remove Unnecessary Code
KB showed a project he inherited with over 500 table extensions — each one doing nothing more than setting a caption that was identical to the original. An automated migration tool had generated them. He removed all 500. Similarly, event subscribers with no code body should be deleted rather than left commented out, and commented-out code blocks should not be checked into source control. If code is not needed, remove it.
Use Object Names, Not Numbers
In version 25, using table numbers in permission sets became a hard error that blocked upgrades. KB flagged a case where a customer’s environment was blocked on upgrade solely because of tabledata 17 in a permission set — a partner’s code that the customer could not easily fix because source download was disabled. Using object names instead of numbers is a discipline that prevents this category of upgrade failure entirely.
Follow Standard AL Patterns
BC ships with standard page patterns that developers should reuse rather than reinvent. For setup pages, Waldo’s CRS AL Language Extension provides a snippet (tSetupPage) that generates the correct pattern: a page with InsertIfEmpty-style logic on OnOpenPage and a corresponding GetOrInsert procedure on the setup table. Using these patterns means consultants and other developers can read the code without explanation — they recognise the pattern immediately. KB also warned against non-standard UI layouts (such as wrapping every field in a group) that seem harmless initially but cause maintenance problems when Microsoft changes the page framework.
Don’t Publish Unfinished Code to AppSource
KB showed an AppSource app — visible in production customer databases — where a code path contained the message “not ready yet, please contact us.” Code that reaches AppSource is installed by real customers. Incomplete features should be commented out or feature-flagged before submission, not left as runtime placeholders.
Recommended VS Code Extensions
KB listed the extensions his team uses for day-to-day AL development:
- Waldo’s CRS AL Language Extension — snippets, file naming conventions, and automated file renaming. All developers on KB’s team use the same configuration so file names and object naming are consistent across the project.
- AZ AL Dev Tools / AL Code Outline (by Andrzej Zwierzchowski) — sorting and removing unused variables, changing casing, and managing variable names. KB mentioned that he now relies on the tool to recall correct variable naming rather than memorising conventions.
- AL Code Actions (by David Feldhoff) — extracting procedures, extracting labels, and refactoring code inline without leaving VS Code.
- Code Spell Checker — KB’s team added a spell-check action to their pull request pipeline specifically to catch misspelled variable and procedure names before they reach the main branch.
- GitHub Copilot — KB uses Copilot primarily to generate tool tips, add comments, and suggest label names — small tasks where the productivity gain is most consistent.
📖 Docs: AL code actions — Microsoft Learn — Overview of built-in and extension-provided code actions available in the AL Language extension for VS Code.
General Principles
KB closed with the principles that cut across all the specific tips:
- Always test your code before submitting it — never send untested changes to a customer.
- Don’t copy code from the internet without understanding it; examples from blogs or videos may take shortcuts that are not appropriate for production code.
- Don’t take shortcuts under time pressure — a “quick fix” that stays in a production database for years costs far more than writing it correctly once.
- If you share code examples publicly, make sure they demonstrate good practice — developers copy what they see.
KB publishes AL development resources, including workbooks for beginners and advanced developers, at mynavblog.com.
This post was drafted with AI assistance based on the webinar transcript and video content.
