Grenzen setzen

Bei der Kommunikation zwischen Systemen und Systemkomponeten kommt es zu Fehlern. Häufig sind mehrdeutige oder falsche Daten die Ursache für diese Fehler. Die titan Datenbeschreibungssprache UJO Schema wurde bereits in den Blog-Beiträgen Es sind die Daten, Dummchen! und Typen gibt’s! vorgestellt. Dieser Beitrag erläutert wie man Daten mit UJO Schema eingrenzt, damit Fehler frühzeitig und automatisch erkannt werden.

Es lässt sich nicht ausschließen, dass Fehler in komplexen Systemen auftreten. Unser Ziel ist es also nicht Fehler grundsätzlich zu verhindern. Vielmehr wollen wir mit der strikten Typisierung in UJO Schema

  • Fehler so früh wie möglich erkennen.
  • die negativen Auswirkungen von Fehlern minimieren.
  • Die Fehleranalyse und Behebung erheblich vereinfachen und so die mittlere Zeit bis zur Behebung eines Fehlers (MTR – Mean Time to Repair) reduzieren.

In der Programmiersprache ADA wird die strikte Typisierung eingesetzt, um Mehrdeutigkeiten und Fehler durch unreflektierte Datenstrukturen zu minimieren. Da ADA für den Einsatz in militärischen Systemen entwickelt wurde ist die Notwendigkeit dafür sicher leicht nachvollziehbar.

A type is used to reason about the objects a program manipulates (an object is a variable or a constant). The aim is to classify objects by what you can accomplish with them (i.e., the operations that are permitted), and this way you can reason about the correctness of the objects’ values.
https://learn.adacore.com/courses/intro-to-ada/chapters/strongly_typed_language.html

Daten einschränken

Damit das gelingt werden Daten auf auschließlich gültige Werte eingeschränkt. Das titan-System kann so falsche Daten identifizieren, melden und die weitere Verarbeitung stoppen. Eine umständliche Fehlersuche entfällt. Werden Daten für die Steuerung von Aktoren wie zum Beispiel Motoren genutzt, hilft die Überprüfung sogar dabei Schäden durch falsche Daten zu verhindern.

mytype = int
    : 
    : 
    : <...>
    : ;

Das obere Beispiel zeigt, wie Einschränkungen einer Typdefinition angefügt werden.

Zahlen und Wertebereiche

Die wohl häufigste Einschränkung bezieht sich auf die möglichen Werte, die ein Datenfeld annehmen kann. Dabei werden entweder die Werte konkret angegeben oder Bereiche definiert. Das verwendete Schlüsselwort für diese Einschränkung ist in.

Definiert man in (1, 2, 3, 4) sind nur die angegeben Werte gültig. Die Festlegung in (1 .. 4) ist gleichwertig und legt fest, dass alle Werte von 1 bis 4 gültig sind. Manchmal möchte man nur den maximal oder minimal möglichen Wert angeben. Zum Beispiel legt in (.. 20) den maximal möglichen Wert auf 20 fest. Kleinere Werte sind uneigeschränkt erlaubt. Die Einschränkung in (-18 ..) legt den kleinsten möglichen Wert auf -18 fest.

Kombiniet man diese Möglichkeiten können in einer einzigen Einschränkung verschiedene gültige Wertebereiche und Werte festgelegt werden.

mytype = int32
    : in (.. -18, 1, 2, 3, 4, 10..15, 20..25, 50 ..);

Das Beispiel erlaubt Werte kleiner als -18 oder größer als 50, die festen Werte 1,2,3 und 4, Werte zwischen 10 und 15 sowie 20 und 25. Alle anderen Werte sind nicht erlaubt und führen zu Fehlern bei der Prüfung.

Natürlich können Werte und Wertebereiche auch für Fließkommazahlen (float) festgelegt werden.

constants = float32
    : in (2.71, 3.14, 9.81);

Das Beispiel erlaubt nur einige Konstanten aus Mathematik und Physik.

Auch wenn die Einschränkung in bereits eine sehr genaue Festlegung des Wertebereichs erlaubt ist es manchmal einfacher zu definieren was nicht enthalten sein soll. Um das zu erreichen die Einschränkung not in verwendet.

