Doppelsieg für Apriko: Gold und Silber bei den Best of Swiss Software-Awards 2024
Im Kongresshaus Zürich wurden am 19. November 2024 die besten Softwarelösungen der Schweiz ausgezeichnet. Besonders strahlend: Das Start-up Apriko, das mit Gold in der Kategorie Business Solutions und Silber in der Kategorie Cloud Native Solutions gleich doppelt überzeugte.
Automatische Generierung der grafischen Benutzeroberfläche (UI)
Ein zentrales Designprinzip der Software-Architektur von Apriko ist es, so viel Boilerplate-Code wie möglich automatisch zu generieren oder Logik abzuleiten. Auf diese Weise kann das Entwicklungsteam den Fokus stärker auf das „Was“ und weniger auf das „Wie“ (die zeitaufwändige Detailarbeit) richten.
Designprozess
Als Beispiel: Im Designprozess wird eine Entität „Person“ definiert, die verschiedene Merkmale wie Vorname und Nachname enthält. Jedes dieser Merkmale kann auch Validierungsregeln unterliegen – so sind etwa Vor- und Nachname Pflichtfelder. Das „Was“ bezieht sich auf die äussere Perspektive der Applikation, also auf die Modellierung von Entitäten und die Definition von Geschäftsregeln (Business Rules). Deklarative Ansätze bieten viele Vorteile, insbesondere da sie die Komplexität verringern. Interne Mechanismen werden schneller umgesetzt und sind unmittelbar sichtbar, ohne dass grosse Mengen an Code zunächst analysiert werden müssen.
Problematik des manuellen Boilerplate-Managements
Üblicherweise wird das „Wie“ manuell implementiert. Dies bietet zwar Flexibilität, führt jedoch schnell zu einer vertikalen Erweiterung über alle Schichten der Software-Architektur. Das Hauptproblem besteht darin, die Kohärenz sicherzustellen. Es müssen ähnliche Probleme mit ähnlichen Lösungsansätzen behandelt werden, um stilistische und funktionale Vollständigkeit und Konsistenz zu gewährleisten. Werden nachträglich Änderungen vorgenommen, besteht das Risiko, dass wichtige Anpassungen übersehen werden, was zu Bugs und Software-Regressionen führen kann.
Inferenz
Aus den zentral definierten Entitäten, Merkmalen, Aktionen und Geschäftsregeln wird automatisch weitergehende Logik abgeleitet. Zum einen rückwärts in tieferen Schichten, indem die Datenbankstruktur automatisch generiert und falls nötig migriert wird. Zum anderen vorwärts in höheren Schichten, indem z.B. Infrastrukturkomponenten und Web-Service-Schnittstellen (API/REST) generiert werden.
Diese Deklarationen, sprich Layout-Definitionen, werden bis ins UI/Frontend getragen. Eine eigens entwickelte UI-Engine verarbeitet diese, um die grafische Benutzeroberfläche zu generieren.
Da diese Architektur eine starke Standardisierung erfordert, müssen viele Anforderungen vereinheitlicht werden, um das volle Potenzial auszuschöpfen. Die Robustheit der Architektur liegt jedoch darin, dass sie Abweichungen vom Standard zulässt, um spezifische Geschäftslogik gezielt zu implementieren, ohne dass dabei Inkonsistenzen entstehen.
Frontend-Engine
Layout-Definitionen
Jeder Service stellt seine Deklarationen in Form von JSON-Dateien als Layout-Definitionen für die Frontend-UI-Engine bereit. Diese Layout-Definitionen enthalten alle Entitäten, Merkmale, Aktionen und Geschäftsregeln in strukturierter Form. Das Frontend kann auf dieser Grundlage den Grossteil der Anwendungsfälle darstellen, ohne dass zusätzliche Programmierung erforderlich ist. Dies ermöglicht ein weitgehend unabhängiges und autarkes Frontend, das nur lose mit dem Backend gekoppelt ist.
Generierung von Ansichten
Aus den Layout-Definitionen können unterschiedliche Ansichten (Views) dynamisch generiert werden. Die Grundstruktur einer View, z.B. eines Formulars, ist explizit implementiert. Der Inhalt – also die Art der Aktion, die Felder und die Entitätstypen – wird hingegen dynamisch anhand des Kontexts ermittelt und aus den Layout-Definitionen konfiguriert. Beispielsweise erhält die Formular-View die Anweisung, „eine Person zu erstellen“, und generiert automatisch die dafür notwendigen Felder inklusive Validierungsregeln und Geschäftslogik, um eine fertige Anfrage ans Backend senden zu können.
Ereignisbasierter Ansatz
Die einzelnen Views und deren Komponenten beziehen ihre Informationen nicht nur aus den Layout-Definitionen, sondern müssen auch den aktuellen Datenstand berücksichtigen. In einem dynamischen System müssen Komponenten auf Ereignisse, wie z.B. die Änderung eines Feldwerts, reagieren und diese Änderungen in Echtzeit darstellen. Dies wird durch einen Mix aus Model–view–controller Pattern (MVC) und einer virtuellen Datenbank im Frontend umgesetzt. Diese virtuelle Datenbank fungiert als Model im Sinne des MVC-Prinzips und synchronisiert Änderungen und generiert entsprechende Ereignisse. Das Model entspricht hierbei auch einem Cache für Abfragen ans Backend.
Model Messages
Der standardisierte Austausch von Änderungen (Create, Update, Delete) an Daten erfolgt über sogenannte Model Messages. Diese werden sowohl zwischen den Systemeinheiten (Services) als auch mit dem Frontend ausgetauscht. Model Messages zeigen nicht nur Änderungen an Entitäten an, sondern auch Änderungen an Beziehungen zwischen Entitäten oder Daten, die zwischen Entitäten geteilt werden. Dieses semantische Wissen, zusammen mit den Layout-Definitionen, ermöglicht die Dynamik des Frontends und trägt zur Entkopplung vom Backend bei.
Model Service
Aufgrund des verteilten Charakters der Applikation, bei der verschiedene Services unterschiedliche Daten verwalten, ist es einem einzelnen Service nicht möglich, eine vollständige Abfrage über alle Daten durchzuführen. Damit das Frontend dennoch effizient Daten von mehreren Services in einer einzigen Abfrage erhalten kann, wurde ein Model Service entwickelt. Dieser verarbeitet die Model Messages und erstellt eine aggregierte Sicht auf die Daten aller Services. Damit fungiert der Model Service als Vorstufe eines Data-Warehouses und ermöglicht umfassende – auch Graph basierte – Abfragen auf diese hierarchische Datenstruktur.
Lokalisierung
Ein weiterer zentraler Bestandteil der Frontend-Engine ist die Lokalisierung, welche die Übersetzung und Formatierung der Inhalte umfasst.
Da Apriko mehrsprachig ist, müssen Texte und Daten in einer generischen, unübersetzten Form vorliegen, respektive vom Backend bereitgestellt werden. Die tatsächliche Übersetzung erfolgt erst im letzten Schritt bei der Generierung der Oberfläche.
Fazit
Die Entkopplung von Backend und Frontend sowie der deklarative Ansatz in der Backend-Entwicklung ermöglichen eine bessere Fokussierung auf die Implementierung der Geschäftslogik. Gleichzeitig wird die Entstehung von unnötigem Boilerplate-Code sowie dessen Erosion minimiert und die Konsistenz durch alle Schichten der Software-Architektur erhöht.