In meinem letzten Blog Es sind die Daten, Dummchen habe ich die titan Datenbeschreibungssprache UJO Schema vorgestellt. Datenschema sind nicht nur für Datenbankexperten und Systemspezialisten wichtig. Jede Person, die direkt oder indirekt mit dem System arbeitet, sollte die Möglichkeit haben, sich ohne großen Aufwand über die verwendeten Datenstrukturen zu informieren. Nur durch das gemeinsame Verstehen kann ein System konsistent – über einen längeren Zeitraum, mit wechselnden Verantwortlichkeiten und verschiedenen Teams weiterentwickelt werden. Der Aufbau technischer Schuld durch Workarounds wird reduziert oder komplett vermieden und die Stabilität des Systems nicht gefährdet.
Für die Programmierung von Software gibt es statisch und dynamisch typisierte Sprachen. Letztere erlauben, zur Laufzeit beliebige Daten zu erzeugen, ohne ihre Struktur vorher festgelegt und beschrieben zu haben. So ist eine hohe Flexibilität möglich, die jedoch auch Probleme mit sich bringt.
Die Struktur der Daten wird oft nicht oder nicht ausreichend dokumentiert. Um aktuelle Datenstrukturen zu ermitteln, kommen dann reverse Engineering Methoden zum Einsatz. Diese reichen vom Betrachten der Daten selbst bis zur Analyse des Software Quellcodes. Heute werden dafür auch KI-basierte, automatische Analysen diskutiert. Diese Verfahren sind jedoch aufwendig und bei umfangreichen Daten potentiell lückenhaft.
Für titan haben wir uns daher entschieden, die Beschreibungssprache zu typisieren. Es gibt verschiedene Kategorien von Datentypen. Eine davon sind die grundlegenden, unteilbaren Typen. Diese atomaren Typen sind zum Beispiel Zahlenwerte, Texte oder binäre Daten wie Bilder. Eine vollständige Liste atomarer Typenist in der Dokumentation zu finden.
Die einfachste Form eines Schemas ist das Umbenennen eines atomaren Typen.
new_type = int64;
Daten stukturieren
Eine weitere Kategorie sind die zusammengesetzten Typen, die verschiedene unterschiedlichen Typen enthalten können und ihnen Struktur geben. Diese Containerkönnen kombiniert und verschachtelt werden. Komplexe Datenstrukturen lassen sich so als wiederverwendbare Module beschreiben.
Die Liste ist die einfachste Form eines Containers. Sie lässt sich leicht erzeugen, indem hinter den gewünschten Datentype ein *
angegeben wird.
number_list = int64*;
Auf Elemente einer Liste wird über ihre Position oder ihren Index zugegriffen. Manchmal ist es jedoch besser, mit einem festgelegten Wert, einem Schlüssel, auf die Elemente zuzugreifen. Dafür kann ein so genanntes assoziatives Array verwendet werden. Das Schema für ein assoziatives Array erfordert die Festlegung des Schlüsseltyps und des Werttyps.
ages = int32>;
Das Beispiel definiert ein assoziatives Array, das genutzt werden kann, um Namen von Personen mit deren Alter zu kombinieren.
Ein Modell der Welt
Listen und assoziativen Arrays reichen nicht aus, um reale Daten verständlich zu strukturieren. Wie kann man zum Beispiel eine Adresse beschreiben? Damit das funktioniert bietet UJO Schema Records und Objekte.
Records beschreiben eine feste Anzahl Elemente, die in einer bestimmten Reihenfolge strukturiert sind.
address = [
Street = string,
No = int32,
ZIPCode = string,
City = string
];
Ein Objekt definiert festgelegte Schlüssel für die einzelnen Elemente. So spielt die Reihenfolge keine Rolle und Elemente können weggelassen oder hinzugefügt werden. Die Schlüssel müssen jedoch bei der Datenübertragung und Speicherung berücksichtigt werden, was die Datenmenge vergrößert. Das spielt heute auf Servern vielleicht keine große Rolle, kann aber ein limitierender Faktor bei Anwendungen im Internet der Dinge (IoT) sein.
Das Adressbeispiel wird als Objekt wie folgt definiert:
address = {
"Street" -> string,
"No" -> int32,
"ZIPCode" -> string,
"City" -> string
];
Mehr Dynamik
Klar definierte Datentypen sorgen für Sicherheit und Planbarkeit, gehen jedoch auf Kosten der Flexibilität. Soll dynamisch auf Daten, die sich nicht klar definieren lassen, reagiert werden, bietet sich der Datentyp variant
an. In einem als variant
deklarierten Element sind alle unterstützten Datentypen erlaubt.
all_data = variant;
Der variante Typ sollte sparsam genutzt werden, damit keine Mehrdeutigkeiten entstehen wo sie vermieden werden sollten.
Atomare Typen schränken die möglichen Daten stark ein. Damit nicht immer, wenn diese Einschränkung zu streng ist, auf den Typ variant
zurückgegriffen werden muss, können alternative Datentypen angegeben werden. Ist beispielsweise bekannt, dass die Daten in jedem Fall ein Zahl sind, kann dies wie folgt beschrieben werden:
number = (int32, int64, uint32, uint42, float32, float64);
Kombinieren und verschachteln
Beim Erstellen von Datenmodellen ist jetzt Kreativität gefragt. Wirklich mächtig wird ein Schema durch die Kombination von Elementen, Containern und die Wiederverwendung von Strukturen.
Zum Beispiel können Kundendaten durch die Wiederverwendung der bereits oben beschriebenen Adresse strukturiert werden:
person = [
family_name = string,
given_names = string,
address = address
];
company = [
name = string,
address = address,
contacts = person*
];
Für die Firmenadresse in company
wird der gleiche address
Typ benutzt wie für die person
. Da in einer Firma verschiedene Personen arbeiten wird das Feld contacts
mit einer Liste von Personen gefüllt.
Damit sind die Möglichkeiten, Datenstrukturen zu definieren, beschrieben. Im nächsten Blog erkläre ich, wie die Einschränkung von Datentypen funktioniert, damit automatisch auf Abweichungen reagiert werden kann.
Interesse geweckt? – Bald gibt es mehr Infos zu titan. Folge uns auf Twitter @InDevOps_Titan
Hier findest Du das Projekt ujoschema-py