AL Coding Standards
This page documents the AL coding patterns and conventions used across all Bestway BC extensions. These are the positive patterns — the "how we do things here." For anti-patterns and what to avoid, see the Contribution Guidelines.
Extension Configuration
Required app.json Fields
Every extension's app.json must include:
| Field | Details |
|---|---|
name | Short, descriptive extension name |
publisher | Publisher organization |
version | Four-part version (major.minor.patch.build) — must match all documentation |
idRanges | Reserved, non-overlapping ID ranges for all objects |
dependencies | Complete list of extension dependencies with correct app IDs and versions |
features | Must include "NoImplicitWith" |
applicationInsightsConnectionString | Bestway's shared Azure Application Insights connection string |
resourceExposurePolicy | allowDebugging, allowDownloadingSource, and includeSourceInSymbolFile all set to true |
Object ID Ranges
Each extension has a reserved, non-overlapping range of IDs defined in idRanges. All new objects — tables, pages, codeunits, enums, permission sets — must use IDs within the assigned range. Never reuse IDs across extensions. If you are running low on available IDs, request an expanded range before proceeding.
Check the idRanges in the extension's app.json and its README for the next available ID.
Telemetry
All extensions must include extension-level telemetry via applicationInsightsConnectionString in app.json. This sends extension-emitted events to Bestway's centralized Azure Application Insights resource. The connection string will be provided at the start of the engagement. This is not optional.
File Organization
Folder Structure
Extensions organize AL objects by type in dedicated subfolders under src/:
ExtensionFolder/
├── docs/
│ ├── CHANGELOG.md
│ └── CHANGE-v{version}.md
├── src/
│ ├── Codeunit/
│ ├── Table/
│ ├── TableExt/
│ ├── Page/
│ ├── PageExt/
│ ├── Enum/
│ ├── EnumExt/
│ ├── PermissionSet/
│ ├── Report/
│ └── ReportExt/
├── app.json
└── README.md
Legacy extensions may use different conventions (lowercase pluralized folders, flat structures without
src/). The structure above applies to all new extensions and major refactors. When modifying an existing extension, follow the convention already established within that extension for consistency.
File Naming
Files follow the convention {Prefix}{ObjectName}.{ObjectType}.al:
PhoneIntegration.Codeunit.alNextivaConfig.Table.alNextivaSetupPage.Page.al
Namespace Declarations
Extensions targeting application: 27.0.0.0 or later should include namespace declarations (e.g., namespace BestwayUSA.bccsmapi;). Extensions targeting earlier versions may omit namespaces.
Naming Prefixes
- INVC prefix: Used on all BestwayUSA core custom objects and fields (originally from Innovia Consulting — e.g.,
INVCSerialNo.Table.al,INVCCustomerCard.PageExt.al) - Custom enums: Use the
INVCprefix for BestwayUSA enums (e.g.,INVCDocumentAttachmentType,INVCWarrantyType)
Architecture Patterns
Business Logic in Codeunits
Business logic belongs in codeunits, not page or report triggers. This is the primary architectural rule for testability.
Page triggers should call codeunit procedures. This pattern enables:
- Unit testing of the logic without a UI dependency
- Reuse of the same logic across multiple pages
- Cleaner separation of concerns
Example pattern — the CSM API extension extracts computed fields into a helper codeunit:
CSM API Helper (Codeunit 56104)
├── GetOrderStatus() → translates BC status codes to API-friendly strings
├── GetAttachmentUrl() → builds blob storage URLs
└── FormatPhoneNumber() → normalizes phone formats
CSM API pages call the helper rather than implementing logic directly.
Event Subscribers for Cross-Extension Integration
Event subscribers are the standard mechanism for cross-extension integration in this repo:
INVCGeneralEvents.Codeunit.al— defines integration eventsINVCSalesHandler.Codeunit.al— subscribes to sales-related events
When an extension needs to respond to events from another extension, implement an event subscriber rather than modifying the source extension.
Test Design
Test codeunits follow these conventions:
- Use the
[Test]attribute on each test procedure - Structure each test with Given / When / Then comment blocks
- Use
TestPagefor functional tests that verify UI behavior - Use
Library Assertfor assertions - Tests use BC's auto-rollback transaction model — test data is cleaned up automatically
- Run tests via the BC Test Tool (page 130401)
Version Numbering
Use four-part versioning: major.minor.patch.build.
The version in app.json must match the version referenced in all documentation (CHANGELOG, CHANGE documents, test plans). Bump the version for every deliverable — there should never be a delivery without a corresponding version increment.