Unveränderbare Daten als Hilfsmittel für stabilere Software

Der Vorteil der Statik – Immutable Data
Kommentare

Was wäre, wenn Daten sich nie ändern würden? Die Welt wäre statisch und vielleicht langweilig, aber Programmierern würde viel unangenehme Arbeit erspart. Oder ist es vielleicht möglich, Daten trotzdem als unveränderbar zu betrachten?

Daten sind veränderbar. Zumindest im Mainstream der imperativen Programmierung wird das allgemein als selbstverständlich angenommen. In der Realität jedoch sorgt die Veränderbarkeit von Daten für viele Probleme, und Programmierer wenden sich mehr und mehr anderen Ansichtsweisen zu, die die Veränderbarkeit von Daten infrage stellen. In der Welt der funktionalen Programmierung sind Daten traditionell „immutable“, also unveränderbar, und Datenstrukturen möglichst „persistent“. Der Begriff der Persistenz darf hier nicht mit Persistenz im Sinne von Datenspeicherung, etwa in Datenbank- oder Dateisystemen verwechselt werden, sondern er steht im Gegensatz zu „ephemeral“ (etwa als „flüchtig“ oder „kurzlebig“ zu verstehen) Daten.

Die Flucht unterbinden

Hinter der Unterscheidung zwischen persistenten und flüchtigen Daten steckt eine Sichtweise, die sich auf einen bestimmten Algorithmus, eine Funktion, einen Thread oder eine ähnliche Verarbeitungseinheit bezieht. Daten sind persistent, wenn gewährleistet ist, dass sie sich im Rahmen einer Verarbeitungseinheit nicht ändern, und flüchtig, wenn dies nicht gewährleistet ist.

Eine Programmierweise, die nur mit unveränderbaren Daten arbeitet, hat in der Praxis viele Vorteile, die sich schwer im kleinen Beispiel verdeutlichen lassen. Dazu zählen größere Stabilität des Codes, bessere Wartbarkeit, bessere Zuverlässigkeit und ähnliche Konsequenzen, die einem Programmierer erst nach einer gewissen Zeit wirklich bewusst werden. Zu den Vorteilen zählt aber auch eine vereinfachte Verwendung der Datenstrukturen und der damit arbeitenden Algorithmen im Rahmen parallelisierter Programme, und dieser Sachverhalt kann für einige einfache Beispiele genutzt werden.

public class Product {
  public string Name { get; set; }
  public decimal Price { get; set; }
}

public class OrderLine {
  public Product Product { get; set; }
  public int Count { get; set; }

  public decimal GetValue( ) {
    return Product.Price * Count;
  }
}

[TestFixture]
public class Tests {
  [Test]
  public void TestOrderLineValue( ) {
    var product = new Product {Name = "Gummiboot", Price = 16.99m};
    var line = new OrderLine { Product = product, Count = 3 };
    Assert.AreEqual(50.97, line.GetValue( ));
  }
}  

Listing 1 enthält die Deklaration zweier einfacher Klassen Product und OrderLine. Diese sind mit automatischen Properties implementiert, die jedoch, wie für Datenklassen durchaus typisch, mit Getter und Setter versehen und damit änderbar sind. Das Listing enthält weiterhin einen Test, der Instanzen dieser beiden Klassen mit bestimmten Werten erzeugt und dann eine Funktion testet, die den Gesamtwert der OrderLine berechnet. Dieses Beispiel ist weniger komplex als in typischen Geschäftsanwendungen, spiegelt aber dennoch einen Sachverhalt und eine Testimplementation wider, die realitätsnah erscheinen.

Falsche Annahmen

Interessant an diesem Test ist, dass er eine Annahme macht bezüglich der Veränderbarkeit der Daten: „Die Daten in Product und OrderLine werden sich nicht ändern, bevor die Berechnung des Gesamtwertes der OrderLine abgeschlossen ist“. In der kleinen künstlich erzeugten Welt des Tests ist das korrekt, aber außerhalb davon kann dieser Sachverhalt nicht gewährleistet werden. Die Datenstrukturen sind auf solche Weise deklariert, dass die darin gespeicherten Werte geändert werden können. Natürlich kann dies nur geschehen, wenn mehrere parallele Threads im Einsatz sind. In der Dokumentation von Standarddatentypen des .NET Frameworks findet sich aus diesem Grund schon lange ein Eintrag, der besagt, ob eine Datenstruktur als „threadsicher“ zu betrachten ist oder nicht. Threadsicher werden Datenstrukturen dabei im Allgemeinen dadurch, dass sie mithilfe von Locks oder anderen Mechanismen zum Zugriffsschutz den Zugriff einschränken.

Unabhängig von den Überlegungen zur Threadsicherheit wird zunächst klar, dass der Test die korrekte Funktionsweise des Algorithmus‘ zur Wertberechnung nur unter bestimmten künstlichen Bedingungen prüft. Wenn angenommen wird, dass die Daten sich jederzeit ändern können, was angesichts der gewählten Implementation schließlich ganz korrekt wäre, dann müsste entweder der Test, oder die Implementation der Datenstrukturen, oder beides, deutlich komplexer sein, um alle Eventualitäten abzudecken.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -