Add interfaces knowledge domain and review leaf skill (#42)

Adds the interfaces knowledge domain covering AL interfaces and enum-with-implementation: three atomic articles with good/bad AL samples, a new al-interfaces-review leaf skill, and additive wiring into al-code-review and the README. Purely additive; no contract change.

Part of #34.

Co-authored-by: Jesper Schulz-Wedde <jesper.schulzwedde@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Jesper Schulz-Wedde 2026-06-25 12:20:56 +02:00 committed by GitHub
parent 45c2b2f5ec
commit 23d5478ac6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 458 additions and 2 deletions

View file

@ -0,0 +1,26 @@
---
bc-version: [16..]
domain: interfaces
keywords: [interface, dependency-injection, testability, test-double, codeunit, polymorphism, mocking]
technologies: [al]
countries: [w1]
application-area: [all]
---
# Assign a codeunit to an interface variable for injectable, testable dependencies
## Description
An interface variable can hold any codeunit that `implements` the interface, assigned directly — no enum is required. That is the lever for dependency injection in AL: a consumer depends on the interface, production code injects the real codeunit, and a test injects a lightweight double that returns predictable values. A consumer that instead `var`-declares a concrete `Codeunit` type hardwires the dependency, so a test is forced to exercise the real logic — external calls, posting, and all. Interfaces arrived in Business Central 2020 release wave 1; LLMs still default to concrete codeunit variables and miss the seam that makes code testable.
## Best Practice
Declare the dependency as an `Interface` variable on the consumer and supply the implementation from outside — typically setter injection through a procedure that takes an `Interface` parameter, or a parameter on the entry method. Production passes the real implementation codeunit; a test passes a test-double codeunit that implements the same interface with deterministic behaviour. Because a codeunit assigns to an interface variable directly, no enum or factory is needed for the injectable case. The consumer's logic is then verifiable in isolation.
See sample: `assign-codeunit-to-interface-for-testability.good.al`.
## Anti Pattern
A consumer that declares its dependency as a concrete `Codeunit "..."` variable and calls it directly. The collaborator cannot be substituted, so a unit test either runs the production side effects or cannot cover the consumer at all. Detection signal: a `var` of type `Codeunit "<concrete impl>"` used for a collaborator that has — or could have — an interface, especially one that performs I/O, posting, or external calls. Extract an interface, depend on the interface variable, and inject the implementation.
See sample: `assign-codeunit-to-interface-for-testability.bad.al`.