Eine redundante Geschichte der Programmierung: Von Parnas bis Scala

Funktionale Programmierung

Von den vielen und mächtigen Konstrukten der funktionalen Programmierung möchte ich nur eines exemplarisch darstellen, das die Auslagerung von Steuerstrukturen ermöglicht. Nehmen wir das alltägliche Beispiel, dass eine Liste von Personen in einem Spezialformat angezeigt werden soll, das mittels Methode getName der Klasse Person zusammengestellt wird. In Java 5 würden wir folgende Funktion benötigen, um eine Liste von Personen in dieses Format umzuwandeln

public List personsToNames(final List persons){
    final List names = new LinkedList();
    for(final Person p: persons){
        names.add(p.getName());
    }
    return names;
}

Die entsprechende Transformation in Scala wäre so knapp ausdrückbar, dass keiner dafür eine eigene Funktion schreiben würde:

persons.map(_.getName)

Das ist möglich, da die Funktion map aus der Scala Collections Library den obigen Algorithmus in allgemeiner Lösung enthält und für jedes Element die ihr übergebene Funktion aufruft. Mittels _ (Unterstrich) wird eine Abbildung von einem anonymen Argument auf den Ausdruck, der den Unterstrich enthält, definiert. Der Typ des Arguments wird aus dem Elementtyp von persons abgeleitet und muss daher nicht explizit angegeben werden. Auf ähnliche Weise würde man in Scala die oben genannte Transaktionsbegleitung garantieren können. Alles was als Transaktion ausgeführt werden soll, müsste zum Beispiel in transaction{…} eingepackt werden, wenn man transaction geeignet definiert. Diese Lösung ist technisch redundanzfrei, wenn auch mit etwas mehr Schreibaufwand verbunden als bei AspectJ. Dafür kommt Scala mit nur einem Minimum von Schlüsselwörtern im Vergleich zu AspectJ aus.

Programmgeneratoren/Domain Specific Languages

Wenn für eine Anwendung hochredundante Codemuster nötig waren, aber die benutzte Programmiersprache keine Möglichkeit bot, sie auszulagern, gab es immer noch ein brutales Mittel: Codegenerierung. Man definierte eine auf das Problem zugeschnittene Spezialsprache, in der man sich redundanzfrei ausdrücken konnte. Daraus generierte man Programmcode. Klassische Beispiele sind Entscheidungstabellengeneratoren wie DETAB/65 oder Parser-Generatoren wie yacc. Als Beispiel sei eine Regel des Parsergenerators ANTLR für Punktrechnung angegeben. Sie bedeutet: Ein Produkt ist eine Folge von Faktoren, die durch ‚*‘ oder ‚/‘ getrennt sind:

product
    :    factor
         ( '*' factor 
         | '/' factor
         )*
    ;

Damit kann ein Parser definiert werden, der Ausdrücke wie a*b/c*d erkennt. Durch das Einstreuen von Aktionen jeweils am Zeilenende kann das zu einem Codegenerator erweitert werden.

Datenhaltung

Auch in der Datenhaltung erzeugen Redundanzen Probleme. Bekanntes Beispiel dafür ist eine Tabelle von Mitarbeitern mit den Spalten ID, Name, Geburtsdatum und Abteilung (Tabelle 1). Wenn die Abteilung als Zeichenkette für jeden Mitarbeiter angegeben ist, verbirgt sich darin eine Redundanz der Daten, woraus die folgenden Probleme erwachsen: 1. Bei einem Tippfehler im Abteilungsnamen kann die Zugehörigkeit zu einer Abteilung nicht mehr automatisch erkannt werden. 2. Eine Umbenennung einer Abteilung erfordert Eingriffe in viele Mitarbeiterzeilen. Die redundanzfreie Lösung besteht in der Verwaltung einer zusätzlichen Tabelle für Abteilungen, auf deren Zeilen mittels einer Abteilungs-ID von jedem Mitarbeiter aus verwiesen wird. Genau das wird durch die Normalisierung nach dem Konzept der relationalen Datenbanken erreicht.

Tabelle 1: Mitarbeiter

D Name Geburtsdatum Abteilung
1 Seyfried, Janina 17.01.1974 Personal
2 Stahl, Georg 06.06.1985 Verkauf
3 Schmidt, Sebastian 26.09.1979 Entwicklung
4 Müller, Friederike 19.11.1987 Verkauf
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.