Sonntag, 8. Juni 2008

Generisch vs. generiert

Häufig wird Code gebraucht, der in ähnlicher Form immer wieder auftaucht. Nur in Details unterscheidet er sich. Dies bringt zwei Probleme mit sich: Erstens ist es eine stumpfsinnige und aufwendige Arbeit, ihn zu schreiben und zweitens ist es sehr schwer, ihn zu pflegen, da man dazu die kleinen Unterschiede in all dem Code überblicken muß.

Für stumpfsinnige Arbeiten sind eigentlich Maschinen erfunden worden. Und so haben sich zwei Ansätze etabliert, mit dem Problem umzugehen: generischer und generierter Code.

Generischer Code

Hier wird der immer wiederkehrende Teil von dem, was den Unterschied ausmacht getrennt. Ein allgemein geschriebener Code (Framework) wird über zusätzliche Daten gesteuert. Diese Daten können in einer Datei (heutzutage meist XML) vorliegen oder werden zur Laufzeit gewonnen z.B. durch Reflection auf andere Codeteile oder durch Abfrage des Datenkatalogs einer Datenbank.

Ist das Framework hinreichend ausgereift, kommt man rasch ans Ziel, eine übersichtliche Anwendung zu bekommen. Das Problem ist aber, daß das Framework alle möglichen Spezialfälle berücksichtigen muß, so daß die Konfiguration auch häufig komplizierter ist, als sie im konkreten Fall sein müßte. Wenn Parameter konfiguriert werden müssen, die nur in anderem Zusammenhang notwendig werden, geht dadurch wieder ein Teil der erstrebten Herausstellung der Teile, die variieren, verloren.

Ansonsten wirkt das Framework wie ein Interpreter. Es gibt einen Overhead durch das Interpretieren der Steuerdaten und Probleme werden erst zur Laufzeit sichtbar.

Generierter Code

Bei der Codegenerierung wird ein Werkzeug benutzt, um den sich wiederholenden Code zu erzeugen. Dies geschieht zur Zeit der Erstellung des Codes. Zur Laufzeit verhält sich das System ähnlich wie ein händisch geschriebenes.

Codegenerierung kann im einfachsten Fall aus der Verwendung der Suche/Ersetzen-Funktion des Editors bestehen und im kompliziertesten Fall aus einem kompletten MDA-Ansatz. Je einfacher der Ansatz, desto weniger Gründe gibt es, ihn im Zweifelsfall nicht zu benutzen. Allerdings kann auch ein gut geplanter Einsatz von MDA sich auszahlen.
Eine häufige Frage ist, wie sich generierter mit manuell erstelltem Code zusammenfügt. Hier spielt die Frage eine Rolle, ob bei späteren Änderungen sich die Generierung wiederholen läßt ("Roundtrip"). Auch wenn dies nicht möglich ist, so gewinnt man bei der Erstellung des Codes häufig dennoch soviel Zeit, daß es sich lohnt. Allerdings bleibt dann das Wartungsproblem, da man dann im weiteren den generierten Code warten muß.
Am besten ist es, wenn der generierte Code und der manuell erstellte so getrennt sind, daß die Generierung unabhängig erfolgen kann. Microsoft hat einige Merkmale von C# nur in Hinblick auf dieses Problem eingeführt (z.B. partial classes).
Der Vorteil von Codegenerierung ist, da es sich um eine Art von Compilierung handelt, daß viele Fehler schon zur Zeit der Erstellung entdeckt werden können.

Hybride

Wie auch sonst gibt es zwischen dem reinen Interpreteransatz und dem Compiler Mischlösungen. Z.B. werden in Ruby on Rails die Datenbankzugriffsmethoden zur Laufzeit generiert. D.h. der Aufwand zur Interpretation fällt nur einmal an.

Beispiel Datenbankschnittstelle

Bei den meisten OR-Mapper arbeiten überwiegend interpretierend. Dadurch werden Probleme im Mapping häufig erst zur Laufzeit sichtbar, was zu einem erhöhtem Testbedarf führt. Im Prinzip könnte der Datenbankzugriffscode auch generiert werden, wenn der Generator Zugriff auf eine repräsentative Datenbankinstanz hat. Wenn der Generator funktioniert, gibt es dann keine Probleme mit Schreibfehlern bei Name von Datenbankobjekten mehr. Mit sind allerdings keine Tools bekannt, die diesen Ansatz verwenden, abgesehen kleinerer selbstgeschriebener.

Keine Kommentare: