Code Generatoren oder T4 Templates, sind sie wirklich böse?

8

Ich habe gehört, dass Codegeneratoren und T4-Vorlagen nicht verwendet werden sollten. Die Logik dahinter ist, dass, wenn Sie Code mit einem Generator generieren, es eine bessere Möglichkeit gibt, den Code durch Generics und Templating zu erstellen.

Obwohl ich mit dieser Aussage oben ein wenig einverstanden bin, habe ich nicht wirklich effektive Wege gefunden, um Templates zu erstellen, die sagen können, dass sie sich zum Beispiel selbst instantiieren. Mit anderen Worten kann ich nie tun:

%Vor%

Außerdem, wenn ich Code basierend auf Datenbankwerten erzeugen möchte, habe ich festgestellt, dass die Verwendung von Microsoft.SqlServer.Management.SMO in Verbindung mit T4-Vorlagen wunderbar große Mengen an Code erzeugen kann, ohne dass man Copy / Paste oder Resharper verwenden muss.

Viele der Probleme, die ich bei Generics gefunden habe, sind zu meinem Schrecken auch viele Entwickler, die sie nicht verstehen. Wenn ich Generika für eine Lösung untersuche, gibt es Zeiten, in denen es kompliziert wird, weil C # angibt, dass Sie etwas nicht tun können, was mir logisch erscheint.

Was sind deine Gedanken? Ziehen Sie es vor, einen Generator zu bauen, oder bevorzugen Sie Generika? Wie weit können Generika gehen? Ich kenne eine ordentliche Menge über Generika, aber es gibt Fallen und Fallstricke, auf die ich immer stoße, die mich dazu veranlassen, auf eine T4-Vorlage zurückzugreifen.

Was ist der richtige Weg für Szenarien, in denen Sie viel Flexibilität benötigen? Oh und als Bonus auf diese Frage, was sind gute Ressourcen für C # und Generics?

    
jwendl 07.02.2009, 18:24
quelle

15 Antworten

15

Sie können neue T (); wenn du das tust

%Vor%

Wie für Code-Generatoren. Ich benutze jeden Tag ohne Probleme. Ich benutze gerade jetzt: -)

Generics lösen ein Problem, Codegeneratoren lösen ein anderes Problem. Erstellen Sie z. B. ein Geschäftsmodell mithilfe eines UML-Editors, und generieren Sie dann Ihre Klassen mit Persistenzcode, so wie ich es die ganze Zeit über dieses Tool konnte mit Generika nicht erreicht werden, da jede persistente Klasse völlig anders ist.

Wie für eine gute Quelle für Generika. Das Beste muss natürlich Jon Skeets Buch sein! : -)

    
Peter Morris 07.02.2009, 18:51
quelle
12

Als Urheber von T4 musste ich diese Frage einige Male verteidigen, wie Sie sich vorstellen können: -)

Ich bin überzeugt, dass die Code-Generierung in ihrer besten Form ein Schritt auf dem Weg zur Herstellung eines gleichwertigen Werts ist, indem wiederverwendbare Bibliotheken verwendet werden.

Wie viele andere bereits gesagt haben, besteht das Schlüsselkonzept zur Aufrechterhaltung von DRY niemals darin, generierten Code jemals manuell zu ändern, sondern vielmehr Ihre Fähigkeit zu regenerieren, wenn sich die Quellmetadaten ändern oder Sie einen Fehler im Codegenerator finden. An diesem Punkt hat der generierte Code viele Eigenschaften des Objektcodes und es treten keine Copy / Paste-Probleme auf.

Im Allgemeinen ist es viel weniger Aufwand, einen parametrisierten Codegenerator zu erstellen (besonders bei vorlagenbasierten Systemen), als eine qualitativ hochwertige Basisbibliothek zu entwickeln, die die Benutzungskosten auf das gleiche Niveau senkt, so dass es schnell geht Möglichkeit, Konsistenz zu erhalten und Wiederholungsfehler zu entfernen.

Ich glaube jedoch immer noch, dass das fertige System meistens durch weniger Code verbessert werden würde. Nicht zuletzt würde sein Speicherbedarf fast immer deutlich kleiner sein (obwohl die Leute dazu neigen, Generika in dieser Hinsicht als kostenlos zu betrachten, was sie ganz sicher nicht sind).

Wenn Sie mit Hilfe eines Code-Generators einen Wert realisiert haben, dann kauft Ihnen das oft Zeit oder Geld oder einen guten Willen, um in das Ernten einer Bibliothek aus der generierten Codebasis zu investieren. Sie können dann den Code-Generator inkrementell neu ausrichten, um die neue Bibliothek zu targetieren und hoffentlich viel weniger Code zu generieren. Spülen und wiederholen.

Ein interessanter Kontrapunkt, der mir gemacht wurde und der in diesem Thread auftaucht, ist, dass reiche, komplexe, parametrische Bibliotheken nicht die einfachste Sache in Bezug auf die Lernkurve sind, besonders für diejenigen, die nicht tief in die Plattform eingetaucht sind. Wenn man bei der Codegenerierung auf einfacheren Grundgerüsten bleibt, kann man einen ausführlichen Code erzeugen, der aber oft recht einfach und leicht zu lesen ist.

Natürlich, wo Sie eine große Varianz und extrem umfangreiche Parametrisierung in Ihrem Generator haben, können Sie einfach die Komplexität Ihres Produkts für Komplexität in Ihren Templates eintauschen. Dies ist ein einfacher Weg, in den man hineinrutschen kann und der Wartung kann genauso Kopfschmerzen bereiten - darauf achten.

    
GarethJ 04.06.2011 20:21
quelle
8

Generieren von Code ist nicht böse und riecht nicht! Der Schlüssel ist, den richtigen Code zur richtigen Zeit zu generieren. Ich denke T4 ist großartig - ich benutze es nur gelegentlich, aber wenn ich es tue, ist es sehr hilfreich. Zu sagen, bedingungslos, dass das Generieren von Code schlecht ist, ist unbedingt verrückt!

    
rp. 07.02.2009 20:19
quelle
6

Ein guter Prozentsatz von dem, was in Visual Studio 2010 ist, wäre ohne Code-Generierung nicht möglich. Entity Framework wäre nicht möglich. Das einfache Ziehen und Ablegen eines Steuerelements auf ein Formular wäre nicht möglich, und Linq. Zu sagen, dass die Codegenerierung nicht verwendet werden sollte, ist seltsam, da so viele es benutzen, ohne darüber nachzudenken.

    
Jerry Lanphear 12.04.2012 00:40
quelle
5

Es scheint mir, dass Code-Generatoren in Ordnung sind, solange die Code-Generierung Teil Ihres normalen Build-Prozesses ist, anstatt etwas, das Sie einmal ausführen und dann seine Ausgabe behalten. Ich füge diesen Vorbehalt hinzu, denn wenn Sie den Code-Generator nur einmal verwenden und die Daten, die ihn erstellt haben, verwerfen, erzeugen Sie automatisch einen massiven DRY-Verstoß und Wartungskopfschmerz. während das Generieren des Codes jedes Mal effektiv bedeutet, dass alles, was Sie zum Generieren verwenden, der echte Quellcode ist und die generierten Dateien nur Zwischenkompilierungsstufen sind, die Sie meistens ignorieren sollten.

Lex und yacc sind klassische Beispiele für Tools, mit denen Sie Funktionalität auf effiziente Weise spezifizieren und daraus effizienten Code generieren können. Wenn Sie versuchen, Ihre Aufträge von Hand auszuführen, wird sich Ihre Entwicklungszeit verlängern und es wird wahrscheinlich weniger effizienter und weniger lesbarer Code produziert. Und während Sie natürlich etwas wie lex und yacc direkt in Ihren Code einbinden können und ihre Aufgaben zur Laufzeit statt zur Kompilierzeit erledigen können, würde das Ihren Code sicherlich erheblich komplizierter machen und ihn verlangsamen. Wenn Sie Ihre Spezifikation zur Laufzeit tatsächlich ändern müssen, lohnt es sich vielleicht, aber in den meisten normalen Fällen ist die Verwendung von lex / yacc, um Code zur Kompilierzeit für Sie zu generieren, ein großer Gewinn.

    
Sol 07.02.2009 20:41
quelle
3

Vielleicht ist es ein bisschen hart, aber für mich riecht Code Generation.

Diese Codegenerierung bedeutet, dass es zahlreiche zugrundeliegende allgemeine Prinzipien gibt, die in einer "Wiederhole dich nicht" -Mode ausgedrückt werden können. Es kann ein wenig länger dauern, aber es ist befriedigend, wenn Sie mit Klassen enden, die nur die Bits enthalten, die sich wirklich ändern, basierend auf einer Infrastruktur, die die Mechanik enthält.

Was Generics betrifft ... nein, ich habe nicht zu viele Probleme damit. Das einzige, was momentan nicht funktioniert, ist das zu sagen.

