bcquality/microsoft/knowledge/events/choose-static-vs-manual-subscribers-deliberately.bad.al
Jesper Schulz-Wedde 54ddd8ecc2 Add events knowledge domain and review leaf skill
Add a new `events` knowledge domain covering AL events & subscribers,
wired into the AL review pipeline.

- 3 atomic articles (+ .good.al/.bad.al samples) under
  microsoft/knowledge/events/: the IsHandled override pattern, thin
  OnBefore/OnAfter integration-event publishers, and static vs manual
  subscribers.
- New leaf skill microsoft/skills/review/al-events-review.md sourcing the
  events domain.
- Wired into microsoft/skills/review/al-code-review.md (sub-skills + Source
  + description) and README.md (leaf-skill count + domain list).

AL event syntax verified against Microsoft Learn. Samples are
demonstration-only (not compiled by CI). Additive change; no contract change.

Part of #34.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-25 11:58:58 +02:00

53 lines
1.7 KiB
AL

// Demonstration-only AL. Not compiled by CI; illustrates the article.
codeunit 50232 "Order Event Pub Bad Sample"
{
procedure ReleaseOrder(OrderNo: Code[20])
begin
OnAfterReleaseOrder(OrderNo);
end;
[IntegrationEvent(false, false)]
local procedure OnAfterReleaseOrder(OrderNo: Code[20])
begin
end;
}
// Anti-pattern 1: a static subscriber drives an always-on side effect that
// should be scoped. Every release now emails the customer, in every session
// and every automated test, with no way to switch it off.
codeunit 50233 "Always Email Sub Bad Sample"
{
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Order Event Pub Bad Sample", 'OnAfterReleaseOrder', '', false, false)]
local procedure SendEmailOnRelease(OrderNo: Code[20])
begin
// Send a confirmation email unconditionally on every release.
end;
}
codeunit 50234 "Scoped Sub Bad Sample"
{
EventSubscriberInstance = Manual;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Order Event Pub Bad Sample", 'OnAfterReleaseOrder', '', false, false)]
local procedure OverrideRelease(OrderNo: Code[20])
begin
// Scoped behaviour intended only for a specific flow.
end;
}
// Anti-pattern 2: a manual subscriber is bound and never unbound. Because the
// instance is held on a SingleInstance global, the binding lives for the whole
// session, so later unrelated releases keep hitting the scoped subscriber.
codeunit 50235 "Leaky Binder Bad Sample"
{
SingleInstance = true;
var
Scoped: Codeunit "Scoped Sub Bad Sample";
procedure ActivateOverride()
begin
BindSubscription(Scoped);
// Missing: a matching UnbindSubscription(Scoped) when the scope ends.
end;
}