Is your AL code robust or weak, what kind of developer are you with Business Central?

This week’s video is a homage to all the great content and work Microsoft put into the documentation of Business Central. Historically, the documentation available to us has been sparse, but that’s no longer the case. In this video I check a new page on defensive development with AL. Check it out:


In this video, Erik explores a valuable Microsoft Learn article about failure modeling and robust coding practices for Business Central AL development. Rather than diving into code samples, this session focuses on the mindset and principles that separate robust AL code from fragile code — and challenges you to think about which kind of developer you are.

The AL Runtime Safety Net — And Why It’s Not Enough

Erik begins by highlighting a key statement from the Microsoft Learn article on failure modeling and robust coding practices:

“While it’s true that the AL runtime makes sure that the session never crashes…”

This means that no matter what you do in AL, you cannot crash the Business Central server. If you manage to, Microsoft would love to hear about it so they can fix it. Your session might error out, but the server itself remains stable by design.

However — and this is the critical point — just because the platform will eventually save you doesn’t mean you can ignore safe coding practices. You still need to think about what can go wrong, how to handle failures, and how to write code that degrades gracefully rather than blowing up in your users’ faces.

Failure Modeling: Thinking About What Can Go Wrong

The article introduces the concept of a failure model: a description of the potential ways a component can fail, along with the cause and effect of those failures. A component can be:

  • Internal — a codeunit, method, API, or report
  • External — an API, web service, or integration point outside Business Central

For each component, you should consider:

  1. What kinds of failures can occur?
  2. What are the causes of those failures?
  3. What is the effect when a failure happens?
  4. What is the probability of the failure occurring?

A simple field on a page is unlikely to fail in dramatic ways, but a codeunit that talks to external web services, prints documents, and orchestrates complex workflows has many more failure points. The article even suggests building a spreadsheet to map out components, their failure modes, causes, effects, and probabilities. Erik notes he wouldn’t do this for an entire application, but the exercise is valuable for critical components.

The Six Principles of Robust AL Code

The article lays out six principles for writing robust code. Erik emphasizes that these aren’t revolutionary inventions from the Business Central product group — they’re established industry practices — but they’re extremely relevant to AL development.

1. Don’t Trust Any Code You Didn’t Write

If you’re calling someone else’s code and the contract says it returns a number between 1 and 100, do you trust that it will never return -200 or -2,000,000,000? Maybe. Probably not. Always validate return values.

Practical guidance from the article includes:

  • For methods that implement a Boolean return code, always check the result with an if statement
  • For methods that return results via output parameters, verify the result is sound
  • For AL methods without a Boolean return code, consider using try methods (though Erik notes this is complicated due to database operations)
  • Let the compiler help you — instead of specifying magic numbers like 4884 for object IDs, use strongly-typed references like Codeunit::"Job Queue Dispatcher"
  • When working with HTTP responses, don’t just check for status code 200 — use the IsSuccessStatusCode method, which correctly handles all 2xx status codes (200, 201, etc.)

2. Don’t Trust Consumers of Your Code

The flip side of principle one. If your function takes an integer parameter that should be between 1 and 100, do you trust that callers will never pass -200? You shouldn’t. Validate your inputs just as rigorously as you validate your outputs.

3. Don’t Trust the Environment Your Code Runs In

This is particularly relevant in the Business Central ecosystem where everything is an app. You don’t know what other apps are installed on your customers’ systems, which means:

  • You don’t know what event subscribers exist. If you subscribe to an event, another app might also be subscribed to it, manipulating data in ways you don’t expect.
  • Data assumptions can break. Erik gives the example of Binary Stream’s Multi-Entity Management app, which turns Dimension One into an entity dimension, fundamentally changing how data is structured. If that app is installed, your assumptions about data layout may be completely wrong.
  • Performance is unpredictable. Something that normally takes milliseconds might suddenly take 5 seconds on a particular environment. If timing is essential to your logic, you need to account for this.
  • Permissions vary. You cannot know how a customer sets up permissions, so if your code needs access to specific data, you may need to explicitly declare permissions using InherentPermissions or similar mechanisms.

Erik shares an important personal principle: whenever he subscribes to an event, he tries never to let the code throw an error — unless it’s an explicit, intentional error to stop a process. That means no unprotected Get or Find calls inside event subscribers, because you’re operating in a potentially hostile multi-app environment where another extension may have changed the data you’re expecting.

4. Offer Graceful Degradation

When something goes wrong, what does your code do? Does it just throw another error and bail out? Or does it handle the failure intelligently — calling an alternative, working around the problem, or at least giving the user meaningful information about what happened?

Robust code anticipates failures and provides fallback behavior rather than simply cascading errors upward.

5. Hide Your Internal Data Structures

When creating an app, you decide what’s public, internal, or local:

  • Local — accessible only within the object; you can change it freely
  • Internal — accessible throughout your extension, but not to other extensions
  • Public — accessible to everything (the default if you don’t specify an access modifier)

Erik admits that some of his earlier AppSource apps have internal functions that are public because they were created before these practices were well-established. Due to the upgrade compatibility requirements (you can’t break existing consumers by changing a public function to internal), those functions remain public. But for anything new, he always asks: “Who is the consumer of this?” If the consumer isn’t an external party, it should be internal or local.

6. Assume Murphy’s Law

“If anything can go wrong, it will go wrong.” And as Erik adds: Murphy was an optimist.

Every developer has experienced the stages of grief when a customer reports an issue: “This can never happen” → investigating → “How did this ever work?!” If you write code, Murphy is your co-pilot.

Telemetry: Murphy’s Best Friend

Erik highlights that telemetry is the essential companion to Murphy’s Law. The challenge with telemetry is finding the needle in the haystack, so Erik has adopted a practice of using increasingly specific LogMessage calls in his apps.

He logs very specific scenarios — especially things that should never happen — so that when the improbable does occur, he has the data to understand it. A prime example is his SharePoint Connector: when SharePoint returns an unexpected error, he logs the full context including what was requested, because Microsoft’s built-in HTTP logging only shows something like “Error 400” without the response body or request content.

This targeted telemetry approach lets you proactively monitor for edge cases rather than waiting for customer complaints.

The Sample Project

The video’s companion project is a simple AL extension skeleton, demonstrating the basic structure of a Business Central app:

namespace DefaultPublisher.RobustCode;

using Microsoft.Sales.Customer;

pageextension 50100 CustomerListExt extends "Customer List"
{
    trigger OnOpenPage();
    begin
        Message('App published: Hello world');
    end;
}

While this is a minimal “Hello World” example, the principles discussed apply to every piece of AL code you write — from simple page extensions to complex integration codeunits.

Summary

The key takeaway from this video is that the AL platform’s safety net is not a substitute for writing robust code. Here are the six principles to keep in mind:

  1. Don’t trust code you didn’t write — validate all return values and responses
  2. Don’t trust consumers of your code — validate all inputs
  3. Don’t trust your environment — other apps, permissions, and performance are all unpredictable
  4. Offer graceful degradation — handle failures intelligently instead of cascading errors
  5. Hide your internals — use appropriate access modifiers (local, internal, public)
  6. Assume Murphy’s Law — and use telemetry to catch the improbable when it inevitably happens

Whether you’re building AppSource apps or customer-specific extensions, these principles will help you write AL code that’s resilient, maintainable, and ready for the unpredictable reality of multi-app Business Central environments.