Warum ist es nicht üblich, die Namen von Argumenten in Funktionsnamen zu codieren? [geschlossen]

47

In Clean Code gibt der Autor ein Beispiel für

assertExpectedEqualsActual(expected, actual)

vs

assertEquals(expected, actual)

Ersteres soll klarer sein, weil es die Notwendigkeit beseitigt, sich daran zu erinnern, wohin die Argumente führen, und den möglichen Missbrauch, der daraus resultiert. Dennoch habe ich in keinem Code ein Beispiel für das frühere Benennungsschema gesehen und sehe das letztere die ganze Zeit. Warum nehmen Programmierer das erstere nicht an, wenn es, wie der Autor behauptet, klarer ist als das letztere?

EternalStudent
quelle
9
Ich denke, das ist eine gute Frage für eine Diskussion. Aber nicht etwas, das mit objektiven Antworten beantwortet werden kann. Diese Frage könnte also als meinungsbasiert abgeschlossen werden.
Euphoric
54
Viele Leute würden gegen das erste Benennungsschema argumentieren, weil es zu ausführlich ist , weit über den Punkt hinaus, an dem es die Klarheit fördern würde . Insbesondere assertEquals()wird diese Methode hunderte Male in einer Codebasis verwendet, so dass zu erwarten ist, dass sich die Leser einmal mit der Konvention vertraut machen. Unterschiedliche Frameworks haben unterschiedliche Konventionen (z. B. (actual, expected) or an agnostic (links, rechts)), aber meiner Erfahrung nach ist dies höchstens eine geringfügige Ursache für Verwirrung.
amon
5
Weil der Gewinn im Vergleich zu seinen Vorteilen so gering ist, dass jeder gesunde Mensch wahrscheinlich weggehen würde. Wenn Sie einen flüssigeren Ansatz wünschen , sollten Sie versuchen assert(a).toEqual(b)(auch wenn IMO immer noch unnötig ausführlich ist), einige verwandte Behauptungen zu verketten.
Adriano Repetti
18
Woher wissen wir, dass tatsächliche und erwartete Werte sind? Sicher sollte es sein assertExpectedValueEqualsActualValue? Aber warte, wie können wir uns erinnern, ob es verwendet ==oder .equalsoder Object.equals? Sollte es sein assertExpectedValueEqualsMethodReturnsTrueWithActualValueParameter?
user253751
6
Angesichts der Tatsache, dass für diese bestimmte Methode die Reihenfolge der beiden Argumente keine Rolle spielt, scheint es ein schlechtes Beispiel zu sein, sich für die Vorteile dieses Benennungsschemas zu entscheiden.
Steven Rands

Antworten:

66

Weil es mehr zu tippen und mehr zu lesen ist

Der einfachste Grund ist, dass die Leute gerne weniger tippen, und das Kodieren dieser Informationen bedeutet mehr Tippen. Wenn ich es lese, muss ich jedes Mal das Ganze lesen, auch wenn ich mit der Reihenfolge der Argumente vertraut bin. Auch wenn Sie mit der Reihenfolge der Argumente nicht vertraut sind ...

Viele Entwickler verwenden IDEs

IDEs bieten häufig einen Mechanismus zum Anzeigen der Dokumentation für eine bestimmte Methode durch Bewegen des Mauszeigers oder über eine Tastenkombination. Aus diesem Grund sind die Namen der Parameter immer verfügbar.

Das Kodieren der Argumente führt zu Duplizierung und Kopplung

Die Namen der Parameter sollten bereits dokumentieren, was sie sind. Indem wir die Namen in den Methodennamen schreiben, duplizieren wir diese Informationen auch in der Methodensignatur. Wir erstellen auch eine Kopplung zwischen dem Methodennamen und den Parametern. Sagen Sie expectedund actualverwirren Sie zu unseren Benutzern. Das Wechseln von assertEquals(expected, actual)zu assertEquals(planned, real)erfordert keine Änderung des Client-Codes mithilfe der Funktion. Das Wechseln von assertExpectedEqualsActual(expected, actual)zu assertPlannedEqualsReal(planned, real)bedeutet eine grundlegende Änderung an der API. Oder wir ändern den Methodennamen nicht, was schnell verwirrend wird.

Verwenden Sie Typen anstelle mehrdeutiger Argumente

Das eigentliche Problem ist, dass wir mehrdeutige Argumente haben, die leicht gewechselt werden können, weil sie vom gleichen Typ sind. Wir können stattdessen unser Typensystem und unseren Compiler verwenden, um die richtige Reihenfolge zu erzwingen:

class Expected<T> {
    private T value;
    Expected(T value) { this.value = value; }
    static Expected<T> is(T value) { return new Expected<T>(value); }
}

class Actual<T> {
    private T value;
    Actual(T value) { this.value = value; }
    static Actual<T> is(T value) { return new Actual<T>(value); }
}

static assertEquals(Expected<T> expected, Actual<T> actual) { /* ... */ }

// How it is used
assertEquals(Expected.is(10), Actual.is(x));

Dies kann dann auf Compilerebene erzwungen werden und garantiert, dass Sie sie nicht rückwärts erhalten können. Aus einem anderen Blickwinkel betrachtet ist dies im Wesentlichen das, was die Hamcrest- Bibliothek für Tests tut.

cbojar
quelle
5
Wenn Sie eine IDE verwenden, finden Sie die Parameternamen in der Sprechblasenhilfe. Wenn Sie keinen verwenden, entspricht das Speichern des Funktionsnamens dem Speichern der Argumente, sodass in beiden Fällen nichts gewonnen wird.
Peter - Reinstate Monica
29
Wenn Sie dagegen sind, assertExpectedEqualsActual"weil es mehr um das Schreiben und mehr um das Lesen geht", wie können Sie dann dafür eintreten assertEquals(Expected.is(10), Actual.is(x))?
Ruakh
9
@ruakh es ist nicht vergleichbar. assertExpectedEqualsActualDer Programmierer muss weiterhin darauf achten, die Argumente in der richtigen Reihenfolge anzugeben. Die assertEquals(Expected<T> expected, Actual<T> actual)Signatur verwendet den Compiler, um die korrekte Verwendung zu erzwingen. Dies ist ein völlig anderer Ansatz. Sie können diesen Ansatz für die Kürze optimieren expect(10).equalsActual(x), aber das war nicht die Frage ...
Holger
6
Auch in diesem speziellen Fall (==) ist die Reihenfolge der Argumente für den endgültigen Wert irrelevant. Die Bestellung ist nur für eine Nebenwirkung von Bedeutung (Meldung des Fehlers). Bei Bestellungen kann dies (geringfügig) sinnvoller sein. Zum Beispiel strcpy (dest, src).
Kristian H
1
Kann nicht mehr mit dem Teil über Vervielfältigung und Kopplung übereinstimmen ... Wenn sich jedes Mal, wenn ein Funktionsparameter seinen Namen ändert, auch der Funktionsname ändern müsste, müssten Sie alle Verwendungen dieser Funktion nachverfolgen und ändern Sie sie auch ... Das würde für mich, mein Team und alle anderen, die unseren Code als Abhängigkeit verwenden, eine
Menge Veränderungen bedeuten
20

Sie fragen nach einer langjährigen Debatte in der Programmierung. Wie viel Ausführlichkeit ist gut? Generell haben die Entwickler festgestellt, dass sich die zusätzliche Ausführlichkeit, mit der die Argumente benannt werden, nicht lohnt.

Ausführlichkeit bedeutet nicht immer mehr Klarheit. Erwägen

copyFromSourceStreamToDestinationStreamWithoutBlocking(fileStreamFromChoosePreferredOutputDialog, heuristicallyDecidedSourceFileHandle)

gegen

copy(output, source)

Beide enthielten den gleichen Fehler, aber haben wir es tatsächlich einfacher gemacht, diesen Fehler zu finden? In der Regel ist das Debuggen am einfachsten, wenn alles maximal knapp ist, außer den wenigen Dingen, die den Fehler aufweisen, und die ausführlich genug sind, um Ihnen mitzuteilen, was schief gelaufen ist.

Das Hinzufügen von Ausführlichkeit hat eine lange Tradition. Zum Beispiel gibt es die allgemein unpopuläre " ungarische Notation ", die uns wunderbare Namen wie gab lpszName. Das ist in der allgemeinen Programmierer-Bevölkerung in der Regel auf der Strecke geblieben. Das Hinzufügen von Zeichen zu Mitgliedsvariablennamen (wie mNameoder m_Nameoder name_) ist jedoch in einigen Kreisen weiterhin beliebt. Andere ließen das gänzlich fallen. Ich arbeite gerade an einer Physiksimulations-Codebasis, deren Codierungsstil-Dokumente erfordern, dass jede Funktion, die einen Vektor zurückgibt, den Rahmen des Vektors im Funktionsaufruf ( getPositionECEF) spezifizieren muss .

Möglicherweise interessieren Sie sich für einige der von Apple verbreiteten Sprachen. Objective-C enthält die Argumentnamen als Teil der Funktionssignatur (Die Funktion [atm withdrawFundsFrom: account usingPin: userProvidedPin]ist in der Dokumentation als geschrieben withdrawFundsFrom:usingPin:. Das ist der Name der Funktion). Swift traf ähnliche Entscheidungen und forderte Sie auf, die Argumentnamen in die Funktionsaufrufe ( greet(person: "Bob", day: "Tuesday")) einzufügen .

Cort Ammon
quelle
13
Abgesehen von allen anderen Punkten wäre das viel einfacher zu lesen, wenn copyFromSourceStreamToDestinationStreamWithoutBlocking(fileStreamFromChoosePreferredOutputDialog, heuristicallyDecidedSourceFileHandle)es geschrieben wäre copy_from_source_stream_to_destination_stream_without_blocking(file_stream_from_choose_preferred_output_dialog, heuristically_decided_source_file_handle). Sehen Sie, wie viel einfacher das war ?! Das liegt daran, dass es zu leicht ist, kleine Änderungen in der Mitte dieses Salats mit ungebrochenen Worten zu übersehen, und dass es länger dauert, herauszufinden, wo die Wortgrenzen liegen. Zertrümmern verwirrt.
Tchrist
1
Die obj-C-Syntax withdrawFundsFrom: account usingPin: userProvidedPinist tatsächlich von SmallTalk entlehnt.
JoH1
14
@tchrist Seien Sie vorsichtig mit der Gewissheit, dass Sie Recht haben, wenn es um heilige Kriege geht. Die andere Seite ist nicht immer falsch.
Cort Ammon
3
@tchrist Addingunderscoresnakesthingseasiertoreadnotharderasyouseemanipuliert das Argument. Die Antwort hier verwendete Großschreibung, die Sie weglassen. AddingCapitalizationMakesThingsEasyEnoughToReadAsYouCanSeeHere. Zweitens sollte ein Name 9-mal von 10 niemals [verb][adjective][noun]ReadSimpleName
größer werden
5
@tchrist - die Wissenschaft Ihrer Studie ( kostenloser Volltext-Link ) zeigt einfach, dass Programmierer, die für die Verwendung des Unterstrich-Stils geschult sind, den Unterstrich-Stil schneller lesen als Camel Case. Die Daten zeigen auch, dass der Unterschied bei erfahreneren Fächern geringer ist (und die meisten Fächer, bei denen es sich um Studenten handelt, weisen darauf hin, dass selbst diese Fächer wahrscheinlich nicht besonders erfahren waren). Dies bedeutet nicht, dass Programmierer, die mehr Zeit mit Camel Case verbracht haben, dasselbe Ergebnis erzielen.
Jules
8

Der Autor von "Clean Code" weist auf ein legitimes Problem hin, sein Lösungsvorschlag ist jedoch eher unelegant. Es gibt normalerweise bessere Möglichkeiten, um unklare Methodennamen zu verbessern.

Er hat Recht, dass assertEquals(aus Unit-Test-Bibliotheken im xUnit-Stil) nicht klar ist, welches Argument das erwartete und welches das tatsächliche ist. Das haben mich auch gebissen! Viele Komponententestbibliotheken haben das Problem festgestellt und alternative Syntaxen eingeführt, z.

actual.Should().Be(expected);

Oder ähnliches. Das ist sicherlich viel klarer als assertEqualsaber auch viel besser als assertExpectedEqualsActual. Und es ist auch viel komponierbarer.

JacquesB
quelle
1
Ich bin anal und folge der empfohlenen Reihenfolge, aber es scheint mir, dass, wenn ich erwarte, dass das Ergebnis fun(x)5 ist, was dann schief gehen könnte, wenn die Reihenfolge umgekehrt wird - assert(fun(x), 5)? Wie hat es dich gebissen?
Emory
3
@emory Ich weiß, dass jUnit (zumindest) eine gründliche Fehlermeldung aus den Werten von expectedund erstellt. Wenn Sie actualdiese also umkehren, wird die Meldung möglicherweise nicht korrekt. Aber ich bin damit einverstanden, dass es sich natürlicher anhört :)
joH1
@ joH1 es kommt mir schwach vor. Fehlgeschlagener Code schlägt fehl und das Weitergeben von Code wird weitergegeben, unabhängig davon, ob Sie dies tun assert(expected, observed)oder assert(observed, expected). Ein besseres Beispiel wäre so etwas wie locateLatitudeLongitude- wenn Sie die Koordinaten umkehren, wird es ernsthaft durcheinander bringen.
Emory
1
@emory Leute, die sich nicht für sinnvolle Fehlermeldungen in Unit-Tests interessieren, müssen sich in einigen alten Codebasen mit "Assert.IsTrue failed" auseinandersetzen. Welches ist enormer Spaß zu debuggen. Aber ja, in diesem Fall ist das Problem möglicherweise nicht so wichtig (es sei denn, wir führen Fuzzy-Vergleiche durch, bei denen die Reihenfolge der Argumente im Allgemeinen von Bedeutung ist). Fließende Behauptungen sind in der Tat eine großartige Möglichkeit, dieses Problem zu vermeiden und den Code aussagekräftiger zu gestalten (und beim Booten eine viel bessere Fehlermeldung zu erhalten).
Voo
@emory: Wenn Sie das Argument umkehren, werden die Fehlermeldungen irreführend und Sie werden beim Debuggen auf den falschen Weg geschickt.
JacquesB
5

Sie versuchen, Ihren Weg zwischen Scylla und Charybdis zur Klarheit zu lenken, um unnötige Ausführlichkeit (auch als zielloses Wandern bezeichnet) sowie übermäßige Kürze (auch als kryptische Knappheit bezeichnet) zu vermeiden.

Wir müssen uns also die Schnittstelle ansehen, die Sie auswerten möchten, um Debug-Aussagen zu machen, dass zwei Objekte gleich sind.

  1. Gibt es eine andere Funktion, bei der es um Arität und Namen geht?
    Nein, der Name selbst ist also klar genug.
  2. Sind die Typen von Bedeutung?
    Nein, also ignorieren wir sie. Hast du das schon gemacht? Gut.
  3. Ist es in seinen Argumenten symmetrisch?
    Fast im Fehlerfall setzt die Nachricht jede Argumentdarstellung an ihre eigene Stelle.

Lassen Sie uns also sehen, ob dieser kleine Unterschied von Bedeutung ist und nicht durch bestehende strenge Konventionen abgedeckt wird.

Ist das beabsichtigte Publikum belästigt, wenn die Argumente unbeabsichtigt ausgetauscht werden?
Nein, die Entwickler bekommen auch einen Stack-Trace und müssen den Quellcode trotzdem überprüfen, um den Fehler zu beheben.
Auch ohne einen vollständigen Stack-Trace löst die Assertions-Position diese Frage. Und wenn selbst das fehlt und aus der Botschaft nicht ersichtlich ist, welches ist, verdoppelt es höchstens die Möglichkeiten.

Entspricht die Reihenfolge der Argumente der Konvention?
Scheint der Fall zu sein. Es scheint jedoch allenfalls eine schwache Konvention zu sein.

Daher sieht der Unterschied ziemlich unbedeutend aus, und die Argumentreihenfolge unterliegt einer Konvention, die stark genug ist, dass jeder Versuch, sie in den Funktionsnamen zu codieren, einen negativen Nutzen hat.

Deduplizierer
quelle
Nun, die Reihenfolge könnte bei jUnit eine Rolle spielen, das eine bestimmte Fehlermeldung aus den Werten von expectedund erstellt actual(zumindest bei Strings)
joH1
Ich glaube , ich , dass ein Teil abgedeckt ...
Deduplicator
Sie erwähnten es aber bedenken: assertEquals("foo", "doo")gibt die Fehlermeldung ComparisonFailure: expected:<[f]oo> but was:<[d]oo>... die Werte Swapping die Bedeutung der Nachricht umkehren würde, das klingt mehr anti mir symmetrisch. Wie auch immer, wie Sie sagten, ein Entwickler hat andere Indikatoren, um den Fehler zu beheben, aber es kann meiner Meinung nach irreführend sein und ein bisschen mehr Debugging-Zeit in Anspruch nehmen.
JoH1
Die Idee, dass es eine "Konvention" für Argumentbefehle gibt, ist witzig, wenn man bedenkt, dass beide Lager (dest, src vs. src, dest) sich mindestens so lange darüber gestritten haben, wie es die AT & T vs. Intel-Syntax gegeben hat. Und nicht hilfreiche Fehlermeldungen in Unit-Tests sind eine Plage, die ausgerottet und nicht durchgesetzt werden sollte. Das ist fast so schlimm wie "Assert.IsTrue failed" ("Hey, Sie müssen den Unit - Test sowieso ausführen, um ihn zu debuggen. Führen Sie ihn also erneut aus und setzen Sie dort einen Haltepunkt.") überprüfen Sie einfach, ob die Bestellung korrekt ist ").
Voo
@Voo: Der Punkt ist, dass der "Schaden" für das Verstehen des Fehlers winzig ist (die Logik hängt nicht davon ab und das Dienstprogramm messages wird in keinem wesentlichen Maße beeinträchtigt), und beim Schreiben der IDE wird Ihnen der Parametername angezeigt und tippe trotzdem.
Deduplizierer
3

Oft fügt es keine logische Klarheit hinzu.

Vergleichen Sie "Add" mit "AddFirstArgumentToSecondArgument".

Wenn Sie eine Überladung benötigen, die beispielsweise drei Werte hinzufügt. Was wäre sinnvoller?

Ein weiteres "Hinzufügen" mit drei Argumenten?

oder

"AddFirstAndSecondAndThirdArgument"?

Der Name der Methode sollte ihre logische Bedeutung vermitteln. Es sollte zeigen, was es tut. Auf Mikroebene zu sagen, welche Schritte erforderlich sind, macht es dem Leser nicht leichter. Die Namen der Argumente liefern bei Bedarf zusätzliche Details. Wenn Sie noch mehr Details benötigen, ist der Code genau richtig für Sie.

Martin Maat
quelle
4
Addschlägt eine kommutative Operation vor. Das OP befasst sich mit Situationen, in denen es auf die Reihenfolge ankommt.
Rosie F
In Swift würden Sie zum Beispiel add (5, bis: x) oder add (5, plus: 7, bis: x) oder add (5, plus: 7, mit: x) aufrufen, wenn Sie die Funktion add () definieren entsprechend.
gnasher729
Die dritte Überladung sollte "Sum"
heißen
@StringyJack Hmm .. Summe ist keine Anweisung, sondern ein Substantiv, das für einen Methodennamen weniger geeignet ist. Aber wenn Sie so denken und wenn Sie puristisch sein wollen, sollte die Version mit zwei Argumenten auch Sum heißen. Wenn Sie über eine Add-Methode verfügen, sollte sie ein Argument haben, das der Objektinstanz selbst hinzugefügt wird (dies müsste ein numerischer oder ein Vektortyp sein). Die zwei oder mehr Argumentvarianten (wie auch immer Sie sie nennen würden) wären statisch. Dann wären die drei oder mehr Argumentversionen überflüssig und wir hätten einen Plus-Operator implementiert: - |
Martin Maat
1
@Martin Warte was? sumist ein perfektes cromulent Verb . Es ist besonders häufig in der Phrase "zusammenzufassen".
Voo
2

Ich möchte noch etwas hinzufügen, das durch andere Antworten angedeutet ist, aber ich glaube, es wurde nicht explizit erwähnt:

@puck sagt "Es gibt immer noch keine Garantie, dass das erste Argument im Funktionsnamen wirklich der erste Parameter ist."

@cbojar sagt "Verwenden Sie Typen anstelle von mehrdeutigen Argumenten"

Das Problem ist, dass Programmiersprachen keine Namen verstehen: Sie werden nur als undurchsichtige, atomare Symbole behandelt. Wie bei Codekommentaren besteht daher nicht notwendigerweise eine Korrelation zwischen dem Namen einer Funktion und ihrer tatsächlichen Funktionsweise.

Vergleichen Sie assertExpectedEqualsActual(foo, bar)mit einigen Alternativen (von dieser Seite und anderswo), wie:

# Putting the arguments in a labelled structure
assertEquals({expected: foo, actual: bar})

# Using a keyword arguments language feature
assertEquals(expected=foo, actual=bar)

# Giving the arguments different types, forcing us to wrap them
assertEquals(Expected(foo), Actual(bar))

# Breaking the symmetry and attaching the code to one of the arguments
bar.Should().Be(foo)

Diese haben alle mehr Struktur als der wörtliche Name, wodurch die Sprache nicht undurchsichtig wirkt. Die Definition und Verwendung der Funktion hängt auch von dieser Struktur ab, so dass sie nicht mit dem synchronisiert werden kann, was die Implementierung tut (wie ein Name oder ein Kommentar).

Wenn ich auf ein Problem wie dieses stoße oder es sehe, nehme ich mir einen Moment Zeit, um zu fragen, ob es „fair“ ist, der Maschine überhaupt die Schuld zu geben, bevor ich frustriert meinen Computer anschreie. Mit anderen Worten, hat die Maschine genügend Informationen erhalten, um zu unterscheiden, was ich wollte und wonach ich gefragt habe?

Ein Anruf wie assertEqual(expected, actual)macht genauso viel Sinn wie assertEqual(actual, expected), daher ist es für uns einfach, sie durcheinander zu bringen und die Maschine vorwärts zu pflügen und das Falsche zu tun. Wenn wir assertExpectedEqualsActualstattdessen verwenden, ist es möglicherweise weniger wahrscheinlich, dass wir einen Fehler machen, aber die Maschine erhält keine weiteren Informationen (sie kann kein Englisch verstehen und die Wahl des Namens sollte sich nicht auf die Semantik auswirken).

Was die "strukturierten" Ansätze bevorzugter macht, wie Schlüsselwortargumente, beschriftete Felder, unterschiedliche Typen usw., ist, dass die zusätzlichen Informationen auch maschinenlesbar sind , so dass wir die Maschine falsche Verwendungen erkennen und uns dabei helfen können, die Dinge richtig zu machen. Der assertEqualFall ist nicht so schlimm, da das einzige Problem ungenaue Nachrichten wären. Ein unheimlicheres Beispiel könnte sein String replace(String old, String new, String content), das leicht zu verwechseln String replace(String content, String old, String new)ist und eine ganz andere Bedeutung hat. Ein einfaches Mittel wäre, ein Paar zu nehmen [old, new], bei dem Fehler sofort einen Fehler auslösen (auch ohne Typen).

Beachten Sie, dass wir selbst bei Typen möglicherweise nicht sagen, was wir wollen. Zum Beispiel behandelt das Anti-Pattern "stringly typed programming" alle Daten als Strings, was es leicht macht, Argumente zu verwechseln (wie in diesem Fall), einen Schritt zu vergessen (zB Escape), um Invarianten versehentlich zu brechen (zB unparseable JSON machen), etc.

Dies hängt auch mit der "Booleschen Blindheit" zusammen, bei der wir eine Reihe von Booleschen Werten (oder Zahlen usw.) in einem Teil des Codes berechnen, aber wenn wir versuchen, sie in einem anderen Teil zu verwenden, ist nicht klar, was sie tatsächlich darstellen, ob Wir haben sie durcheinander gebracht, usw. Vergleichen Sie dies zB mit verschiedenen Aufzählungen, die beschreibende Namen haben (zB LOGGING_DISABLEDanstatt false) und die eine Fehlermeldung verursachen, wenn wir sie durcheinander bringen.

Warbo
quelle
1

weil es die Notwendigkeit beseitigt, sich daran zu erinnern, wohin die Argumente führen

Wirklich? Es gibt noch keine Garantie, dass das zuerst genannte Argument im Funktionsnamen wirklich der erste Parameter ist. Schlagen Sie es also besser nach (oder lassen Sie Ihre IDE das tun) und bleiben Sie bei vernünftigen Namen, als sich blind auf einen ziemlich dummen Namen zu verlassen.

Wenn Sie den Code lesen, sollten Sie leicht sehen, was passiert, wenn die Parameter so benannt werden, wie sie sein sollten. copy(source, destination)ist viel leichter zu verstehen als soemthing wie copyFromTheFirstLocationToTheSecondLocation(placeA, placeB).

Warum nehmen Programmierer das erstere nicht an, wenn es, wie der Autor behauptet, klarer ist als das letztere?

Weil es unterschiedliche Sichtweisen auf verschiedene Stile gibt und Sie x Autoren anderer Artikel finden können, in denen das Gegenteil festgestellt wird. Du würdest verrückt werden, wenn du versuchst, allem zu folgen, was jemand irgendwo schreibt ;-)

Puck
quelle
0

Ich stimme zu, dass das Codieren von Parameternamen in Funktionsnamen das Schreiben und Verwenden von Funktionen intuitiver macht.

copyFromSourceToDestination( // "...ahh yes, the source directory goes first"

Die Reihenfolge der Argumente in Funktionen und Shell-Befehlen kann leicht vergessen werden, und viele Programmierer verlassen sich aus diesem Grund auf IDE-Features oder Funktionsreferenzen. Die im Namen beschriebenen Argumente wären eine beredte Lösung für diese Abhängigkeit.

Einmal geschrieben, wird die Beschreibung der Argumente jedoch für den nächsten Programmierer, der die Anweisung lesen muss, überflüssig, da in den meisten Fällen benannte Variablen verwendet werden.

copy(sourceDir, destinationDir); // "...makes sense"

Die Knappheit wird die meisten Programmierer überzeugen und ich persönlich finde es einfacher zu lesen.

BEARBEITEN: Wie @Blrfl bereits betont hat, ist die Codierung von Parametern nicht so intuitiv, da Sie sich zunächst den Namen der Funktion merken müssen. Dies erfordert das Nachschlagen von Funktionsreferenzen oder das Anfordern von Hilfe von einer IDE, die wahrscheinlich ohnehin Informationen zur Parameterreihenfolge liefert.

Josh Taylor
quelle
9
Wenn ich für eine Minute den Anwalt des Teufels spielen kann: Es ist nur intuitiv, wenn Sie den vollständigen Namen der Funktion kennen. Wenn Sie wissen, dass es eine Kopierfunktion gibt und Sie sich nicht daran erinnern, ob dies der Fall ist copyFromSourceToDestinationoder nicht copyToDestinationFromSource, können Sie diese durch Ausprobieren oder Lesen des Referenzmaterials finden. IDEs, die Teilnamen vervollständigen können, sind nur eine automatisierte Version der letzteren.
Blrfl
@Blrfl Der Sinn des Aufrufs copyFromSourceToDestinationist, dass copyToDestinationFromSourceder Compiler Ihren Fehler findet, wenn Sie glauben, dass er es ist , aber wenn er aufgerufen wurde copy, wird er es nicht tun . Es ist einfach, die Parameter einer Kopierroutine in die falsche Richtung zu lenken, da strcpy, strcat usw. einen Präzedenzfall setzen. Und ist die knappe leichter zu lesen? Erstellt mergeLists (listA, listB, listC) listA aus listB & listC oder liest listA & listB und schreibt listC?
Rosie F
4
@RosieF Wenn ich nicht sicher wäre, was die Argumente bedeuten, würde ich die Dokumentation lesen, bevor ich den Code schreibe. Außerdem gibt es auch bei den ausführlicheren Funktionsnamen noch Interpretationsspielraum für die tatsächliche Reihenfolge. Jemand, der sich den Code genauer ansieht, kann sich nicht vorstellen, dass Sie die Konvention aufgestellt haben, dass der Name der Funktion die Reihenfolge der Argumente widerspiegelt. Sie müssten es immer noch im Voraus wissen oder die Dokumente lesen.
Blrfl
OTOH, destinationDir.copy (sourceDir); // "... macht mehr Sinn"
Kristian H
1
@KristianH In welche Richtung geht die dir1.copy(dir2)Arbeit? Keine Ahnung. Was ist dir1.copyTo(dir2)?
Maaartinus