Anpassbarkeit in SaaS Software - Erfahrungsbericht Teil 1

von Alexander Huber

Es ist jetzt schon mehr als 15 Jahre her, dass wir time cockpit verfügbar gemacht haben. Genau genommen am 1. Januar 2010. Seit damals sind wir mit dem Produkt auf dem Markt. Time cockpit hatte damals viele USPs. Es gab noch nicht viele Zeiterfassungstools mit einem grafischen Kalender. Auch der Activity Tracker war damals ein Novum. Mittlerweile haben viele Zeiterfassungen einen Kalender, und auch Activity Tracker sind weiter verbreitet. Was aber bis heute, zumindest nach unserem Wissen, ein Alleinstellungsmerkmal ist, ist die Anpassbarkeit von time cockpit.

In diesem ersten Blogartikel der Serie möchte ich darüber sprechen, warum uns damals Anpassbarkeit so wichtig war und warum dies auch für den Leser relevant sein könnte, der überlegt, eine neue SaaS-Applikation zu entwickeln. Dabei werden die Kernaspekte der Anpassbarkeit – insbesondere das Metamodell und die dynamische Datenschicht – näher beleuchtet.

Das Kernkonzept: Anpassbarkeit

Der Kern von time cockpit hat einen Namen: das sogenannte COFX (Cockpit Framework). Um ehrlich zu sein, time cockpit ist nur eine von mehreren Anwendungen, die auf Basis von COFX entwickelt wurden. Verschiedene Produkte wie TFM oder Emir-ate basieren auf dem Framework. Diese Anwendungen sind allesamt datengetriebene SaaS-Applikationen. Genau das ist COFX – ein Framework für datengetriebene Anwendungen.

Time cockpit ist unser Flaggschiffprodukt, und für dieses wurde COFX entwickelt. Warum war es so wichtig für uns, dass time cockpit anpassbar ist? Die Gründer von Software Architects bzw. time cockpit haben ihre gesamte Erfahrung als Geschäftsführer einer Dienstleistungsfirma in das Produkt eingebracht. Und eins war klar: Wenn Zeiterfassung, dann muss sie anpassbar sein. Warum? Weil jedes Unternehmen anders ist.

Nehmen wir als Beispiel IT-Dienstleistungsunternehmen. Diese Unternehmen ticken zwar ähnlich, aber nicht gleich. Sie unterscheiden sich in ihren Strukturen, Prozessen und Anforderungen. Unternehmen entwickeln sich – sie wachsen, schrumpfen, und Prozesse verändern sich. Unserer Erfahrung nach reichen Standardprodukte für viele Anwendungsfälle nicht aus. Erfolgreiche Software muss sich an die Gegebenheiten eines Unternehmens anpassen.

Die technische Umsetzung: Stabiler Kern und flexible Anpassungen

Wir haben time cockpit so konzipiert, dass es einen stabilen Kern sowie domänenspezifische Business-Logik out-of-the-box bietet. Dazu gehören komplexe Berechnungen wie Überstundenberechnung, Urlaubs-/Resturlaubsberechnung und die Erkennung von Arbeitszeitverletzungen. Kundenspezifische Anforderungen können über Konfiguration und einfaches Coding umgesetzt werden. Auch Weiterentwicklungen des Kerns werden dadurch erleichtert.

Unternehmerisch bringt Anpassbarkeit auch einige Vorteile mit sich: time cockpit generiert Umsatz sowohl über monatliche Lizenzgebühren als auch über Dienstleistungen zur Anpassung des Produkts an die Bedürfnisse der Kunden. Ein weiterer wichtiger Aspekt ist, dass die Anpassbarkeit es uns ermöglicht, den Customer Lifetime Value (CLV) zu erhöhen. Da time cockpit flexibel ist und sich den veränderten Anforderungen eines Kunden anpassen kann, muss dieser nicht zu einem neuen Produkt wechseln, wenn sich seine Geschäftsanforderungen ändern. Stattdessen bleibt er in einer gewohnten Umgebung und arbeitet weiterhin mit einem Dienstleister zusammen, den er bereits kennt und dem er vertraut. Dies bedeutet auch, dass teure Migrationsprojekte und aufwendige Mitarbeiterschulungen entfallen. Kunden können in ihrem etablierten Workflow bleiben, was sowohl Zeit als auch Ressourcen spart.

Die Säulen der Anpassbarkeit

Die Anpassbarkeit von time cockpit basiert auf mehreren Säulen:

  1. Metamodell und Modell
  2. Dynamische/Adaptive Datenschicht
  3. String Templates
  4. Dynamische Abfragesprache
  5. UI-Engine
  6. Scripting-Sprache auf Basis von IronPython

