© oatawa/Shutterstock.com
Generieren oder nicht generieren – das ist hier die Frage!

Im Fokus: Codegenerierung


In diesem Artikel geht es um Codegenerierung, warum wir Code generieren müssen und wie es funktioniert. Zunächst möchte ich allgemein beschreiben, warum die Generierung von Code notwendig ist, und auch ein bisschen Theorie einfließen lassen (aber nicht zu viel). Außerdem geht es um die verschiedenen Phasen der Softwareentwicklung, in denen der Quellcode programmatisch generiert werden kann, und ich vergleiche die verschiedenen Ansätze. Nicht zuletzt gehe ich auf die Architektur und die Idee hinter einem spezifischen Tool ein, das in einer bestimmten Phase Code generiert.

Um mit den Worten Shakespeares zu sprechen: Code generieren oder nicht generieren, das ist hier die Frage. Und die Praxis gibt die Antwort, genau wie in Hamlet. Wir generieren Code. Viele Entwickler generieren Code. Auch wenn uns das nicht gefällt. Bei toolgeneriertem Code haben wir ein schlechtes Gefühl. Es fühlt sich unprofessionell oder zumindest nicht optimal an. Aber so ist das Leben. Das meiste ist nicht optimal, und trotzdem müssen wir damit umgehen. So auch bei der automatisierten Codegenerierung.

Warum wir Code generieren

Der Hauptgrund für die automatische Codegenerierung ist, dass uns manchmal nichts anderes übrig bleibt oder einfällt. Die manuelle Codegenerierung kann zu umständlich und fehleranfällig sein oder die Sprache, das Framework oder einfach unsere Erfahrung und unser Wissen erlauben keine simplere Lösung. Und das ist bereits die Quintessenz dieses Artikels, schon ganz am Anfang. Bevor wir uns für die Generierung von Code entscheiden, müssen wir wissen, warum wir ihn überhaupt brauchen.

Keinen Code generieren, außer Sie müssen

Verrückt, oder? Besonders, wenn ich über ein Open-Source-Tool spreche, das genau auf die Generierung von Java-Code ausgerichtet ist. Und trotzdem bin ich der Meinung, dass so viel Code wie möglich manuell geschrieben werden sollte. Leider oder – im Sinne des erwähnten Tools – zum Glück gibt es genug Gelegenheiten, bei denen eine manuelle Codegenerierung keine Option ist oder zumindest die automatisierte Codegenerierung die bessere Option zu sein scheint.

Warum soll man überhaupt Code generieren?

Wenn die beste Option die Generierung von Code zu sein scheint, dann läuft im System etwas falsch oder zumindest suboptimal (Abb. 1):

  • Der Entwickler, der den Code erstellt, ist unterdurchschnittlich.

  • Die Programmiersprache ist unterdurchschnittlich.

  • Die Umgebung oder/und ein Framework sind unterdurchschnittlich.

verhas_codegen_1.tif_fmt1.jpgAbb. 1: Gründe für die Generierung von Code

Sie sollten sich nun nicht angegriffen fühlen. Wenn ich über einen „unterdurchschnittlichen Entwickler“ spreche, meine ich doch nicht Sie. Als Entwickler liegen Sie weit über dem Durchschnitt, nicht zuletzt, weil Sie offen sind und sich für neue Dinge interessieren. Das ist schon dadurch bewiesen, dass Sie diesen Artikel lesen. Wenn Sie jedoch Code schreiben, sollten Sie auch durchschnittliche Hinz-und-Kunz-Entwickler berücksichtigen, die ihr Programm irgendwann in der Zukunft warten müssen. Und durchschnittliche Entwickler haben ein besonderes Merkmal: Sie sind nicht gut. Sie sind auch nicht schlecht, aber, wie der Name schon sagt, sie sind eben durchschnittlich.

Die Legende des unterdurchschnittlichen Entwicklers

Vielleicht passiert Ihnen genau das, was mir vor einigen Jahren passiert ist:

Für die Lösung eines Problems habe ich ein Mini-Framework erstellt. Nicht wirklich ein Framework, wie Spring oder Hibernate, denn ein einzelner Entwickler kann so etwas nicht entwickeln (das hält allerdings einige nicht davon ab, es trotzdem zu versuchen, sogar in einer professionellen Umgebung – was sich widerspricht, denn das ist unprofessionell). Man braucht ein Team. Was ich erstellt habe, war eine einzelne Klasse, die mit ein bisschen „Reflexionszauberei“ Objekte in Karten und wieder zurück konvertiert hat. Zuvor hatten wir die Methoden toMap() und fromMap() in allen Klassen, die diese Funktionalität benötigten. Sie wurden manuell erstellt und gewartet.

