Vor kurzem bin ich auf das Framework von Microsoft für Codeverträge gestoßen.
Ich las ein bisschen Dokumentation und fragte mich ständig: "Warum sollte ich das jemals tun wollen, da es keine statische Analyse durchführt und oft nicht kann."
Jetzt habe ich schon eine Art defensiven Programmierstil, mit Ausnahmen wie dieser:
if(var == null) { throw new NullArgumentException(); }
Ich verwende auch NullObject-Muster viel und habe selten irgendwelche Probleme. Fügen Sie Unit-Tests hinzu, und schon sind Sie fertig.
Ich habe nie Behauptungen benutzt und sie nie verpasst. Ganz im Gegenteil. Ich hasse wirklich Code, der viele bedeutungslose Behauptungen enthält, was für mich nur Rauschen ist und mich von dem ablenkt, was ich wirklich sehen möchte. Codeverträge sind zumindest auf die Art von Microsoft ähnlich - und noch schlimmer. Sie fügen dem Code viel Rauschen und Komplexität hinzu. In 99% wird sowieso eine Ausnahme geworfen - es ist mir also egal, ob es sich um die Behauptung / den Vertrag oder das eigentliche Problem handelt. Es bleiben nur sehr wenige Fälle, in denen die Programmzustände wirklich verfälscht werden.
Was ist der Vorteil der Verwendung von Codeverträgen? Gibt es überhaupt welche? Wenn Sie Unit-Tests und Code bereits defensiv einsetzen, ist die Einführung von Verträgen meines Erachtens die Kosten einfach nicht wert und führt zu Störungen in Ihrem Code, die ein Betreuer beim Aktualisieren dieser Methode verfluchen wird, ähnlich wie ich es tue, wenn ich nicht sehe, was der Code tut aufgrund unbrauchbarer Behauptungen. Ich habe noch keinen guten Grund, diesen Preis zu zahlen.
quelle
Antworten:
Sie könnten genauso gut gefragt haben, wann statisches Tippen besser ist als dynamisches Tippen. Eine seit Jahren wütende Debatte, deren Ende nicht abzusehen ist. Schauen Sie sich also Fragen wie Dynamisch vs Statisch getippte Sprachkurse an
Das Hauptargument wäre jedoch das Potenzial, Probleme beim Kompilieren zu entdecken und zu beheben, die andernfalls in die Produktion geraten wären.
Verträge gegen Wachen
Selbst mit Wachen und Ausnahmen haben Sie immer noch das Problem, dass das System in einigen Fällen seine beabsichtigte Aufgabe nicht ausführen kann. Möglicherweise eine Instanz, deren Ausfall sehr kritisch und kostspielig sein wird.
Verträge vs. Unit-Tests
Das übliche Argument in diesem Fall ist, dass Tests das Vorhandensein von Fehlern belegen, während Typen (Verträge) das Fehlen belegen. ZB Wenn Sie einen Typ verwenden, von dem Sie wissen, dass kein Pfad im Programm möglicherweise ungültige Eingaben liefern kann, können Sie bei einem Test nur feststellen, dass der abgedeckte Pfad die richtigen Eingaben liefert.
Verträge vs. Null Objektmuster
Das ist jetzt zumindest im selben Stadion. Sprachen wie Scala und Haskell hatten großen Erfolg mit diesem Ansatz, Nullreferenzen vollständig aus Programmen zu entfernen. (Auch wenn Scala formell Nullen zulässt, ist die Konvention, diese niemals zu verwenden.)
Wenn Sie dieses Muster bereits verwenden, um NREs zu beseitigen, haben Sie im Grunde genommen die größte Ursache für Laufzeitfehler beseitigt, die es im Grunde genommen gibt, wie Verträge dies zulassen.
Der Unterschied besteht möglicherweise darin, dass Verträge die Option haben, Ihren gesamten Code automatisch zu fordern, um null zu vermeiden, und Sie daher zu zwingen, dieses Muster an mehreren Stellen zu verwenden, um die Kompilierung zu bestehen.
Darüber hinaus bieten Verträge Ihnen die Flexibilität, auf Dinge zu zielen, die über null hinausgehen. Wenn Sie also in Ihren Bugs kein NRE mehr finden, sollten Sie Verträge verwenden, um das nächsthäufigste Problem, das Sie haben könnten, zu ersticken. Aus um eins? Index außerhalb des zulässigen Bereichs?
Aber...
Das alles gesagt. Ich bin damit einverstanden, dass die Verträge für syntaktisches Rauschen (und sogar für strukturelles Rauschen) den Code erheblich erweitern und die Auswirkung der Analyse auf Ihre Build-Zeit nicht zu unterschätzen ist. Wenn Sie also Verträge zu Ihrem System hinzufügen möchten, ist es wahrscheinlich ratsam, dies sehr sorgfältig zu tun und sich dabei darauf zu konzentrieren, welche Klasse von Fehlern Sie beheben möchten.
quelle
Ich weiß nicht, woher die Behauptung kommt, dass "es keine statische Analyse durchführt und oft nicht kann". Der erste Teil der Behauptung ist eindeutig falsch. Der zweite hängt davon ab, was Sie mit "oft" meinen. Ich würde eher sagen, dass es oft statische Analysen durchführt und selten daran scheitert. In der normalen Geschäftsanwendung wird selten viel näher an nie .
Hier kommt also der erste Vorteil:
Vorteil 1: statische Analyse
Gewöhnliche Behauptungen und Argumentprüfungen haben einen Nachteil: Sie werden verschoben, bis der Code ausgeführt wird. Andererseits manifestieren sich Codeverträge auf einer viel früheren Ebene, entweder beim Codierschritt oder beim Kompilieren der Anwendung. Je früher Sie einen Fehler abfangen, desto günstiger ist es, ihn zu beheben.
Vorteil 2: Sozusagen immer aktuelle Dokumentation
Codeverträge bieten auch eine Art Dokumentation, die immer auf dem neuesten Stand ist. Wenn der XML-Kommentar der Methode
SetProductPrice(int newPrice)
angibt, dassnewPrice
sie höher oder gleich Null sein sollte, können Sie hoffen, dass die Dokumentation auf dem neuesten Stand ist, Sie können jedoch auch feststellen, dass jemand die Methode so geändert hat, dassnewPrice = 0
einArgumentOutOfRangeException
, aber niemals die entsprechende Dokumentation geändert wurde. Angesichts der Korrelation zwischen den Codeverträgen und dem Code selbst liegt kein Problem mit der nicht synchronen Dokumentation vor.Die Art der Dokumentation, die durch Codeverträge bereitgestellt wird, ist auch in einer Weise wertvoll, dass XML-Kommentare die akzeptablen Werte häufig nicht gut erklären. Wie oft war ich frage mich , ob
null
oderstring.Empty
oder\r\n
ein autorisierter Wert für ein Verfahren und XML - Kommentare schweigen auf das!Fazit: Ohne Codeverträge sind viele Codeteile wie folgt:
Mit Code-Verträgen wird es:
Vorteil 3: Verträge von Schnittstellen
Ein dritter Vorteil ist, dass Codeverträge Schnittstellen ermöglichen. Nehmen wir an, Sie haben etwas wie:
Wie würden Sie mit Asserts und Exceptions garantieren, dass
CommitChanges
nur aufgerufen werden kann, wennPendingChanges
nicht leer? Wie würden Sie garantieren, dassPendingChanges
das niemals istnull
?Vorteil 4: Erzwingen Sie die Ergebnisse einer Methode
Schließlich ist der vierte Vorteil, um
Contract.Ensure
die Ergebnisse zu können. Was ist, wenn ich beim Schreiben einer Methode, die eine Ganzzahl zurückgibt, sicherstellen möchte, dass der Wert niemals schlechter oder gleich Null ist? Einschließlich fünf Jahre später nach vielen Veränderungen durch viele Entwickler? Sobald eine Methode mehrere Rückgabepunkte hat, wird sieAssert
zu einem Alptraum für die Instandhaltung.Betrachten Sie Codeverträge nicht nur als Mittel zur Richtigkeit Ihres Codes, sondern auch als strengere Methode zum Schreiben von Code. In ähnlicher Weise kann eine Person, die ausschließlich dynamische Sprachen verwendet, fragen, warum Sie Typen auf Sprachebene erzwingen sollten, während Sie bei Bedarf dasselbe in Behauptungen tun können. Sie können, aber statische Typisierung ist einfacher zu verwenden, weniger fehleranfällig im Vergleich zu einer Reihe von Behauptungen und selbstdokumentierend.
Der Unterschied zwischen dynamischer und statischer Typisierung kommt dem Unterschied zwischen gewöhnlicher Programmierung und vertraglicher Programmierung sehr nahe.
quelle
Ich weiß, dass die Frage etwas spät ist, aber Code Contracts bietet noch einen weiteren Vorteil, der erwähnt werden muss
Verträge werden außerhalb der Methode geprüft
Wenn wir Schutzbedingungen innerhalb unserer Methode haben, ist dies der Ort, an dem die Überprüfung stattfindet und Fehler gemeldet werden. Möglicherweise müssen wir dann den Stack-Trace untersuchen, um herauszufinden, wo die eigentliche Fehlerquelle liegt.
Codeverträge befinden sich innerhalb der Methode, aber die Voraussetzungen werden außerhalb der Methode überprüft, wenn versucht wird, diese Methode aufzurufen. Die Verträge werden Teil der Methode und bestimmen, ob sie aufgerufen werden können oder nicht. Das bedeutet, dass wir einen Fehler erhalten, der viel näher an der eigentlichen Ursache des Problems liegt.
Wenn Sie eine vertraglich geschützte Methode haben, die an vielen Stellen aufgerufen wird, kann dies ein echter Vorteil sein.
quelle
Wirklich zwei Dinge:
quelle