In diesem Artikel möchte ich die ersten beiden Säulen – Metamodell und Modell sowie die dynamische Datenschicht – näher beleuchten.

Metamodell und Modell

COFX und damit time cockpit ist eine modellgetriebene Applikation. Es gibt ein Metamodell, das beschreibt, wie eine Anwendung auf Basis von COFX aussieht. Das Metamodell von time cockpit besteht aus zentralen Elementen wie:

  • SYS_ENTITY
  • SYS_PROPERTY
  • SYS_RELATION
  • SYS_PERMISSION
  • SYS_MODELACTION
  • SYS_ENTITYVIEW

Diese Metamodell-Elemente werden in sogenannten SYS-Tabellen in der Datenbank gespeichert. Diese Tabellen sind integraler Bestandteil jeder Kundendatenbank und werden von der Datenschicht ausgelesen und interpretiert. Ein Beispiel: Die Tabelle SYS_ENTITY enthält Einträge wie APP_Timesheet, APP_Project oder APP_Task, also Tabellen spezielle für die Domäne Zeiterfassung. Die Tabelle SYS_PROPERTY beschreibt die Eigenschaften dieser Tabellen.

SYS-Tabellen bilden das Metamodell und speichern Informationen über das Datenmodell der Applikation. Dieses Datenmodell besteht aus zwei Hauptkomponenten: APP-Tabellen und USR-Tabellen. APP-Tabellen liefern wir standardmäßig mit aus und sie repräsentieren die Kernfunktionen des Produkts. USR-Tabellen hingegen werden speziell für die Anforderungen unserer Kunden erstellt, um individuelle Anpassungen abzubilden.

In unserem Ansatz haben wir Standard- und Benutzeranpassungen konsequent getrennt. Wir nutzen Namensräume (z. B. SYS, APP, USR), um Standardfeatures von benutzerspezifischen Erweiterungen zu isolieren. Dieser Ansatz hat sich für uns bewährt, da er Updates erleichtert und die Weiterentwicklung des Standardprodukts sichert.

Ein weiterer entscheidender Vorteil unseres Ansatzes ist, dass alle Entitäten als Tabellen in der Datenbank existieren. APP_Timesheet, APP_Project samt ihren Eigenschaften (Spalten) und Relationen (Foreign Keys) sind Teil eines klar strukturierten Datenbankschemas. Dieses Schema ist sowohl für Menschen als auch für Maschinen leicht lesbar und verständlich. Daten werden nicht in XML- oder JSON-Spalten gespeichert, sondern relational. Dadurch ergeben sich mehrere Vorteile: Wir können mit SQL-Tools wie SQL Management Studio, Azure Data Studio oder SSIS direkt auf die Daten zugreifen. Das ermöglicht beispielsweise große Datenimporte direkt über die Datenbank, ohne die time cockpit Web API nutzen zu müssen.

Der direkte Zugriff auf das relationale Datenbankschema eröffnet zusätzliche Integrationsmöglichkeiten. Tools wie Power BI oder Tableau können direkt auf die Daten zugreifen, was Reporting und Analyse erheblich erleichtert. Viele unserer Kunden haben bereits Know-How in diesen Tools und können somit Auswertungen in Ihrer gewohnten Umgebung (PowerBI, Tableau) selbst umsetzen. Dieser Ansatz hat sich für uns bewährt, vielleicht ist er auch für Sie interessant.

Dynamische Datenschicht

Ein Metamodell ist schön und gut, aber für sich allein bringt es noch keinen praktischen Nutzen für Anwendungen wie Time Cockpit oder COFX. Die dynamische Datenschicht von COFX hat mehrere Hauptaufgaben, die sie zu einem zentralen Bestandteil des Frameworks machen:

  • Lesen und Interpretieren des Metamodells: Diese Funktion ermöglicht es, das Modell zur Laufzeit zu analysieren und dynamisch anzupassen.
  • CRUD-Operationen (Create, Read, Update, Delete) auf Daten: Daten können flexibel bearbeitet werden, ohne dass der zugrunde liegende Code statisch angepasst werden muss.
  • Datenabfragen: Die Datenschicht erlaubt es, flexible Abfragen auf Basis des Metamodells durchzuführen (Thema eines späteren Blogbeitrags).
  • CRUD-Operationen auf dem Metamodell: Sogar das Datenmodell selbst kann zur Laufzeit modifiziert werden, um sich verändernden Anforderungen anzupassen.

Im Objektmodell (z. B. in C#) sind die SYS-Tabellen die einzigen Tabellen, für die eine Repräsentation als POCOs implementiert. APP- und USR-Tabellen existieren hingegen nicht im Source Code, sondern werden dynamisch zur Laufzeit generiert und kompiliert. Die Datenschicht von COFX liest das Metamodell aus und interpretiert es zur Laufzeit. Wenn z.B. im Metamodell bei APP_Timesheet ein TextProperty definiert ist, wird in C# mittels Reflection eine String-Property generiert. Dasselbe gilt auch für DateProperty, NumericProperty und andere unterstützte Datentypen.

Ein entscheidender Vorteil unserer dynamischen Datenschicht ist, dass Änderungen am Datenmodell on-the-fly eingespielt und ausgerollt werden können. Bei klassischen Business-Applikationen ist es oft notwendig, die Software nach Änderungen neu zu kompilieren und auszurollen. Bei time cockpit ist dies nicht der Fall. Dies war ein Grund, warum wir bei der initialen Implementierung kein Framework wie Entity Framework nutzen konnten, da solche Frameworks (zumindest zum Zeitpunkt der Entwicklung von time cockpit) den Source Code neu kompilieren und ausrollen mussten.

Wir haben festgestellt, dass die dynamische Generierung von Objekten uns geholfen hat, verschiedene Anforderungen innerhalb einer zentralen Version zu erfüllen. Dies hat die Komplexität im Release-Management reduziert. Vielleicht lohnt sich dieser Ansatz auch in Ihrer Architektur.

Ein weiterer Vorteil der dynamischen Datenschicht ist die Möglichkeit, kundenspezifische Erweiterungen effizient zu verwalten. Kunden können Erweiterungen haben, die speziell für sie entwickelt wurden. Es gibt zwei Ansätze: entweder individuelle Versionen für jeden Kunden oder eine zentrale Version mit allen Erweiterungen. Beide Optionen sind in der Praxis schwierig zu handhaben und bringen Herausforderungen im Release- und Konfigurationsmanagement mit sich. Dank der dynamischen Datenschicht und der on-the-fly generierten Objekte, deren Klassen nicht im Voraus existieren, konnten wir diese Probleme umgehen.

Für uns hat sich eine Architektur bewährt, die Anpassungen ohne Redeployment ermöglicht. Das bedeutet für uns weniger Unterbrechungen im Betrieb und eine deutlich schnellere Reaktionszeit auf Änderungen oder neue Anforderungen. Wir können Anpassungen direkt und effizient umsetzen, ohne dass Kunden auf neue Versionen warten müssen. Dadurch sparen wir Zeit, reduzieren Kosten für wiederholte Tests und Deployments und bieten unseren Kunden eine nahtlose Nutzungserfahrung. Vielleicht ist ein ähnlicher Ansatz auch für Ihr Projekt hilfreich.

Die Manipulation der Daten erfolgt dynamisch. Statt direkten Code wie timesheet.Description = "foo" zu nutzen, verwenden wir dynamische Methoden wie timesheet.SetMember("Description", "foo") oder für das Auslesen timesheet.Get("Description").

Aber nicht nur Anwendungsdaten können über die Datenschicht eingefügt, geändert und gelöscht werden, sondern auch das Datenmodell selbst kann verändert werden. Tabellen, Eigenschaften, Relationen, Business-Logik, Masken und Listen können zur Laufzeit hinzugefügt und geändert werden. Dadurch ist es in vielen Fällen möglich, time cockpit ohne Programmierung, lediglich durch Scripting und Konfiguration, an die Bedürfnisse unserer Kunden anzupassen – wiederum ohne eine neue Version auszurollen.

Die Möglichkeit, Metadaten und Laufzeitanpassungen zu nutzen, hat uns geholfen, Kundenanforderungen schneller und effizienter umzusetzen. Dadurch können wir flexibel auf individuelle Wünsche reagieren und unsere Kunden profitieren von einer Lösung, die optimal an ihre Bedürfnisse angepasst ist.

Fazit

Die Kombination aus Metamodell und dynamischer Datenschicht macht COFX und damit time cockpit zu einem bewährten Framework für datengetriebene SaaS-Applikationen. Die Flexibilität, sich an unternehmensspezifische Anforderungen anzupassen, hat in unserer langjährigen Praxis einen bedeutenden Unterschied gemacht. Anpassbarkeit verstehen wir dabei nicht nur als technisches Konzept, sondern auch als strategischen Vorteil für eine nachhaltige Produktentwicklung.

Im zweiten Teil dieser Serie wird ein Schwerpunkt auf die eigene Abfragesprache sowie die String Templates von time cockpit gelegt, um weitere Einblicke in die Funktionalität und Nutzen dieses Ansatzes zu geben.