%Vor%

Aber selbst das wird in der nächsten Version von C # möglich sein.

    
flq 07.02.2009 18:59
quelle
2

Mehr Code bedeutet mehr Komplexität. Mehr Komplexität bedeutet mehr Platz für Bugs, die sich verstecken, was längere Fixierungszyklen bedeutet, was wiederum höhere Kosten während des gesamten Projekts bedeutet.

Wenn möglich, bevorzuge ich es, die Menge an Code zu minimieren, um eine äquivalente Funktionalität bereitzustellen; idealerweise mit dynamischen (programmatischen) Ansätzen anstelle von Code-Generierung. Reflektion, Attribute, Aspekte und Generika bieten viele Optionen für eine DRY-Strategie und lassen die Generierung als letzten Ausweg zurück.

    
Morendil 07.02.2009 18:55
quelle
2

Codegenerierung ist für mich eine Umgehungslösung für viele Probleme in Sprache, Frameworks usw. Sie sind nicht von sich aus böse, ich würde sagen, dass es sehr, sehr böse (dh böse) ist, eine Sprache (C #) und ein Framework zu veröffentlichen zwingt Sie zum Kopieren und Einfügen (Austauschen von Eigenschaften, Auslösen von Ereignissen, Fehlen von Makros) oder Verwenden von magischen Zahlen (wpf-Bindung).

Also, ich weine, aber ich benutze sie, weil ich muss.

    
greenoldman 02.06.2011 08:33
quelle
2

Ich habe T4 für die Code-Generierung und Generics verwendet. Beide sind gut, haben Vor- und Nachteile und sind für verschiedene Zwecke geeignet.

In meinem Fall verwende ich T4, um Entities, DAL und BLL basierend auf einem Datenbankschema zu generieren. DAL und BLL verweisen jedoch auf ein Mini-ORM, das ich basierend auf Generics und Reflection gebaut habe. Ich denke also, du kannst sie nebeneinander benutzen, solange du die Kontrolle behältst und sie klein und einfach hältst.

T4 generiert statischen Code, während Generics dynamisch ist. Wenn Sie Generics verwenden, verwenden Sie Reflection, von der gesagt wird, dass sie weniger performant ist als eine "fest codierte" Lösung. Natürlich können Sie Reflexionsergebnisse zwischenspeichern.

Bezüglich "return new T ();" verwende ich dynamische Methoden wie folgt:

%Vor%

Dann nenne ich es so:

%Vor%     
Nathan 22.11.2011 07:20
quelle
1

Generika und Codegenerierung sind zwei verschiedene Dinge. In einigen Fällen könnten Sie Generika anstelle von Code-Generierung verwenden und für diejenigen, die Sie glauben, sollten Sie. Für die anderen Fälle ist die Codegenerierung ein mächtiges Werkzeug.

Für all die Fälle, in denen Sie einfach Code basierend auf Dateneingaben generieren müssen, ist die Codegenerierung der richtige Weg. Das offensichtlichste, aber keineswegs das einzige Beispiel ist der Formulareditor in Visual Studio. Hier ist die Eingabe die Designerdaten und die Ausgabe ist der Code. In diesem Fall ist Generika wirklich keine Hilfe, aber es ist sehr schön, dass VS den Code basierend auf dem GUI-Layout einfach generiert.

    
Brian Rasmussen 07.02.2009 19:20
quelle
1

Code-Generatoren könnten als ein Code-Geruch betrachtet werden, der auf einen Fehler oder eine fehlende Funktionalität in der Zielsprache hinweist.

Zum Beispiel, während hier gesagt wurde, dass "Objekte, die persistieren, nicht verallgemeinert werden können", wäre es besser, sie als "Objekte in C #, die automatisch persistieren, ihre Daten können nicht in C # verallgemeinert werden" zu verstehen Ich kann sicherlich in Python durch den Einsatz verschiedener Methoden.

Der Python-Ansatz könnte jedoch in statischen Sprachen durch Verwendung von operator [] (Methodenname als String) emuliert werden, wobei je nach Bedarf entweder ein Funktor oder eine Zeichenkette zurückgegeben wird. Leider ist diese Lösung nicht immer anwendbar, und die Rückgabe eines Funktors kann ungünstig sein.

Der Punkt, den ich mache, ist, dass Code-Generatoren einen Fehler in einer gewählten Sprache anzeigen, die durch Bereitstellung einer bequemeren spezialisierten -Syntax für das spezifische Problem adressiert werden.

    
Arafangion 03.06.2009 02:18
quelle
1

Das Kopieren / Einfügen von generiertem Code (wie ORMs) kann auch sehr nützlich sein ...

Sie können Ihre Datenbank erstellen und anschließend vom ORM eine Kopie dieser Datenbankdefinition in Ihrer bevorzugten Sprache erstellen lassen.

Der Vorteil kommt, wenn Sie Ihre ursprüngliche Definition (die Datenbank) ändern, drücken Sie auf Kompilieren und der ORM (wenn Sie einen guten haben) kann Ihre Kopie der Definition neu generieren. Nun können alle Verweise auf Ihre Datenbank vom Compiler-Typ-Checker überprüft werden und Ihr Code wird nicht kompiliert, wenn Sie nicht mehr vorhandene Tabellen oder Spalten verwenden.

Denken Sie darüber nach: Wenn ich eine Methode einige Male in meinem Code anrufe, beziehe ich mich nicht auf den Namen, den ich dieser Methode ursprünglich gegeben habe? Ich wiederhole diesen Namen immer und immer wieder ... Sprachdesigner erkannten dieses Problem und entwickelten "Typ-Sicherheit" als Lösung. Die Kopien nicht entfernen (wie DRY vorschlägt), sondern stattdessen auf Korrektheit prüfen.

Der ORM-generierte Code bringt dieselbe Lösung, wenn er sich auf Tabellen- und Spaltennamen bezieht. Entfernen Sie nicht die Kopien / Referenzen, sondern bringen Sie die Datenbankdefinition in Ihre (typsichere) Sprache, in der Sie stattdessen auf Klassen und Eigenschaften verweisen können. Zusammen mit der Compiler-Typprüfung löst dies ein ähnliches Problem auf ähnliche Weise: Garantiere Fehler bei der Kompilierung anstelle von Runtime-Fehlern, wenn Sie auf veraltete oder falsch geschriebene Tabellen (Klassen) oder Spalten (Eigenschaften) verweisen.

    
Renko 28.09.2011 18:57
quelle
1

Zitat: Ich habe nicht wirklich effektive Wege gefunden, um Templates zu erstellen, die sich zum Beispiel selbst instanziieren können. Mit anderen Worten kann ich nie tun:

gib ein neues T ();

zurück %Vor%     
Renko 28.09.2011 19:15
quelle
0

Code-Generierung, wie Generika, Vorlagen und andere solche Verknüpfungen, ist ein mächtiges Werkzeug. Und wie bei den meisten leistungsfähigen Werkzeugen, verstärkt es die Fähigkeit seines Anwenders zum Guten und zum Bösen - sie können nicht getrennt werden.

Wenn Sie also Ihren Code-Generator gründlich verstehen, antizipieren Sie alles, was er erzeugt, und warum, und beabsichtigen Sie, dies aus berechtigten Gründen zu tun, dann haben Sie es. Aber benutze es nicht (oder irgendeine andere Technik), um dich an einem Ort vorbei zu bringen, an dem du nicht sicher bist, wohin du unterwegs bist oder wie du dorthin kommst.

Einige Leute denken, dass wenn Sie Ihr aktuelles Problem gelöst und ein bestimmtes Verhalten implementiert haben, Sie golden sind. Es ist nicht immer offensichtlich, wie viel Grausigkeit und Undurchsichtigkeit Sie auf Ihrer Spur für den nächsten Entwickler hinterlassen (der Sie selbst sein könnte.)

    
dkretz 07.02.2009 19:37
quelle
-1

Warum ist es wirklich akzeptabel, wirklich schnell kopieren und einfügen zu können?

Das ist die einzige Rechtfertigung für die Code-Generierung, die ich sehen kann.

Auch wenn der Generator die gesamte Flexibilität bietet, die Sie benötigen, müssen Sie immer noch lernen, wie Sie diese Flexibilität nutzen - was noch eine weitere Ebene des Lernens und Testens erfordert.

Und selbst wenn es in der Zeit null läuft, bläht es immer noch den Code auf.

Ich habe meine eigene Datenzugriffsklasse gerollt. Es weiß alles über Verbindungen, Transaktionen, gespeicherte Prozessparmen, usw., und ich musste nur alle ADO.NET-Sachen einmal schreiben.

Es ist jetzt so lange her, dass ich irgendetwas mit einem Verbindungsobjekt darin schreiben (oder sogar ansehen) musste, dass ich mich schwer daran gewöhnen müsste, die Syntax auswendig zu kennen.

    
ChrisA 07.02.2009 19:11
quelle

Tags und Links