AL-udvikling i Business Central handler ikke kun om at levere ny funktionalitet hurtigt. Det handler mindst lige så meget om at bygge extensions, der kan opgraderes uden drama, kan forstås af andre udviklere og kan leve gennem nye versioner af platformen.
Mange løsninger ser fine ud i en sandkasse, men bliver dyre at vedligeholde, når app-identitet, dependencies, events og upgrade-kode ikke er tænkt ind fra start. Erfaringer fra faglige profiler og miljøer som yzhums.com, hougaard.com, waldo.be og vjeko.com peger på det samme: robuste løsninger respekterer standarden, udvider via klare grænser og holder arkitekturen løst koblet.
- Udvid standarden via events frem for at “hække” i standardobjekter
- Hold offentlige kontrakter stabile (events, interfaces, offentlige procedurer)
- Design for opgradering fra første release, ikke som en senere “fase 2”
App-identitet i app.json skal være stabil fra dag ét
Når et nyt AL-projekt oprettes, er app.json mere end metadata. Filen er kontrakten for installation, opgradering og samspil med andre apps: navn, publisher, version, id, dependencies og målplatform.
Den afgørende del er app-identiteten: app-id og versionshistorik bestemmer, om platformen ser en udgivelse som en opdatering eller som en helt ny app. Reglerne og konsekvenserne er beskrevet i artiklen om app identity for extensions.
Skifter app-id uden en bevidst plan, opstår der typisk et af disse problemer: dobbelt installation, manglende opgradering, manuelle datamigreringer eller oprydning i “gamle” data, som reelt stadig ligger i databasen.
- Behold samme app-id gennem hele produktets liv, medmindre der er et bevidst produktbrud
- Hæv versionsnummer ved hver release, så opgraderingsstien er tydelig
- Brug navn og publisher som branding, ikke som identitetsstyring
- Vælg et kort, stabilt app-navn og en konsekvent navnestandard på tværs af apps
Struktur og naming gør vedligeholdelse mindre risikabel
En opgraderbar løsning starter med en struktur, der afspejler ansvar. Når tabeller, pages, codeunits, permissions, enums, interfaces og tests blandes sammen i få store filer, bliver hver ændring farligere, og fejlretning tager længere tid.
En enkel, praktisk struktur er at lægge forretningslogik i service-/domænecodeunits, holde UI-tilpasninger adskilt og isolere integrationer i egne moduler. Det er et mønster, der går igen hos flere erfarne AL-profiler, fordi det skaber tydelige grænser og gør test enklere.
- Domænelogik i dedikerede codeunits (tænk “services” frem for “god objects”)
- UI (page extensions/actions) holdes tyndt og kalder domænelogik
- Integrationer samles i egne codeunits og afkobles via events/interfaces
Opsplitning i flere apps kan være en fordel, men kun når grænserne er reelle. For mange små apps giver flere dependencies, mere initiering og tungere opgraderinger. Derudover kan der ligge data tilbage efter afinstallation (orphaned extension data), som belaster drift og fejlsøgning over tid.
Naming er lavpraktisk, men afgørende. Navne skal hjælpe den næste udvikler (eller dig selv om 6 måneder) med at forstå, hvad der sker, uden at læse hele løsningen.
- Brug konsekvente præfikser og navnestandarder
- Giv event-subscribers navne, der fortæller hvilket event og hvilken intention de har
- Undgå generiske navne som
HandleEventogProcessuden kontekst
Event-baseret arkitektur giver løs kobling, hvis du designer til vilkårene
Business Central er bygget til udvidelser via events. Når du reagerer på publicerede events i stedet for at ændre standardkode direkte, stiger sandsynligheden for problemfri opgraderinger markant.
Et publisher-method er selve hooket og bør være simpelt. Retningslinjerne fremgår af publishing events. Tilsvarende gælder for subscribers: flere subscribers kan lytte på samme event, og rækkefølgen er ikke noget, du kan stole på. Det er tydeligt beskrevet i subscribing to events.
Konsekvensen er, at du ikke må designe logik, der kræver, at subscriber A altid kører før subscriber B. Hvis rækkefølge betyder noget, skal det løses i én samlet service eller via en eksplicit orkestrering, ikke via implicit event-rækkefølge.
- Brug standardevents først, før du opfinder egne hooks
- Hold subscribers små og flyt logik til testbare service-codeunits
- Antag ingen rækkefølge mellem subscribers
- Publicér egne events som bevidste kontrakter, ikke som “hurtige genveje”
Et godt mønster er: subscriber-metoden er en tynd indgang, og al forretningslogik ligger i en codeunit, der kan testes og genbruges. Det reducerer kompleksitet og gør fejlsøgning mere forudsigelig.
Dependencies skal minimeres, og versionering skal være konsekvent
Dependencies virker ofte harmløse i starten, men bliver en af de hyppigste årsager til fejl i build, installation og opgradering. Hver dependency er en binding, der skal holde gennem flere releases.
Hvis en app kun bruger én enum eller én hjælpefunktion fra en anden app, er det et signal om, at snitfladen kan være forkert. Overvej events, interfaces eller flytning af fælles logik til et bevidst “shared” modul.
En praktisk opdeling, som ofte giver ro i arkitekturen, er at skelne mellem:
- Kerneapps med data- og procesregler
- Integrationsapps, der taler med eksterne systemer
- Præsentationsapps med UI-tilpasninger
Når disse lag blandes, bliver opgraderinger tunge og fejl bliver sværere at isolere.
- Gennemgå hver dependency og skriv begrundelsen ned i repo’et (kort, men konkret)
- Behandl offentlige flader som API’er: ændringer kræver versioneringsdisciplin
- Undgå at gøre interne hjælpeprocedurer offentlige “for en sikkerheds skyld”
Jo mere en app genbruges, desto mere skal dens offentlige flade behandles som et API.
Performance handler både om kode og om platformens drift
På kodeniveau gælder de klassiske AL-principper stadig: undgå unødige databasekald, indlæs kun nødvendige felter, og vær varsom med tunge beregninger i UI-triggere. Men performance i Business Central handler samtidig om platformens drift: antallet af installerede apps, opgraderingsarbejde, initiering og data, der bliver liggende efter afinstallation.
Det betyder, at en “ren” arkitektur ofte er den bedste performance-optimering, fordi den reducerer støj, dependencies og sideeffekter.
- Brug målrettet dataindlæsning (
SetLoadFields) hvor det giver mening - Flyt tung logik væk fra UI og hyppige events
- Undgå synkrone eksterne kald i kritiske brugerflows
- Ryd op i udgåede apps og efterladt data som en del af drift og governance
Opgraderbarhed kræver planlagte upgrade-triggers og validering
Opgraderinger bliver dyre, når de håndteres sent. Hvis du ændrer datamodel, udfaser felter eller indfører nye strukturer, skal upgrade-kode skrives sammen med ændringen.
Platformen stiller upgrade-triggers til rådighed i systemets upgrade-codeunits, herunder OnUpgradePerDatabase og OnUpgradePerCompany. De officielle triggers og deres formål er beskrevet i artiklen om upgrade-triggers. Pointen er enkel: database-ændringer og company-specifikke ændringer skal behandles forskelligt.
Validering bliver ofte sprunget over, men er det, der afgør, om en opgradering reelt er sikker. Når datakonsistens er kritisk, bør validering være en fast del af opgraderingsforløbet.
- Planlæg udfasning: marker gamle felter/strukturer og definér en overgangsperiode
- Flyt data i dedikeret upgrade-kodeunits, ikke i tilfældige jobkørsler
- Validér resultatet systematisk efter migrering
- Fjern gamle strukturer i en senere release, når overgangsperioden er afsluttet
Egen event-kontrakt: design den som en aftale, ikke som en detalje
Når standardevents ikke rækker, kan egne publishers være det rigtige. Her skal du tænke som API-designer: hvilke parametre er stabile, hvad er fremtidssikret, og hvad kan andre apps forvente i næste version?
For brede signatures bliver hurtigt svære at ændre, og for smalle signatures bliver ubrugelige, hvilket skaber pres for breaking changes. Mange teams får bedre resultater ved at lade interne hooks modne, før de gøres til officielle kontrakter mellem apps.
- Navngiv events efter forretningsøjeblikket (
OnAfterCreateLedgerEntry) frem for intern implementering - Begræns parametre til det, der er stabilt og relevant
- Dokumentér hensigten i en kort kommentar, så andre kan bruge eventet korrekt
Test, review og governance holder kvaliteten stabil over tid
Selv god kode bliver sårbar uden faste arbejdsgange. Opgraderbarhed kommer fra disciplin: review, versionsstyring, dependency-kontrol, test og en releaseproces, der tænker migrering med.
En enkel governance-model behøver ikke være tung, men den skal være konsekvent. Det er et fokuspunkt, som flere erfarne AL-miljøer fremhæver: teknisk gæld opstår sjældent fra én stor fejl, men fra mange små kompromiser, der aldrig bliver rettet.
- Godkend nye dependencies eksplicit
- Lås praksis for app-id, versionering og naming
- Behandl offentlige procedurer/events som kontrakter
- Test upgrade-kode på realistiske data, ikke kun demo-selskaber
Et review kan med fordel køre efter en fast tjekliste:
- Er standardevents udnyttet før der er lavet nye udvidelsespunkter?
- Er subscriber-logik lille og flyttet til testbare codeunits?
- Er
app.json, versionsnummer og dependencies konsistente? - Er dataopgradering og validering tænkt ind i ændringen?
- Kan løsningen fjernes eller ændres senere uden at efterlade teknisk affald?
AL-udvikling i Business Central fungerer bedst, når det behandles som produktarkitektur og ikke kun som kodeleverance. Når du styrer identitet, struktur, events, dependencies, performance og upgrade-triggers bevidst, får du extensions, der er lettere at læse, lettere at opdatere og markant billigere at holde kørende gennem næste release.