Zum Beispiel können für die Festlegung von Grad Celsius folgende Beschreibungen verwendet werden.

gradCelsiusA = float32
    : in (-273.15 ..);

gradCelsiusB = float32
    : not in (.. -273.15);

Worte, nichts als Worte

Mit der Einschränkung in werden auch für Texte gültige Wortlisten definiert. Für die Farbnamen in einem Kartenspiel würde zum Beispiel ein eingeschränkter Datentyp wie folgt beschrieben.

kartenFarben = string
    : in ("Herz", "Kreuz", "Pik", "Karo");

Für die Festlegung der Textlänge wird die Einschränkung length verwendet. Die Länge kann entweder als feste Anzahl Zeichen sein, variabel mit maximalen und minimalen Werten eingeschränkt werden. Die einschränkung length (.. 50) definiert eine maximale Länge von 50 Zeichen. Gibt man length ( 10 ..) an, müssen mindestend 10 Zeichen vorhanden sein. Mit length (10..50) sind mindestend 10 Zeichen erforderlich, aber maximal 50 möglich.

Listen einschränken

Wenden wir in und length auf Listen an, wirken sich die Einschränkungen auf alle Elemente der Liste aus. Es können sogar Texte und Zahlen kombiniert werden.

mixListe = (int32, string)*
    : in (1..20)
    : in ("Karo", "Herz", "Pik", "Kreuz")
    : length ( ..10 );

In dem Beispiel dürfen maximal 10 Elemente in einer Liste vorhanden sein. Die enthaltenen Texte werden auf die Kartenfarben festgelegt. Als Zahlenwerte sind nur 1 bis 20 zulässig.

Es ist zu beachten, dass die Einschränkung length sich hier nicht auf die Länge der Texte, sondern auf die Länge der Liste bezieht. Die Textlänge kann mit Hilfe eines weiteren eigenen Datentyps eingeschränkt werden, wie folgendes Beispiel zeigt.

shortText = string
    : length (..100);

mixListe = (int32, shortText)*
    : in (1..20)
    : in ("Herz", "Kreuz", "Pik", "Karo")
    : length ( ..10 );

Weniger als nichts

Grundsätzlich können Datenfelder beliebiger Typen undefiniert sein. Um diesen Zustand der Abwesenheit von Daten zu kennzeichnen wird das Schlüsselwort nullverwendet, damit der Unterschied zum Wert 0 klar erkennbar ist. Falls es erforderlich ist auf jeden Fall gültige Daten zu erzwingen, weil sonst ein unklarer Systemzustand entsteht, wird dies mit der Einschränkung not null erreicht.

Manchmal reicht es auch aus einen speziellen Wert zu setzen, wenn keine echten Daten vorhanden sind. Mit dem optionalen Schlüsselwort default kann dieser für die Einschränkung not null gesetzt werden. Das System kann dann automatisch nicht vorhandene Daten durch Defaultwerte ersetzen.

noNull = int32
    : not null default 0;

Das Beispiel zeigt einen Datentyp der immer Daten enthalten muss. Sollten keine Daten vorhanden sein wird der Wert 0 angenommen.

Fazit

Im titan Projekt prüfen wir die Anwendung von UJO Schema. Es hat sich bereits gezeigt, dass zukünftig noch weitere Einschränkungen den Umgang mit Daten erleichern könnten.

Reguläre Ausdrücke für Prüfungen, ob Textfelder korrekt formatiert sind und zum Beispiel eine E-Mail Adresse enthalten könnten, helfen die Korrektheit von Daten weiter zu verbessern.

Eine ebenfalls bereits diskutierte Idee ist die Verwendung von Einheiten für technische Werte. Besonders im Internet of Things (IoT) könnten klar definierte Einheiten ein System in die Lage versetzen automatische Konvertierungen und Umrechnungen vorzunehmen.

In meinem nächsten Blog geht es um die Verwendung von UJO Schema als Werzeug für die Dokumentation von Daten.

Interesse geweckt? – Bald gibt es mehr Infos zu titan. Folge uns auf Twitter @InDevOps_Titan

Hier findest Du das Projekt ujoschema-py