Zum Glück musste ich das nicht allein tun und hatte ein Team. Meine Kollegen sagten mir, ich solle doch den von mir geschriebenen Code in die Tonne treten und weiterhin toMap() und fromMap() manuell erstellen. Der Grund dafür ist, dass der Code von den Entwicklern, die nach uns kommen, gewartet werden muss. Und diese kennen wir nicht, ja, es gibt sie ja noch nicht einmal. Sie studieren vielleicht noch. Vielleicht sind sie noch nicht einmal auf der Welt. Eines wissen wir aber: Sie werden durchschnittlich sein, und der von mir erstellte Code erfordert etwas mehr als durchschnittliche Fähigkeiten. Die Wartung der manuell erstellten Methoden toMap() und fromMap() erfordert jedoch lediglich eine durchschnittliche Kompetenz, auch wenn die Wartung fehleranfällig ist. Aber das ist eher ein Kostenproblem, das etwas mehr Investition in die Qualitätssicherung erfordert, aber deutlich weniger Kosten generiert als die Einstellung von Senior-Developer-Assen.

Sie können sich meine zwiespältigen Gefühle vorstellen, da mein brillanter (Achtung, Ironie!) Code zwar abgelehnt, aber dennoch mein Ego gestreichelt wurde. Und ich muss sagen, die Kollegen hatten Recht.

Unterdurchschnittliches Framework

Nun, viele Frameworks sind in diesem Sinne unterdurchschnittlich. Vielleicht ist dieser Ausdruck auch nicht wirklich der beste. Beispielsweise wird Java-Code aus einer WSDL-Datei generiert. Warum generiert das Framework Quellcode anstelle von Java-Bytecode? Dafür gibt es einen guten Grund.

Die Generierung von Bytecode ist komplex und erfordert spezielle Kenntnisse. Und das ist mit Kosten verbunden. Eine Bytecodegenerierungsbibliothek wie Byte Buddy wird benötigt. Für den Programmierer ist es schwieriger, mit dem Code zu debuggen, und es hängt auch ein wenig von der JVM-Version ab. Falls der Code als Java-Quellcode generiert wird – und das gilt auch, wenn es sich um eine spätere Version von Java handelt und das Projekt eine ältere Version verwendet – stehen die Chancen, dass das Projekt den generierten Code irgendwie herabstufen kann, bei einem Java-Code besser als bei einem Bytecode.

Unterdurchschnittliche Sprache

Natürlich sprechen wir hier nicht von Java, denn Java ist die beste Sprache der Welt – es gibt keine bessere. Oder? Wenn jemand behauptet, dass eine Sprache perfekt sei, ignorieren Sie ihn einfach. Jede Sprache hat ihre Stärken und Schwächen. Java ist da nicht anders. Wenn man bedenkt, dass diese Sprache vor über 20 Jahren entworfen wurde und die Rückwärtskompatibilität gemäß der Entwicklungsphilosophie sehr streng gehandhabt wurde, heißt das einfach, dass andere Sprachen in manchen Bereichen besser sein sollten.

Denken Sie an die Methoden equals() und hashCode(), die in der Klasse Object definiert sind und die in jeder Klasse überschrieben werden können. Es gibt nicht viele Neuerungen, was die Überschreibung betrifft. Diese überschriebenen Implementierungen sind eher Standard. Tatsächlich sind sie sogar so standardisiert, dass die integrierten Entwicklungsumgebungen die Generierung von Code für diese Methoden jeweils unterstützen. Warum sollten dann wir Code für die Methoden generieren? Warum sind sie nicht auf deklarative Art und Weise Teil der Sprache? Das sind alles Fragen, auf die es sehr gute Antworten geben sollte, denn es wäre wirklich nicht sehr aufwendig, Dinge wie diese in die Sprache zu implementieren. Aber das passiert einfach nicht. Es hat seinen guten Grund, warum ich nicht der beste Kandidat bin, darüber zu schreiben.

Es gibt noch ein weiteres Beispiel: den Lambdaausdruck. Dieser wurde erst vor kurzem, etwa vor fünf Jahren, in die Sprache eingeführt. Zuvor mussten Programmierer zum Beispiel anonyme Klassen verwenden. Lassen wir die Tatsache beiseite, dass sich die Performance un...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang