Ich habe gerade eine Funktion geschrieben, die ungefähr 100 Zeilen umfasst. Wenn Sie das hören, sind Sie wahrscheinlich versucht, mich über einzelne Verantwortlichkeiten zu informieren und mich zur Umgestaltung aufzufordern. Das ist auch mein Bauchgefühl, aber hier ist das Problem: Die Funktion macht eine Sache. Es führt eine komplexe Zeichenfolgenmanipulation durch, und der Funktionskörper besteht hauptsächlich aus einer ausführlichen Regex, die in viele dokumentierte Zeilen unterteilt ist. Wenn ich den regulären Ausdruck in mehrere Funktionen aufteilen würde, hätte ich das Gefühl, die Lesbarkeit zu verlieren , da ich effektiv die Sprache wechsle und nicht in der Lage bin, einige Funktionen des regulären Ausdrucks zu nutzen. Hier ist jetzt meine Frage:
Sind große Funktionskörper bei der String-Manipulation mit regulären Ausdrücken noch ein Anti-Pattern? Es scheint, dass benannte Erfassungsgruppen Funktionen einen sehr ähnlichen Zweck erfüllen. Übrigens habe ich Tests für jeden Fluss durch den Regex.
quelle
Antworten:
Was Ihnen begegnet, ist die kognitive Dissonanz, die entsteht, wenn Sie Leuten zuhören, die die sklavische Einhaltung von Richtlinien unter dem Deckmantel von "Best Practices" gegenüber begründeten Entscheidungen bevorzugen.
Sie haben Ihre Hausaufgaben klar gemacht:
Wenn einer dieser Punkte nicht zutrifft, würde ich als Erster sagen, dass Ihre Funktion Arbeit braucht. Es gibt also eine Stimme dafür, dass der Code unverändert bleibt.
Die zweite Stimme ergibt sich aus der Betrachtung Ihrer Optionen und dem, was Sie jeweils erhalten (und verlieren):
Diese Entscheidung hängt davon ab, worauf Sie mehr Wert legen: Lesbarkeit oder Länge. Ich falle in das Lager, das die Länge für gut hält, aber die Lesbarkeit ist wichtig und wird die letztere jeden Tag in der Woche überholen.
Fazit: Wenn es nicht kaputt ist, reparieren Sie es nicht.
quelle
Ehrlich gesagt kann Ihre Funktion "eine Sache tun", aber wie Sie selbst angegeben haben
was bedeutet, dass Ihr Reg-Ex-Code viele Dinge tut. Und ich denke, es könnte in kleinere, einzeln testbare Einheiten zerlegt werden. Wenn dies jedoch eine gute Idee ist, ist die Antwort nicht einfach (insbesondere ohne den tatsächlichen Code zu sehen). Und die richtige Antwort kann weder "ja" noch "nein" sein, sondern "noch nicht, aber beim nächsten Mal müssen Sie etwas in dieser Ausrichtung ändern exp".
Und das ist der Kernpunkt - Sie haben einen Code, der in der Sprache reg ex geschrieben ist . Diese Sprache bietet kein gutes Mittel zur Abstraktion an sich (und ich betrachte "benannte Erfassungsgruppen" nicht als Ersatz für Funktionen). Ein Refactoring "in der Reg-Ex-Sprache" ist also nicht wirklich möglich, und das Verweben kleinerer Reg-Exps mit der Host-Sprache verbessert möglicherweise nicht die Lesbarkeit (zumindest haben Sie das Gefühl , aber Sie haben Zweifel, sonst hätten Sie die Frage nicht gestellt). . Also hier ist mein Rat
Zeigen Sie Ihren Code einem anderen fortgeschrittenen Entwickler (möglicherweise unter /codereview// ), um sicherzustellen, dass andere die Lesbarkeit auf Ihre Weise beurteilen. Seien Sie offen für die Idee, dass andere Benutzer eine 100-Zeilen-Registrierung möglicherweise nicht so lesbar finden wie Sie. Manchmal kann die Vorstellung von "es ist nicht leicht in kleinere Stücke zu zerbrechen" nur durch ein zweites Paar Augen überwunden werden.
Beobachten Sie die tatsächliche Evolvabilität. Sieht Ihre glänzende reg exp immer noch so gut aus, wenn neue Anforderungen eintreffen und Sie sie implementieren und testen müssen? Solange Ihre Registrierung gültig ist, würde ich es nicht anfassen, aber wenn etwas geändert werden muss, würde ich überlegen, ob es wirklich eine gute Idee ist, alles in diesen einen großen Block zu packen - und (im Ernst!) Zu überdenken, wenn sich jemand aufteilt kleinere Stücke wären keine bessere Option.
Beobachten Sie die Wartbarkeit - können Sie die reg exp in der aktuellen Form sehr gut debuggen? Besitzen Sie einen reg exp-Debugger, der Ihnen hilft, die Ursache zu finden, besonders nachdem Sie etwas ändern müssen und jetzt Ihre Tests Ihnen sagen, dass etwas nicht stimmt? Wenn das Debuggen schwierig wird, ist dies auch eine Gelegenheit, Ihr Design zu überdenken.
quelle
Manchmal ist eine längere Funktion, die eine Sache erledigt, die geeignetste Art, eine Arbeitseinheit zu handhaben. Sie können leicht auf sehr lange Funktionen zugreifen, wenn Sie mit der Abfrage einer Datenbank beginnen (mit Ihrer bevorzugten Abfragesprache). Eine Funktion (oder Methode) lesbarer zu machen, während sie auf den angegebenen Zweck beschränkt ist, würde ich als das wünschenswerteste Ergebnis einer Funktion betrachten.
Die Länge ist ein beliebiger "Standard", wenn es um die Codegröße geht. Wenn eine 100-Zeilen-Funktion in C # als länglich angesehen werden kann, ist sie in einigen Assemblyversionen winzig. Ich habe einige SQL-Abfragen gesehen, die weit über den Bereich von 200 Codezeilen lagen und einen sehr komplizierten Datensatz für einen Bericht zurückgaben.
Fully - Code arbeiten , das ist so einfach wie möglich vernünftig machen es zum Ziel.
Ändere es nicht, nur weil es lang ist.
quelle
Sie können den regulären Ausdruck jederzeit in untergeordnete reguläre Ausdrücke aufteilen und den endgültigen Ausdruck nach und nach erstellen. Dies könnte das Verständnis für ein sehr großes Muster erleichtern, insbesondere wenn dasselbe Untermuster viele Male wiederholt wird. Zum Beispiel in Perl;
quelle
Ich würde sagen, brecht es, wenn es zerbrechlich ist. Unter dem Gesichtspunkt der Wartbarkeit und möglicherweise der Wiederherstellbarkeit ist es sinnvoll, diese zu unterbrechen, aber natürlich müssen Sie Ihre Funktion berücksichtigen, wie Sie Eingaben erhalten und was sie zurückgeben wird.
Ich erinnere mich, dass ich daran gearbeitet habe, Streaming-Chunked-Daten in Objekte zu zerlegen. Also habe ich es im Grunde genommen in zwei Hauptteile aufgeteilt, eine vollständige Zeichenfolgeeinheit aus codiertem Text erstellt und im zweiten Teil diese Einheiten in ein Datenwörterbuch geparst und organisiert sie (können zufällige Eigenschaften für verschiedene Objekte sein) und dann Objekte aktualisieren oder erstellen.
Außerdem konnte ich jeden Hauptteil in mehrere kleinere und spezifischere Funktionen aufteilen, so dass ich am Ende 5 verschiedene Funktionen hatte, um das Ganze zu erledigen, und einige der Funktionen an verschiedenen Stellen wiederverwenden konnte.
quelle
Eine Sache, die Sie vielleicht in Betracht gezogen haben oder nicht, ist, einen kleinen Parser in der von Ihnen verwendeten Sprache zu schreiben, anstatt einen regulären Ausdruck in dieser Sprache zu verwenden. Dies ist möglicherweise einfacher zu lesen, zu testen und zu warten.
quelle
Riesen-Regexes sind in den meisten Fällen eine schlechte Wahl. Nach meiner Erfahrung werden sie häufig verwendet, weil der Entwickler mit dem Parsen nicht vertraut ist (siehe die Antwort von Thomas Eding ).
Angenommen, Sie möchten sich an eine auf Regex basierende Lösung halten.
Da ich den tatsächlichen Code nicht kenne, werde ich die beiden möglichen Szenarien untersuchen:
Der reguläre Ausdruck ist einfach (viele wörtliche Übereinstimmungen und wenige Alternativen)
In diesem Fall sind die erweiterten Funktionen eines einzelnen regulären Ausdrucks nicht unbedingt erforderlich. Dies bedeutet, dass Sie wahrscheinlich von der Aufteilung profitieren werden.
Der reguläre Ausdruck ist komplex (viele Alternativen)
In diesem Fall können Sie keine vollständige Testabdeckung erzielen, da Sie wahrscheinlich Millionen von möglichen Flows haben. Um es zu testen, müssen Sie es aufteilen.
Mir fehlt vielleicht die Vorstellungskraft, aber ich kann mir keine reale Situation vorstellen, in der ein Regex mit 100 Zeilen eine gute Lösung ist.
quelle