Ein Deep-Dive für erfahrene Entwickler in die moderne App-Architektur, Design Patterns und die Fallstricke der Cloud-Umgebung.
Podcast auf toknow hörenHerzlich willkommen bei toknow und zu unserer neuen Podcast-Reihe über die professionelle AL-Entwicklung für Microsoft Dynamics 365 Business Central. Wenn wir heute über Business Central sprechen, dann reden wir nicht mehr über das klassische Navision oder die Zeiten, in denen wir einfach im Object Designer ein paar Zeilen Code geändert haben. Wir befinden uns in einer Ära des modernen Software-Engineerings, in der Cloud-Readiness, Updatefähigkeit und eine saubere Architektur keine netten Zusatzoptionen mehr sind, sondern die absolute Grundvoraussetzung für den Erfolg unserer Projekte. In den nächsten zwölf Kapiteln nehmen wir euch mit auf eine Reise durch das gesamte Ökosystem der modernen AL-Entwicklung. Wir richten uns dabei gezielt an erfahrene Entwickler, die den Umstieg von C/AL auf AL vielleicht schon hinter sich haben, aber nun den nächsten Schritt gehen wollen, um ihre Lösungen auf ein echtes Enterprise-Niveau zu heben. In diesem ersten Kapitel möchte ich euch einen Überblick darüber geben, was euch in dieser Serie erwartet und warum es heute wichtiger denn je ist, über Best Practices und bewährte Entwurfsmuster nachzudenken. Wir beginnen in der nächsten Folge mit dem fundamentalen Paradigmenwechsel: Der Bewegung weg von der Modifikation hin zur Extension. Das klingt erst einmal trivial, erfordert aber ein völlig neues Mindset, besonders wenn es um das Event-basierte Modell geht. Wir schauen uns an, wie man Abhängigkeiten so strukturiert, dass das System auch nach dem zehnten Microsoft-Update noch stabil läuft. Danach steigen wir tief in die Werkzeugkiste der Architektur ein. Wir sprechen über Workspace-Strukturen und modulare App-Architekturen, um große Monolithen in wartbare Einheiten zu zerlegen. Ein besonderes Highlight wird unsere Analyse der AL Design Patterns sein. Wir besprechen, wie man Singleton- und Facade-Patterns nutzt, um Logik sauber von der Benutzeroberfläche zu trennen. Auch das Strategy Pattern in Kombination mit Extensible Enums darf nicht fehlen, denn das ist der Schlüssel zu hochflexiblen Branchenlösungen. Ein kritischer Punkt in jeder Cloud-Umgebung ist die Performance. Deshalb widmen wir uns ausführlich den SQL-Queries, dem Locking-Verhalten und dem effizienten Daten-Handling. Ihr erfahrt, wie ihr Deadlocks vermeidet und warum JIT-Loading in Business Central so wichtig ist. Wir werfen zudem einen Blick auf modernes UI-Design, die Integration von APIs und warum ein API-First-Ansatz heute der Standard sein sollte. Ein Thema, das oft stiefmütterlich behandelt wird, dem wir aber viel Platz einräumen, ist das Automated Testing. Ohne das Test Toolkit ist eine kontinuierliche Bereitstellung in der Cloud kaum noch verantwortungsvoll machbar. Wir zeigen euch zudem, wie ihr Telemetrie und Azure Application Insights nutzt, um Probleme zu finden, bevor der Kunde überhaupt zum Hörer greift. Zum Abschluss schauen wir uns die großen Don’ts an, also die Anti-Patterns, die man unbedingt vermeiden sollte, und wagen einen Ausblick auf die Zukunft der Sprache AL. Es geht uns in diesem Podcast darum, euch das Rüstzeug an die Hand zu geben, um nicht nur Code zu schreiben, der funktioniert, sondern Software zu bauen, die nachhaltig, performant und zukunftssicher ist. Schnallt euch an, es gibt viel zu besprechen. Willkommen in der Welt der professionellen AL-Entwicklung.
Wir alle kennen noch die Zeiten, in denen wir den Object Designer geöffnet, die Page oder das Table-Objekt direkt im Standard modifiziert und unsere Logik einfach mitten in den bestehenden Code geschrieben haben. In der alten C/AL-Welt war das völlig normal. Der Standard-Code war wie ein großer Steinbruch, aus dem wir uns bedient haben und in dem wir fast schon chirurgisch eingegriffen haben, um die Anforderungen unserer Kunden umzusetzen. Doch wenn wir heute über professionelle AL-Entwicklung in der Cloud sprechen, müssen wir uns eingestehen, dass dieses Mindset in einer modernen Softwarearchitektur nicht nur veraltet, sondern schlichtweg gefährlich ist. Der Paradigmenwechsel von der Modification zur Extension ist weit mehr als nur ein Wechsel der Programmiersprache oder der Entwicklungsumgebung. Es ist eine fundamentale Transformation unserer Arbeitsweise. In der On-Premise-Welt hatten wir die volle Kontrolle über den Zeitpunkt von Updates. Wenn eine Anpassung beim Upgrade Probleme bereitete, haben wir das Upgrade eben verschoben oder den Code mühsam angepasst. In der Cloud-Welt von Business Central Online ist das vorbei. Microsoft rollt Updates kontinuierlich aus, und Ihre App muss funktionieren, egal was im Unterbau passiert. Wer versucht, das alte C/AL-Denken in AL fortzuführen, indem er zum Beispiel massiv mit Beinahe-Kopien von Standard-Objekten arbeitet oder versucht, den Standard durch unsaubere Workarounds zu überlisten, baut sich eine technische Sackgasse. Das Problem ist die Kopplung. Früher war unser Code fest mit dem Kernsystem verschweißt. Heute müssen wir lernen, in Schichten zu denken. Wir sind nicht mehr der Chirurg, der am offenen Herzen des Standards operiert, sondern wir sind Beobachter, die auf bestimmte Ereignisse reagieren. Hier kommt das Event-basierte Modell ins Spiel. Es ist das Herzstück der modernen AL-Entwicklung. Anstatt den Code in eine bestehende Prozedur hineinzuschreiben, abonnieren wir ein Event. Wir warten darauf, dass die Basis-App uns ein Signal gibt, nach dem Motto: Ich bin gerade dabei, einen Verkaufsbeleg zu buchen, möchte jemand noch etwas hinzufügen? Diese lose Kopplung ist der einzige Weg, um die Update-Fähigkeit zu garantieren. Aber dieser Wechsel erfordert Disziplin. Es bedeutet, dass wir nicht mehr einfach irgendwo eine Variable global definieren können, auf die wir von überall zugreifen. Wir müssen lernen, mit den Parametern zu arbeiten, die uns die Publisher zur Verfügung stellen. Und wenn ein Event im Standard fehlt? Dann kopieren wir nicht den Code, sondern wir fordern bei Microsoft ein neues Event an oder suchen nach architektonischen Alternativen wie dem Handling über temporäre Tabellen oder Puffer-Strukturen. Das Mindset muss sich weg von der reinen Funktionserfüllung hin zur langfristigen Wartbarkeit verschieben. Eine gute Extension ist wie ein Plug-in für ein Betriebssystem: Sie fügt sich nahtlos ein, lässt sich aber jederzeit entfernen, ohne dass das Gesamtsystem kollabiert. Wenn wir diesen Paradigmenwechsel verinnerlichen, gewinnen wir etwas Entscheidendes: Geschwindigkeit. Wir müssen uns nicht mehr bei jedem Minor-Update vor einem Systemstillstand fürchten. Wir entwickeln Lösungen, die skalieren und die bereit sind für eine Welt, in der Software nicht mehr fertig ist, sondern sich permanent weiterentwickelt. Das ist die Basis für alles, was wir in den nächsten Kapiteln besprechen werden. Denn nur wer versteht, warum wir nicht mehr im Standard graben dürfen, kann die Vorteile modularer App-Architekturen wirklich ausschöpfen.
Nachdem wir uns im letzten Kapitel angeschaut haben, warum das alte C-AL-Mindset in der Cloud-Welt so riskant ist, widmen wir uns jetzt dem Fundament eurer Projekte: der Workspace-Struktur und einer modularen App-Architektur. Wer aus der Welt der monolithischen Anpassungen kommt, ist es gewohnt, dass im Grunde alles mit allem verknüpft ist. In VS Code und der AL-Entwicklung führt dieser Ansatz jedoch schnell in eine Sackgasse. Wenn wir von moderner Architektur in Business Central sprechen, dann geht es vor allem darum, wie wir große, komplexe Lösungen so zerlegen, dass sie wartbar bleiben, schnell kompilieren und die Abhängigkeiten uns nicht in den Wahnsinn treiben. Ein entscheidendes Werkzeug dafür sind die Multi-Root Workspaces in VS Code. Anstatt eine riesige App zu bauen, die alles von der Finanzbuchhaltung bis zur spezialisierten Logistiklösung abdeckt, sollten wir in Schichten und Modulen denken. Ein bewährtes Modell ist die Aufteilung in Layer. Ganz unten steht oft eine Basis-App, ein Core-Modul, das allgemeine Hilfsfunktionen, globale Enums oder grundlegende Tabellenerweiterungen enthält, die in fast jedem Projekt benötigt werden. Darüber legen wir die funktionalen Module. Diese sollten so weit wie möglich voneinander entkoppelt sein. Wenn ein Feature für das Warehouse-Management nichts mit der Reisekostenabrechnung zu tun hat, dann haben diese beiden Dinge in derselben App nichts verloren. Warum ist das so wichtig? Zum einen wegen der Performance der Entwicklungsumgebung. Je größer eine App wird, desto länger dauert das Kompilieren und das Publizieren. Zum anderen geht es um das Risikomanagement bei Updates. Wenn Microsoft ein Breaking Change in einem Bereich einführt, ist bei einer modularen Struktur nur ein kleiner Teil eurer Lösung betroffen. Ihr könnt gezielter testen und schneller reagieren. Ein großer Schmerzpunkt für viele erfahrene Entwickler ist die sogenannte Dependency-Hell. Wenn App A von App B abhängt, B von C und C plötzlich wieder von A, haben wir einen zirkulären Bezug, den AL nicht erlaubt. Ein sauberes Layer-Modell verhindert das von vornherein. Man definiert klare Hierarchien: Informationen fließen immer nur von oben nach unten, nie zurück. Um diese Unabhängigkeit zu erreichen, nutzen wir oft das Prinzip der Separation of Concerns. Das bedeutet auch, dass wir Geschäftslogik strikt von der Benutzeroberfläche trennen. Eine Codeunit sollte niemals direkt davon abhängen, ob sie gerade von einer Page oder von einer API aufgerufen wird. Wenn wir unsere App-Architektur modular aufbauen, nutzen wir idealerweise Fassaden-Codeunits als öffentliche Schnittstellen für ein Modul. Das erlaubt uns, die interne Logik eines Moduls komplett zu verändern, solange die Fassade stabil bleibt. Das minimiert die Auswirkungen auf andere Apps im Workspace. Am Ende des Tages führt eine modulare Architektur dazu, dass eure Teams parallel an verschiedenen Bereichen arbeiten können, ohne sich ständig gegenseitig in die Quere zu kommen. Es ist der Weg weg vom unübersichtlichen Monolithen hin zu einer flexiblen, Cloud-fähigen Systemlandschaft, die auch nach vielen Microsoft-Updates noch stabil steht. Im nächsten Kapitel werden wir sehen, wie wir dieses strukturierte Fundament nutzen, um mit spezifischen AL Design Patterns noch tiefer in die saubere Programmierung einzusteigen.
Nachdem wir uns im letzten Kapitel mit der groben Struktur unserer Projekte beschäftigt haben, gehen wir heute eine Ebene tiefer in den Maschinenraum der AL-Entwicklung. Es geht darum, wie wir unsere Logik innerhalb der Objekte so organisieren, dass sie nicht nur heute funktioniert, sondern auch in drei Jahren noch wartbar und vor allem testbar ist. In der Welt der Softwarearchitektur nutzen wir dafür Design Patterns, also bewährte Lösungsmuster für wiederkehrende Probleme. Für Business Central sind zwei Muster dabei absolut essenziell: das Singleton und das Facade Pattern. Fangen wir mit dem Singleton an. In AL implementieren wir dieses Muster über Codeunits, bei denen die Eigenschaft SingleInstance auf true gesetzt ist. Das bedeutet, dass die Instanz dieser Codeunit über die gesamte Client-Session hinweg bestehen bleibt, sobald sie einmal aufgerufen wurde. Warum ist das so wertvoll? Viele Entwickler unterschätzen, wie oft sie in ihrem Code Setup-Tabellen oder komplexe Konfigurationen abfragen. Jeder dieser Zugriffe geht potenziell auf die Performance, selbst wenn das SQL-Caching von Business Central im Hintergrund arbeitet. Ein Singleton dient hier als intelligenter Zwischenspeicher im Arbeitsspeicher. Ihr ladet die Konfiguration einmal beim ersten Zugriff und behaltet sie für den Rest der Sitzung vor. Aber es geht um mehr als nur Performance. Ein Singleton erlaubt es uns, einen konsistenten Status innerhalb einer Session zu verwalten, ohne auf temporäre Tabellen oder komplizierte Parameterübergaben durch zig Funktionen angewiesen zu sein. Es schafft einen zentralen Ort für den Zustand eurer App während der Laufzeit. Das bringt uns direkt zum Facade Pattern, das vielleicht wichtigste Werkzeug für sauberen Code in Business Central überhaupt. Die Fassade ist im Grunde der Türsteher eurer Geschäftslogik. Ein weit verbreitetes Problem ist es, Logik direkt in die Trigger von Pages zu schreiben, sei es im OnValidate eines Feldes oder im OnAction eines Buttons. Das Problem dabei ist offensichtlich: Sobald ihr dieselbe Logik für einen API-Aufruf, eine Job Queue oder eine externe Integration benötigt, fängt das große Kopieren von Code an. Die Facade löst dieses Problem radikal. Ihr erstellt eine Codeunit, die als einzige öffentliche Schnittstelle nach außen fungiert. Die Page selbst enthält keine Logik mehr, sie ruft nur noch die Methoden der Fassade auf. Das macht euren Code modular und vor allem unabhängig von der Benutzeroberfläche. Wenn Microsoft etwas an der UI-Struktur ändert, bleibt eure eigentliche Geschäftslogik davon völlig unberührt. Die konsequente Kombination dieser beiden Muster führt zu einer Architektur, die wir Separation of Concerns nennen, also die Trennung von Zuständigkeiten. Wir trennen die Zuständigkeit für die Datenhaltung durch das Singleton von der Zuständigkeit für die Prozesssteuerung durch die Facade. Wenn ihr eine neue Funktion entwickelt, solltet ihr euch immer fragen: Gehört das wirklich auf die Page? Oder sollte die Page nur der Auslöser sein, der eine klar definierte Methode in einer Facade-Codeunit anspricht? Dieser Ansatz ist übrigens die absolute Grundvoraussetzung für effektive automatisierte Tests. Denn eine Facade lässt sich wunderbar isoliert testen, während eine simulierte Page-Interaktion im Test-Code immer komplex und fehleranfällig ist. Im nächsten Schritt werden wir diese Basis nutzen, um zu verstehen, wie wir mit Enums und dem Strategy Pattern sogar noch einen Schritt weiter gehen können, um unsere Logik für Erweiterungen Dritter flexibel zu öffnen.
In den letzten Kapiteln haben wir uns intensiv mit der Struktur unserer Apps und grundlegenden Design Patterns beschäftigt. Jetzt wird es Zeit, tiefer in die Mechanik der Business-Logik einzutauchen, denn hier entscheidet sich oft, wie wartbar eine Lösung über Jahre hinweg bleibt. Ein klassisches Problem in der alten Welt von C/AL waren die endlosen Case-Statements. Ihr erinnert euch sicher an Funktionen, die hunderte Zeilen lang waren, weil für jede Versandart, jede Preisberechnung oder jede länderspezifische Logik eine neue Abzweigung eingebaut wurde. In der Cloud-Welt und mit dem modernen AL-Ansatz ist das nicht nur unschön, sondern ein echtes Hindernis für die Erweiterbarkeit und die Stabilität eurer Updates. Hier kommt das Strategy Pattern ins Spiel, das in Business Central durch die Kombination von Interfaces und Extensible Enums seine volle Kraft entfaltet. Die Grundidee dahinter ist simpel: Anstatt dass eine zentrale Funktion selbst entscheidet, wie eine Aufgabe im Detail gelöst wird, delegiert sie diese Entscheidung an ein austauschbares Objekt. Das Ziel ist das sogenannte Open-Closed-Prinzip. Unser Code soll offen für Erweiterungen sein, aber geschlossen für Modifikationen. Wenn wir also eine neue Logik hinzufügen wollen, möchten wir keinen bestehenden Code anfassen oder bestehende Funktionen umbauen müssen, sondern einfach ein neues Modul anflanschen. Der technische Enabler für dieses Muster sind die Enums. Früher waren Optionsfelder starr, aber mit Extensible Enums haben wir die Möglichkeit geschaffen, dass andere Extensions neue Werte hinzufügen können. Der eigentliche Durchbruch für die Architektur kam jedoch mit der Einführung von Interfaces in AL. Ein Interface definiert quasi den Vertrag: Welche Methoden müssen vorhanden sein? Nehmen wir das Beispiel einer komplexen Versandkostenberechnung. Wir definieren ein Interface namens I-Shipping-Calculator mit einer Methode zur Berechnung des Preises. Jetzt wird es spannend: In der Enum-Definition können wir jedem Wert eine spezifische Codeunit zuweisen, die genau dieses Interface implementiert. Das Enum-Attribut Implementations erlaubt es uns, den Enum-Wert direkt mit der Logik zu verknüpfen. Im Hauptcode passiert dann etwas fast schon Magisches. Wir müssen nicht mehr mit Case-Statements prüfen, welcher Wert ausgewählt wurde. Wir weisen den Enum-Wert einfach einer Variablen vom Typ des Interfaces zu. Business Central weiß im Hintergrund sofort, welche Codeunit aufgerufen werden muss. Der Clou dabei ist die Erweiterbarkeit für Dritte. Wenn ihr eine Basislösung baut und ein anderer Entwickler eine völlig neue Versandmethode hinzufügen möchte, muss er euren Core-Code nicht einmal anfassen. Er erstellt einfach eine Enum-Extension, fügt seinen Wert hinzu und verweist auf seine eigene Codeunit. Eure Logik erkennt den neuen Wert automatisch und nutzt die korrekte Berechnung, ohne dass ihr jemals davon gehört habt. Das ist saubere Entkopplung in Perfektion. Dieses Muster reduziert die Komplexität eurer Apps massiv. Ihr habt keine gigantischen Codeunits mehr, sondern viele kleine, spezialisierte Einheiten, die leicht zu verstehen und vor allem isoliert zu testen sind. Es verhindert auch, dass ihr euch in komplizierten Event-Subscriber-Ketten verliert, nur um ein bisschen Logik zu verbiegen. Wenn ihr das Strategy Pattern konsequent einsetzt, schafft ihr eine Architektur, die mit den Anforderungen wächst, ohne unter ihrem eigenen Gewicht zusammenzubrechen. Es ist der Weg weg vom monolithischen Denken hin zu einer echten, modularen Plattformstrategie. Im nächsten Kapitel schauen wir uns an, wie wir diese Logik performant auf die Datenbank bringen, damit eure flexiblen Lösungen auch bei großen Datenmengen in der Cloud nicht in die Knie gehen.
Nachdem wir uns in den letzten Kapiteln intensiv mit der Softwarearchitektur und den Design Patterns beschäftigt haben, kommen wir jetzt zu einem Thema, das in der Cloud-Welt oft über Erfolg oder Misserfolg eines Projekts entscheidet: Performance, speziell im Kontext von SQL-Abfragen und Locking. Wenn wir früher On-Premises entwickelt haben, konnten wir uns oft auf die schiere Hardware-Power verlassen oder im Notfall den SQL-Server manuell tunen. In der Business Central SaaS-Umgebung teilen wir uns die Ressourcen in einer Multi-Tenant-Architektur. Das bedeutet, wir müssen viel smarter mit der Datenbank kommunizieren, um sowohl die eigene App als auch die Umgebung stabil zu halten. Ein zentrales Stichwort hierbei ist das Just-In-Time-Loading, kurz JIT. Viele Entwickler sind es gewohnt, einfach eine Record-Variable zu definieren und mit einem FindSet die Daten zu laden. Aber unter der Haube macht das einen riesigen Unterschied für die SQL-Performance. Nutzt ihr SetLoadFields konsequent? Falls nicht, zieht Business Central standardmäßig alle Felder einer Tabelle in den Speicher, sobald auf ein Feld zugegriffen wird, das nicht im initialen Read enthalten war. Das erzeugt unnötigen Overhead und bläht die SQL-Abfragen massiv auf. Mit SetLoadFields sagen wir der Runtime explizit, welche Daten wir wirklich für unsere Logik brauchen. Das ist besonders bei Tabellen mit vielen Media-Feldern oder komplexen Erweiterungen ein echter Lebensretter für die Antwortzeiten. Denkt auch an die Art der Iteration. Ein FindSet ist nicht gleich ein FindSet. Die Entscheidung, ob wir den Parameter für das Update auf True oder False setzen, beeinflusst direkt, wie SQL die Zeilen sperrt. Werden Daten nur gelesen, sollte der Parameter immer auf False stehen, um die Parallelität nicht einzuschränken. Und wenn wir über große Datenmengen sprechen, sollten wir uns von der klassischen Record-Schleife verabschieden und öfter zu Query-Objekten greifen. Queries erzeugen auf SQL-Ebene deutlich effizientere Joins und reduzieren die Anzahl der Roundtrips zwischen dem Middle-Tier und der Datenbank dramatisch. Damit sind wir direkt beim Thema Locking und Deadlocks. In der Cloud ist das Transaktionsmanagement kritisch. Ein häufiger Fehler ist das zu frühe oder zu lange Sperren von Tabellen. Wenn ihr ein Lock setzt, zum Beispiel durch ein LockTable, sollte die verbleibende Transaktion so kurz wie nur möglich sein. Ein absolutes No-Go ist es, während einer offenen Schreibtransaktion langwierige externe Web-Service-Calls abzusetzen. Während eure App auf die Antwort einer API wartet, bleiben die SQL-Sperren bestehen und blockieren potenziell andere User oder Hintergrundprozesse. Das führt unweigerlich zu Timeouts und frustrierten Anwendern. Etabliert eine klare Strategie für den Tabellenzugriff. Deadlocks entstehen meistens dann, wenn verschiedene Prozesse in unterschiedlicher Reihenfolge auf dieselbe Menge an Tabellen zugreifen. Wenn Prozess A erst Tabelle Eins und dann Tabelle Zwei sperrt, während Prozess B genau die umgekehrte Reihenfolge wählt, haben wir die klassische Sackgasse. Ein einheitliches Zugriffsmuster ist hier die beste Verteidigung. Performance in AL ist also kein Zufallsprodukt, sondern das Ergebnis von bewussten Entscheidungen beim Datenzugriff und einem tiefen Verständnis dafür, wie der Business Central Server eure AL-Befehle in SQL-Statements übersetzt. Wer diese Prinzipien verinnerlicht, baut Anwendungen, die auch bei hohem Datenaufkommen in der Cloud performant bleiben. Im nächsten Kapitel schauen wir uns an, wie wir diese Effizienz in die Benutzeroberfläche bringen, damit die User Experience nicht unter komplexen Prozessen leidet.
Nachdem wir uns im letzten Kapitel tief in die Tiefen von SQL-Abfragen und Locking-Strategien vergraben haben, kommen wir nun zu dem Teil Ihrer App, den Ihre Kunden tatsächlich jeden Tag sehen und anfassen: Das User Interface. Oft wird das UI-Design in der Business-Central-Entwicklung ein wenig stiefmütterlich behandelt, ganz nach dem Motto: Hauptsache die Logik im Hintergrund stimmt und das Feld ist irgendwo auf der Page vorhanden. Doch für die Akzeptanz einer Software ist die User Experience, also die Erfahrung, die der Anwender bei der täglichen Arbeit macht, absolut entscheidend. Ein mächtiges Werkzeug nützt am Ende wenig, wenn es sich für den Nutzer wie ein Hindernis anfühlt. Beginnen wir mit der Strukturierung von Pages. Eine goldene Regel für fortgeschrittene Entwickler lautet: Weniger ist mehr. Wenn Sie eine Page mit fünfzig Feldern entwerfen, erschlagen Sie den Nutzer förmlich. Nutzen Sie stattdessen konsequent die Importance-Property. Felder, die nur gelegentlich gebraucht werden, gehören in die Kategorie Additional, damit sie standardmäßig ausgeblendet sind. Das sorgt nicht nur für visuelle Übersicht, sondern reduziert auch den kognitiven Load für den Anwender massiv. Ein weiterer wichtiger Punkt sind die Cues auf den Role Centern. Diese sollten nicht nur hübsche Kacheln sein, sondern echte Handlungsempfehlungen geben. Verwenden Sie farbliche Indikatoren sinnvoll, um auf Engpässe oder dringende Aufgaben hinzuweisen, anstatt nur nackte Zahlen zu präsentieren. Ein gut gestaltetes Role Center fungiert als das Cockpit eines Unternehmens und sollte genau die Informationen priorisieren, die für die jeweilige Rolle unmittelbar relevant sind. Ein besonders spannendes, aber auch technisch anspruchsvolles Feld sind die Control Add-ins. Mit JavaScript und HTML können wir Business Central um Funktionen erweitern, die nativ in AL schlicht nicht möglich wären. Denken wir an interaktive Diagramme, Kartenintegrationen oder komplexe Drag-and-Drop-Editoren. Aber hier lauert eine gefährliche Performance-Falle. Ein Control Add-in wird in einem I-Frame geladen, und jede Kommunikation zwischen AL und dem JavaScript-Teil erfolgt über eine asynchrone Brücke. Wenn Sie bei jedem Tastendruck oder jeder kleinsten Mausbewegung Daten hin und her schicken, wird die Bedienung extrem zäh. Best Practice ist hier: Senden Sie Daten gesammelt und minimieren Sie die Anzahl der Aufrufe. Das UI darf niemals einfrieren, während im Hintergrund ein Control Add-in Daten verarbeitet. Überlegen Sie sich auch genau, ob ein Add-in wirklich notwendig ist, oder ob eine geschickt konfigurierte Standard-Page mit FactBoxes nicht die stabilere und wartungsfreundlichere Lösung wäre. Apropos FactBoxes: Diese sind genial, um Kontextinformationen zu liefern, ohne die Hauptseite zu überfrachten. Aber Vorsicht beim Datendesign. Eine FactBox, die bei jedem Datensatzwechsel in einer Liste komplexe Berechnungen oder gar externe API-Calls auslöst, ruiniert die Scroll-Performance der gesamten Anwendung. Hier greifen wir wieder auf Techniken zurück, die wir beim Thema Performance gelernt haben: Nutzen Sie Page-Background-Tasks, um aufwendige Berechnungen in den Hintergrund zu verlagern. So bleibt die Liste flüssig bedienbar, während die FactBox ihre Daten erst dann einblendet, wenn sie fertig geladen sind. Zusammenfassend lässt sich sagen: Ein exzellentes UI-Design in Business Central bedeutet, den Nutzer durch den Prozess zu führen, anstatt ihm nur eine Datenbankmaske vorzuwerfen. Nutzen Sie die Möglichkeiten der Plattform, um Logik von der reinen Anzeige zu trennen, halten Sie die Oberflächen schlank und setzen Sie komplexe Add-ins nur dort ein, wo sie echten Mehrwert bieten, ohne die Performance zu korrumpieren. Im nächsten Kapitel schlagen wir dann die Brücke nach außen und schauen uns an, wie wir unsere Anwendungen über API-Pages und Azure Functions für die moderne Cloud-Welt öffnen.
Wenn wir heute über moderne Integrationen in Business Central sprechen, kommen wir an einem grundlegenden Paradigmenwechsel nicht vorbei. In der Vergangenheit war es oft die schnellste Lösung, einfach eine bestehende Page zu nehmen und diese als Webservice freizugeben. Das hat zwar funktioniert, war aber architektonisch gesehen eine Sackgasse. Warum? Weil diese Pages für Menschen gemacht sind, nicht für Maschinen. Sie enthalten UI-Logik, Trigger, die auf Benutzereingaben warten, und oft eine Performance, die bei automatisierten Massendaten-Abfragen in die Knie geht. In einer modernen Cloud-Architektur ist der API-First-Ansatz deshalb kein optionales Extra mehr, sondern der absolute Goldstandard. Echte API-Pages sind von Grund auf anders konzipiert. Sie entkoppeln die Benutzeroberfläche vollständig von der Datenschnittstelle. Das gibt uns als Entwicklern die Freiheit, das zugrunde liegende Tabellendesign zu ändern, ohne sofort die Integrationen unserer Kunden oder Drittanbieter zu zerstören. Durch die konsequente Nutzung von API-Versionierung in der URL stellen wir sicher, dass wir neue Features ausrollen können, während die alte Logik für bestehende Anbindungen stabil bleibt. Aber es geht nicht nur um Stabilität, sondern vor allem um Geschwindigkeit. API-Pages nutzen das OData-v4-Protokoll weitaus effizienter aus, unterstützen Deep-Inserts, bei denen Header und Zeilen in einem einzigen Aufruf verarbeitet werden, und minimieren den Overhead, der durch herkömmliche Page-Trigger entsteht. Wer heute noch Web-Services auf Basis von Standard-Pages baut, baut sich im Grunde technische Schulden für morgen auf. Doch eine moderne Schnittstelle besteht nicht nur aus passiven Endpunkten, die darauf warten, abgefragt zu werden. Wir müssen weg vom teuren Polling. Wenn ein externer Onlineshop alle fünf Minuten bei Business Central nachfragt, ob es neue Artikeländerungen gibt, verschwendet das wertvolle Ressourcen und erzeugt unnötige Last auf der Datenbank. Hier kommen Webhooks ins Spiel. Das Ziel muss eine ereignisgesteuerte Architektur sein. Business Central benachrichtigt das externe System proaktiv, sobald sich ein relevanter Datensatz geändert hat. Das hält die Kommunikation schlank und sorgt für eine Synchronisation nahezu in Echtzeit. In der AL-Entwicklung bedeutet das, dass wir uns intensiv mit den Subscription-Modellen für Webhooks auseinandersetzen müssen, um BC als aktiven Player im Ökosystem zu positionieren. Manchmal stößt AL als Sprache aber auch an seine Grenzen, sei es bei komplexen mathematischen Berechnungen, der Verarbeitung großer Dateimengen oder der Anbindung an exotische Drittanbieter-Bibliotheken. In diesen Momenten sollten wir nicht versuchen, Business Central zu Dingen zu zwingen, für die es nicht gebaut wurde. Stattdessen nutzen wir Azure Functions als unsere verlängerte Werkbank. Eine Azure Function kann genau das erledigen, was in AL zu langsam oder schlicht unmöglich wäre, und liefert das Ergebnis sauber per HTTP-Call zurück. Das ist wahre Cloud-Readiness: Wir nutzen Business Central für die Business-Logik und die Datenhaltung, aber wir lagern spezialisierte Aufgaben in die skalierbare Azure-Welt aus. Wenn wir diese Werkzeuge – also dedizierte API-Pages, Webhooks und Azure Functions – klug kombinieren, schaffen wir Systeme, die nicht nur heute funktionieren, sondern die auch mit den Anforderungen von morgen mitwachsen können. Im nächsten Kapitel schauen wir uns an, wie wir diese komplexen Konstrukte durch automatisiertes Testen absichern können.
Wir kommen nun zu einem Thema, das in der klassischen Entwicklung oft als lästige Pflicht stiefmütterlich behandelt wurde, in der modernen Business Central Welt aber über Erfolg oder Scheitern entscheidet: Automated Testing. Wenn wir über Cloud-Readiness sprechen, dann sprechen wir zwangsläufig über Veränderung. Microsoft rollt monatlich Minor-Updates und halbjährlich Major-Releases aus. In dieser Dynamik ist manuelles Testen nicht nur ineffizient, es ist schlichtweg unmöglich. Wer keine automatisierte Absicherung hat, riskiert bei jedem Plattform-Update, dass geschäftskritische Prozesse beim Kunden stillstehen. Der Kern unserer Strategie ist das Microsoft Test Toolkit. Für viele erfahrene Entwickler ist der Einstieg erst einmal ungewohnt, weil wir plötzlich mehr Code für die Tests schreiben als für die eigentliche Funktion. Aber genau hier liegt der Hebel für langfristige Wartbarkeit. Eine professionelle AL-Lösung sollte immer aus mindestens zwei Apps bestehen: der Haupt-App und einer korrespondierenden Test-App. In dieser Test-App nutzen wir die Library-Codeunits von Microsoft, die uns unzählige Hilfsfunktionen bieten, um beispielsweise Debitoren, Artikel oder Verkaufsbelege mit nur einer Zeile Code anzulegen, ohne uns um die komplexen Tabellenbeziehungen im Hintergrund kümmern zu müssen. Ein entscheidendes Entwurfsmuster für eure Tests ist das Given-When-Then-Schema. Es strukturiert den Test-Code so, dass er fast wie eine fachliche Spezifikation lesbar ist. Unter Given definieren wir die Ausgangslage, also die Testdaten und den Systemzustand. Unter When führen wir die spezifische Aktion aus, die wir prüfen wollen, etwa das Auslösen einer speziellen Rabattlogik. Und unter Then validieren wir das Ergebnis. Dieser strukturierte Ansatz hilft nicht nur bei der Fehlersuche, sondern dient gleichzeitig als Dokumentation der Geschäftslogik. Ein fortgeschrittener Aspekt ist der Umgang mit Benutzeroberflächen. Da automatisierte Tests im Hintergrund ohne User-Interaktion laufen müssen, nutzen wir UI-Handler-Funktionen. Damit simulieren wir Bestätigungsdialoge oder Seiteneingaben, ohne dass der Testlauf unterbrochen wird. Das Ziel sollte dabei immer sein, so wenig UI wie möglich und so viel Logik wie nötig zu testen. Unit-Tests sollten isoliert und schnell sein, während Integrationstests die gesamte Kette vom Auftrag bis zur Buchung abbilden. Die wahre Magie entfaltet sich jedoch erst, wenn diese Tests in eure CI-CD-Pipelines integriert sind. Bei jedem Push in das Repository oder spätestens beim täglichen Build sollten alle Tests automatisch in einer Docker-Umgebung oder einer Online-Sandbox gegen die aktuelle BC-Version laufen. So erkennt ihr Breaking Changes von Microsoft oft schon Wochen, bevor das Update die Produktionsumgebung eurer Kunden erreicht. Das ist der ultimative Schutz für eure Update-Fähigkeit. Natürlich kostet das Schreiben von Tests Zeit, und der Druck in Projekten ist oft hoch. Aber wir müssen weg von der Vorstellung, dass Tests ein optionales Extra sind. Sie sind ein integraler Bestandteil des Produkts. Ein gut geschriebener Test ist eine Versicherung gegen Regressionen und ermöglicht es uns, Refactoring am Kernsystem vorzunehmen, ohne Angst haben zu müssen, unbemerkt an einer anderen Stelle etwas kaputt zu machen. Wer automatisiert testet, investiert in seine eigene Schlafqualität und in das Vertrauen seiner Kunden. Im nächsten Kapitel schauen wir uns an, wie wir dieses Vertrauen durch proaktives Monitoring mit Telemetrie noch weiter stärken können.
Bisher haben wir uns intensiv damit beschäftigt, wie wir sauberen und performanten AL-Code schreiben. Aber Hand aufs Herz: Egal wie gut unsere Unit-Tests sind und wie strikt wir Design-Patterns befolgen, die Realität in der Cloud ist komplex. Wenn eine Extension erst einmal produktiv beim Kunden im Einsatz ist, fühlen wir uns als Entwickler oft so, als würden wir im Dunkeln fliegen. Wir wissen zwar, dass das System läuft, aber wir sehen nicht direkt, wo es knirscht, bis der Kunde zum Hörer greift. Genau hier setzen Azure Application Insights und die Telemetrie an. Es ist der entscheidende Schritt von einer rein reaktiven Fehlerbehebung hin zu einem proaktiven Monitoring, das uns erlaubt, Probleme zu lösen, bevor der Anwender sie überhaupt bemerkt. Technisch gesehen ist die Einrichtung erstaunlich simpel. Wir benötigen lediglich eine Application-Insights-Instanz in Azure und tragen den dazugehörigen Instrumentation-Key im Business Central Admin Center ein. Doch der wahre Wert liegt nicht in der Verbindung, sondern in den Daten, die ab diesem Moment fließen. Microsoft liefert uns eine riesige Menge an Standard-Signalen. Das reicht von fehlgeschlagenen Logins über SQL-Timeouts bis hin zu Performance-Metriken für Berichte und Webservices. Um diese Datenflut zu beherrschen, nutzen wir Kusto, die Kusto Query Language, kurz KQL. Wer sich einmal in KQL eingearbeitet hat, erkennt schnell die Mächtigkeit dieser Sprache. Wir können damit innerhalb von Sekunden herausfinden, welche SQL-Abfrage in den letzten 24 Stunden die längste Ausführungszeit hatte oder ob ein bestimmter API-Endpunkt seit dem letzten Update vermehrt Fehler wirft. Ein absoluter Gamechanger für uns AL-Entwickler ist jedoch die Möglichkeit, eigene Telemetrie-Daten zu senden. Mit der Funktion Session.LogMessage können wir gezielte Informationen aus unserem Code direkt nach Azure schicken. Das ist besonders wertvoll bei komplexen Business-Logiken oder Schnittstellen zu Drittsystemen. Stellen Sie sich vor, Sie haben eine Anbindung an einen Logistikdienstleister. Anstatt bei Fehlern mühsam in Log-Tabellen innerhalb von Business Central zu suchen, die die Datenbank aufblähen, senden Sie den Status einfach als Telemetrie-Signal. Sie können dabei sogar eigene Dimensionen definieren, also Metadaten wie die Mandanten-ID oder eine spezifische Prozess-Nummer. So lässt sich im Fehlerfall präzise nachvollziehen, an welcher Stelle im Code die Logik abgebrochen ist. Aber Vorsicht ist geboten: Telemetrie ist kein Dump für sensible Daten. Aus Datenschutzgründen und im Sinne der DSGVO dürfen niemals personenbezogene Daten wie Namen oder Klarschriftadressen in die Telemetrie fließen. Der Fokus sollte immer auf dem technischen Ablauf und der Performance liegen. Wenn wir das richtig angehen, können wir uns Dashboards in Azure oder Power BI bauen, die uns auf einen Blick den Gesundheitszustand aller Kundenumgebungen zeigen. Wir sehen Performance-Bottlenecks durch Locking-Probleme oder ineffiziente Queries sofort. Der größte Vorteil ist am Ende das Vertrauen des Kunden. Wenn wir ihn anrufen und sagen können, dass wir bereits an einer Optimierung für einen Prozess arbeiten, der gestern Nachmittag ungewöhnlich langsam war, dann heben wir unsere Dienstleistung auf ein völlig neues Niveau. Telemetrie macht unsere Arbeit in der Cloud transparent und gibt uns die Kontrolle zurück, die wir in der On-Premises-Welt durch direkten SQL-Zugriff hatten, nur eben viel skalierbarer und moderner.
Nachdem wir uns im letzten Kapitel angesehen haben, wie wir Fehler proaktiv über die Telemetrie aufspüren, kommen wir nun zu dem Teil, der uns hilft, diese Probleme gar nicht erst entstehen zu lassen. Es geht um die großen Don'ts der AL-Entwicklung. In der Welt von Business Central gibt es Fehler, die zwar technisch kompilieren, aber in einer Cloud-Umgebung wie eine Zeitbombe wirken. Lassen Sie uns mit einem der häufigsten Performance-Killer aufräumen, den Record-Referenzen innerhalb von Schleifen. Es ist ein klassisches Anti-Pattern, in einer Iteration über tausende Zeilen hinweg für jeden einzelnen Datensatz ein Get auf eine verknüpfte Tabelle auszuführen oder, noch schlimmer, Schreibzugriffe zu tätigen. Was lokal auf dem Docker-Container vielleicht noch performant wirkt, führt in der Cloud durch die Latenz zum SQL-Server schnell zu massiven Einbußen. Nutzen Sie stattdessen konsequent Mengenoperationen oder bereiten Sie Daten in temporären Tabellen vor, um die Anzahl der Server-Roundtrips zu minimieren. Ein weiterer kritischer Punkt sind die UI-Trigger, allen voran OnAfterGetRecord auf List-Pages. Erfahrene Entwickler wissen zwar, dass dieser Trigger bei jedem Scrollen gefeuert wird, aber trotzdem sehen wir immer wieder komplexe Kalkulationen oder sogar FlowField-Berechnungen an dieser Stelle. Das Ergebnis ist eine ruckelige Benutzererfahrung, die den Endanwender frustriert. Wenn Logik auf einer Page sein muss, dann gehört sie in die OnOpenPage oder sollte über FlowFields gelöst werden, die bereits auf Datenbankebene optimiert sind. Ein absolutes Tabu ist zudem der Missbrauch von OnGlobal-Triggern oder zu tief verschachtelten Event-Subscribern. Da wir in Business Central eine ereignisgesteuerte Architektur haben, ist die Versuchung groß, sich an jedes verfügbare Event zu hängen. Doch Vorsicht, wenn Sie globale Trigger nutzen, um Geschäftslogik zu prüfen, die eigentlich in eine spezifische Funktion gehört, blähen Sie den gesamten Prozess auf und erschweren das Debugging massiv. Ein ganz besonders gefährliches Anti-Pattern betrifft das Transaktionshandling. Die Nutzung von expliziten Commit-Befehlen sollte die absolute Ausnahme bleiben. In der Cloud-Umgebung riskieren Sie mit unbedachten Commits inkonsistente Datenzustände, falls ein Prozess später abbricht, da der automatische Rollback an dieser Stelle gestoppt wurde. Wer Commits nutzt, um UI-Fehlermeldungen zu umgehen oder Hintergrundprozesse zu steuern, baut technische Schulden auf, die bei jedem Minor-Update von Microsoft zu Problemen führen können. Zu guter Letzt möchte ich noch das Thema Hartcodierung ansprechen. Es klingt banal, aber in der AL-Entwicklung ist das Festschreiben von IDs, Namen oder spezifischen Mandanten-Logiken im Code ein Garant für spätere Fehler. Nutzen Sie stattdessen konsequent Setup-Tabellen oder die neuen Möglichkeiten von Enums und dem Strategy Pattern, über das wir bereits gesprochen haben. Ein sauberer Code zeichnet sich dadurch aus, dass er keine Annahmen über die Umgebung trifft, in der er läuft. Wenn Sie diese Anti-Patterns konsequent vermeiden, sorgen Sie nicht nur für eine bessere Performance, sondern auch für eine Cloud-Readiness, die den Namen wirklich verdient. Im nächsten und letzten Kapitel ziehen wir dann ein Fazit und schauen uns an, wohin die Reise mit der AL-Sprache in Zukunft noch gehen wird.
Damit sind wir am Ende unserer Reise durch die professionelle AL-Entwicklung angekommen. Wir haben viel abgedeckt, vom harten Paradigmenwechsel beim Umstieg in die Cloud bis hin zu den subtilen Performance-Fallen, die selbst erfahrenen Entwicklern immer mal wieder begegnen. Wenn ihr eine zentrale Botschaft aus dieser Serie mitnehmen solltet, dann ist es die Erkenntnis, dass moderne Business-Central-Entwicklung weit über das reine Schreiben von Code hinausgeht. Es ist eine Frage der Disziplin und der richtigen Architektur. Der Wandel von C-AL hin zu AL war nicht nur ein Wechsel der Syntax, sondern eine fundamentale Neuausrichtung unseres Handwerks. In der Welt der Extensions können wir uns nicht mehr darauf verlassen, dass wir den Standard einfach verbiegen. Wir müssen stattdessen lernen, ihn durch saubere Events und modulare Strukturen zu erweitern. Erinnert euch an die Design-Patterns, die wir besprochen haben: Das Strategy Pattern oder das Facade Pattern sind keine akademischen Spielereien. Sie sind eure Werkzeuge, um Komplexität beherrschbar zu machen und sicherzustellen, dass eure Apps auch in zwei Jahren noch wartbar sind, wenn Microsoft das nächste Major-Update ausrollt. Ein weiterer entscheidender Punkt bleibt die Performance. In der Cloud-Umgebung teilen wir uns Ressourcen, und jedes ineffiziente Locking oder jede unnötige Datenbankabfrage hat direkte Auswirkungen auf die User-Experience. Wir haben gesehen, wie wichtig Telemetrie und Azure Application Insights geworden sind. Ein professioneller Entwickler wartet heute nicht mehr darauf, dass der Kunde anruft, weil das System langsam ist. Er erkennt die Bottlenecks proaktiv im Monitoring, bevor sie zum Problem werden. Das gehört zum neuen Standard der Cloud-Readiness dazu. Auch das Thema Testing ist kein optionales Extra mehr. Wer ohne automatisierte Regressionstests in der Cloud unterwegs ist, spielt im Grunde russisches Roulette mit jeder neuen Version von Business Central. Aber wie geht es nun weiter? Wenn wir nach vorne blicken, sehen wir eine Evolution der AL-Sprache, die immer mächtiger wird. Microsoft investiert massiv in die Entwicklungsumgebung in Visual Studio Code und bringt uns Werkzeuge, die die Grenze zwischen klassischer ERP-Entwicklung und moderner Softwaretechnik weiter verschwimmen lassen. Ein riesiges Thema der Zukunft ist zweifellos die Künstliche Intelligenz. Wir sehen bereits jetzt, wie GitHub Copilot und spezialisierte KI-Modelle uns beim Schreiben von AL-Code, bei der Dokumentation und beim Erstellen von Test-Szenarien unterstützen können. Die Rolle des Entwicklers wird sich dadurch weiter verschieben, weg vom reinen Code-Schreiben hin zum Architekten und Reviewer von KI-generierten Vorschlägen. Business Central wird zudem immer stärker in das gesamte Microsoft-Ökosystem integriert. Das bedeutet für uns, dass wir uns nicht mehr nur auf AL beschränken können. Die Verzahnung mit der Power Platform, mit Azure Functions und Dataverse wird zum Alltag gehören. Die Zukunft der AL-Entwicklung ist vernetzt, datengetrieben und vor allem eines: rasant schnelllebig. Bleibt also neugierig, testet neue Patterns aus und behaltet eure Telemetrie-Daten im Auge. Vielen Dank, dass ihr bei dieser Staffel von toknow dabei wart. Wir hoffen, ihr fühlt euch jetzt besser gerüstet für eure tägliche Arbeit in der Welt von Microsoft Dynamics 365 Business Central. Viel Erfolg bei euren nächsten Projekten und bis zum nächsten Mal.