Sonntag, 15. März 2009

Nichts als Problem

Das Nichts zeichnet sich durch das Fehlen aller Dinge aus. Ein Physiker würde vielleicht sogar unterscheiden zwischen dem Nichts, bei dem es nicht mal die Dimensionen eines Raumes gibt, und dem Vakuum, dem leeren Raum. Die alten Philosophen waren der Meinung, daß die Natur immer versucht, diese Lehre zu vermeiden. Sie sprachen vom Horror Vacui. Auch dem Informatiker kann das Fehlen von Daten manchmal Angst bereiten. Es gibt zwei Probleme mit fehlender Information: was bedeutet sie und wie stellen wir sie dar.

Interpretation von fehlender Information

Es kann drei Gründe geben, warum eine bestimmte Information ein Datensatz nicht vorhanden ist:

  1. Die Information ist nicht anwendbar. Zum Beispiel ist es den deutschen Adressen nicht üblich, das Bundesland anzugeben, während bei amerikanischen Adressen der Staat zugehört. Somit muß eine korrekte Modellierung einer Adresse erlauben, daß für deutsche Adressen das Feld Staat leer bleibt.
  2. Information ist (noch) nicht bekannt. Die Situation tritt auf, wenn ein Datensatz schon angelegt wird, aber einige Daten erst in späteren Schritten der Bearbeitung anfallen.
  3. Der leere Wert ist Information. Wenn die Bestellungen im Restaurant erfaßt werden soll und es je ein Feld für Speise und Getränk gibt, und dafür Getränk leer bleibt, so bedeutet das, daß der Gast kein Getränk bestellt hat.

Fehlende Information in Datenbanken

Bei der Modellierung von Datenbanken unterscheidet man zwischen optionalen und Pflichtfeldern. Nur bei Ersteren darf die Information fehlen. Fehlt Information in einem Pflichtfeld, so verhindert die Datenbank das Einfügen eines solchen Datensatzes. Was eine Datenbank in der Regel nicht macht, ist die Unterscheidung zwischen leerer und nicht vorhandener Information. Das heißt, es ist nicht möglich, einen Text von der Länge Null abzuspeichern.

Bei der Verwendung von optionalen Feldern sollte man beachten, daß die Suche nach leeren Feldern in der Regel sehr aufwendig ist, da sich nicht vorhandene Information nicht indizieren läßt.

Es ist durchaus möglich, eine relationale Datenbank auch so zu modellieren, daß es ausschließlich Pflichtfeld ergibt. Dies geschieht, indem man optionale Information in gesonderte Tabellen ausgelagert. Für ein einzelnes Feld ist das in der Regel nur theoretisch interessant. Wenn aber eine Gruppe von Feldern nur gemeinsam auftreten oder fehlen kann, ist die Auslagerung die sauberste Modellierung. Wenn die Daten ausschließlich gemeinsam verwendet werden, kann eine Einbuße bei der Zugriffsgeschwindigkeit bei vielen Datenbanken verhindert werden, indem man die beiden Tabellen clustert.

Fehlende Information in Objekten

Solange alles aus Objekten besteht, so wird fehlende Information in einem Objekt durch das Fehlen von Referenzen zu anderen Objekten dargestellt. Diese Darstellung hat eine große Ähnlichkeit mit der oben für Datenbanken vorgeschlagenen Modellierung zur Vermeidung optionaler Felder. Wenn nun versucht wird, über diese Referenz auf das Objekt zuzugreifen, so kommt es zu einem Fehler. In Java ist das die berüchtigte NullPointerException - ein komischer Name bei einer Sprache, die doch versprochen hat im Gegensatz zu C ohne Pointer auszukommen. Für den Entwickler bedeutet das, daß er vor jeder Verwendung eines referenzierten Objekts auch überprüfen muß, ob es wirklich existiert. Das zu vergessen ist wohl der häufigste Programmierfehler überhaupt in objektorientierter Programmierung.

Die Prüfung auf fehlende Referenzen ist ein Fall von extremer Codewiederholung. Wiederholung von Code sollte aber immer vermieden werden. Eine Möglichkeit, die Behandlung der fehlenden Information an genau einer Stelle zu konzentrieren, ist die Einführung von Objekten, die die fehlende Information repräsentieren. Das heißt, es wird ein neues Objekt definiert, daß sich von dem an dieser Stelle erwarteten ableitet und das verwendet wird, wenn die Information nicht vorhanden ist. Die Methoden werden so überschrieben, daß sie bei Aufruf die Behandlung durchführen, die sonst verteilt im Code passieren würden, wenn ein leerer Wert auftritt. Beispielsweise ist es häufig sinnvoll, bei der Ausgabe von leerer Information eine leere Zeichenkette zu verwenden. Also würde eine Funktion toString eben diese zurückgeben. Eine Addition eines nicht vorhandenen Wertes mit etwas beliebig anderem sollte meist wiederum einen nicht vorhandenen Wert ergeben. Auf diese Weise wird eine konsistente Behandlung der fehlenden Information erreicht.

Ein weiterer Vorteil dieses Vorgehens ist, daß die Möglichkeit besteht, für die oben erwähnten unterschiedlichen Interpretationen von fehlender Information unterschiedliche Repräsentationen zu haben, die entsprechend der Interpretation anders reagieren können.

Zeichenketten können fehlen oder leer sein. Wenn die Daten in einer Datenbank abgelegt werden sollen, so empfiehlt es sich, nur eine der beiden Darstellungen zu verwenden. Nach dem eben gesagten, würde ich die leer Zeichenkette vorziehen.

In Java, C# und C++ gibt es neben Objektreferenzen auch primitive Typen (Zahlen, Wahrheitswerte und Datumsangaben). Diese besitzen keine offensichtlichen Möglichkeiten mitdem Fehlen der Information umzugehen. Häufig werden als Ausweg „magische“ Werte verwendet. So kann eine negative Zahl oder ein bestimmtes Datum (z.B. 1.1.1970) für das Fehlen des Wertes stehen. Dies ist recht unschön. Eine andere Möglichkeit besteht bei Java und C# darin, grundsätzlich die auch vorhandene Objektrepräsentation der Werte zu verwenden (Integer statt int). Dies führt aber zu Performanceeinbußen, da der Compiler uns ja schon gesagt hat, daß er nicht bereit ist, intern die Verwendung der verschiedenen Darstellungen zu optimieren. In älteren Java-Versionen, die noch kein Auto(un)boxing kennen, führt das auch zu sehr unschönem Code.

C# hat ab Version 2.0 den Nullable-Wrapper eingeführt. Dieser wird von den Datentypen verwendet, deren Name mit „?“ endet, wie z.B. int?. Dies erleichtert insbesondere die Kommunikation mit Datenbanken erheblich. In anderen Programmiersprachen läßt sich so etwas leicht nachbilden.

Fehlende Information in XML

In XML muß man zuerst unterscheiden zwischen einen leeren Tag (<tag></tag>) und einem fehlenden Tag. Wenn ein XML-Schema verwendet wird, so muß das entsprechende Element im ersten Fall leere Zeichenketten zulassen (<minLength value=“0“/>) und im zweiten Fall als optional gekennzeichnet sein (minOccurs=“0“). Ein gutes Schema sollte sich um eine einheitliche Darstellung bemühen. Alles andere führt bei der Verwendung der XML-Dokumente in Schnittstellen zu endlosen Diskussionen. Persönlich würde ich in der Regel leere Tags zu vermeiden suchen, da es einige XML-APIs gibt, bei denen diese wesentlich schwieriger zu handhaben sind wie optionale Tags. Bei der Serialisierung von Daten in XML müssen dann nämlich nicht nur die Daten betrachtet werden, sondern auch das Schema, denn die fehlenden Daten können nicht das Erstellen des leeren Tags auslösen (sie fehlen ja). Dies muß über die Schemadefinition gehen.

Zusätzlich gibt es noch eine dritte, in meinen Augen etwas obskure, Methode in XML mit fehlender Information umzugehen: nillable. Hier ein Beispiel direkt von der W3C-Website geklaut:

<xsd:element name="shipDate" type="xsd:date" nillable="true"/>
<shipDate xsi:nil="true"></shipDate>

Elemente, die keine Information haben, bekommen hier also das Attribut xsi:nil=”true”. Wozu das gut sein soll, muß mir noch mal jemand erklären. Eigentlich zeigt ja schon das leere Tag, daß da nichts ist. Diese Darstellung wird nur selten benutzt; daher kann man sich auch nicht darauf verlassen, daß jede API sie unterstützt. Falls es nicht sehr, sehr gute Gründe gibt, sollte man von der Verwendung absehen.

Ausweichverhalten des Benutzers

In zahlreichen Anwendungen findet man Eingabefelder, die einen Wert verpflichtend erwarten. Wenn man aber nachher in die wirklich erfaßten Daten schaut, so findet man, daß dort meist nur ein Punkt („.“) oder ein „x“ stehen. Dies bedeutet, daß das Feld für die Bearbeitung nicht wirklich relevant ist und die Benutzer die genannten Werte als Ersatzdarstellung für fehlende Information verwenden. Dies erhöht die Nutzbarkeit der Daten nicht gerade. In diesem Fall sollte eine Änderung der Datenmodellierung erwogen werden, die diese Felder optional macht.

Und die Lehre von der Geschicht …

Fehlende Information kann unterschiedlich interpretiert werden. Die verschiedenen Techniken, die wir zur Erstellung einer Anwendung verwenden, haben unterschiedliche und nur beschränkt miteinander kompatible Darstellungen dafür. Wenn man keine klare Strategie hat, wie man damit umgehen will, handelt man sich jede Menge von Ärger ein. Leider wird dieses Problem von den meisten Softwarearchitekten sträflich ignoriert. Die Entwickler kommen dann mit einer Vielzahl von meist ad hoc gefundenen Lösungen und bei der Integration kommt es zu teuren aber vermeidbaren Problem.

Keine Kommentare: