Was ist die richtige Balance zwischen Codekonsistenz und Codeverbesserung?


53

Vor kurzem hatte ich eine Diskussion mit einem Kollegen über den Codestil. Er argumentierte, dass Ihre Verwendung von APIs und die von Ihnen verwendeten allgemeinen Muster mit dem umgebenden Code so ähnlich wie möglich sein sollten, wenn nicht mit der Codebasis als Ganzes, so wie Sie es mit dem Erscheinungsbild des Codes (geschweifte Klammern, Großschreibung usw.) tun würden. . Wenn ich beispielsweise einer DAO-Klasse in C # eine Methode hinzufüge, würde ich versuchen, LINQ zu verwenden, um meinen Code sauberer und pflegeleichter zu machen, selbst wenn keine der anderen Methoden in dieser Klasse dies verwendet. Mein Kollege würde jedoch argumentieren, dass ich es in diesem Fall nicht verwenden sollte, weil es gegen den bestehenden Stil dieser Klasse und somit schwerer zu verstehen wäre.

Zuerst fand ich seine Position ziemlich extrem, aber nachdem ich eine Weile darüber nachgedacht habe, beginne ich, seinen Standpunkt zu verstehen. Im hypothetischen LINQ-Beispiel enthält diese Klasse sie möglicherweise nicht, weil meine Kollegen mit LINQ nicht vertraut sind. Wenn ja, wäre mein Code für meine Kollegen nicht besser zu pflegen, wenn ich ihn nicht verwenden würde? Auf der anderen Seite, wenn ich wirklich glaube, dass die Verwendung einer solchen Technik zu einem saubereren Code führen würde, sollte ich sie dann nicht verwenden, auch wenn sie sich drastisch vom umgebenden Code unterscheidet?

Ich denke, der Kern der Argumentation meines Kollegen ist, dass, wenn wir alle ähnliche Funktionen in einer Codebasis auf unterschiedliche Weise implementieren und wir alle denken, dass unser Weg "am besten" ist, der Code insgesamt am Ende nur schwieriger wird verstehen. Im Moment denke ich jedoch immer noch, dass die Qualität mit der Zeit nur langsam verrottet, wenn wir dem vorhandenen Code blind folgen.

Inwieweit sind Muster Teil des Codestils, und wo sollten wir die Grenze zwischen Konstanz und Verbesserungen ziehen?


14
Wie also würde sich die Codequalität jemals verbessern, wenn sich jeder auf den "schlechten" Weg beschränken würde?
Izkata


Wenn Sie LINQ schreiben, meinen Sie damit nicht LINQ to SQL? Wenn ja, dann könnte ich Ihrem Freund zustimmen. Wenn Sie über LINQ sprechen, stimme ich ihm nicht zu. Jeder muss heutzutage mit LINQ vertraut sein. Es ist nicht ihre Wahl. Sie werden dafür bezahlt, vertraut zu sein.
Piotr Perak

@Peri Ich meinte nur einfaches LINQ - ich denke, mein Beispiel hätte sich IEnumerableeher mit s als mit einem DAO befassen sollen .
Robert Johnson

2
ICYMI - Dilbert-Comic zu diesem Thema: dilbert.com/strips/2013-09-21
Jim Bethancourt

Antworten:


53

Um eine allgemeinere Antwort zu geben:

In einem solchen Fall gibt es zwei "Best Practices" für die Programmierung, die sich widersprechen: Die Codekonsistenz ist wichtig, aber auch die Auswahl der bestmöglichen Methode, um Ihre Aufgabe zu erfüllen. Es gibt keine richtige Antwort auf dieses Dilemma. es hängt von ein paar Faktoren ab:

  • Wie nützlich ist der "richtige" Weg?

    • Manchmal führt die neue und verbesserte Best Practice zu einer drastischen Leistungssteigerung, zur Beseitigung von Fehlern, zu einer weitaus einfacheren Programmierbarkeit usw. In einem solchen Fall würde ich mich stark für die Verwendung der neuen Methode einsetzen. Andererseits kann der "richtige Weg" etwas anderes sein als syntaktischer Zucker oder eine vereinbarte idiomatische Methode, um etwas zu tun, das nicht wirklich überlegen ist. In diesem Fall ist die Codekonsistenz wahrscheinlich wichtiger.
  • Wie groß ist das Problem, das durch Inkonsistenz verursacht wird?

    • Wie stark ist der neue Code mit dem alten Code verbunden? Ist Ihr neuer Code Teil einer Bibliothek? Erstellt es ein Objekt, das an viele Teile des Programms übergeben wird? In solchen Fällen ist die Konsistenz sehr wichtig. Die Verwendung einer neuen API oder einer neuen Art, Dinge im Allgemeinen zu erledigen, kann zu geringfügig unterschiedlichen Ergebnissen führen, die Annahmen an anderer Stelle in Ihrem Programm verletzen. Auf der anderen Seite ist es weniger wahrscheinlich, dass Inkonsistenz ein Problem darstellt, wenn Sie einen ziemlich isolierten Code schreiben.
    • Wie groß und wie ausgereift ist Ihre Codebasis? Wie viele Entwickler müssen das verstehen und daran arbeiten? Bei größeren Projekten sind vereinbarte, einheitliche Standards viel wichtiger.
    • Muss der Code in älteren Umgebungen ausgeführt werden, die möglicherweise nicht die neuesten Funktionen unterstützen?

Basierend auf dem Gleichgewicht dieser Probleme müssen Sie die richtige Wahl treffen, welche Route Sie einschlagen möchten. Ich persönlich sehe aus Gründen der Konsistenz wenig Wert in der Konsistenz und würde es vorziehen, die neuesten, besten Methoden zu verwenden, es sei denn, dies ist mit erheblichen Kosten verbunden.

Natürlich gibt es eine dritte Option: den vorhandenen Code neu zu schreiben, damit er die besten Methoden verwendet und konsistent ist. Es gibt Zeiten, in denen dies notwendig ist, jedoch mit hohen Kosten verbunden ist.


7
Sehr gute und ausgewogene Antwort (+1). Meiner Erfahrung nach kann ein Team produktiver sein, wenn sich alle auf einen relativ kleinen Satz gut verstandener Redewendungen einigen, als wenn jedes Teammitglied neue und andere Redewendungen verwenden kann, die für andere Teammitglieder möglicherweise schwer zu verstehen sind. Ein kleiner Punkt in Bezug auf die Aussage "Umschreiben des vorhandenen Codes, damit er die neuesten Methoden verwendet und konsistent ist": "Aktuell" bedeutet nicht automatisch "Besser". Man muss sich immer von Fall zu Fall entscheiden.
Giorgio

1
@Giorgio, danke für das Feedback; Ich habe die Sprache des letzten Punktes angepasst.

6
Gute Antwort und guter Kommentar von Giorgio. Vielleicht sollte man bedenken, dass in diesem Beispiel je nach Team / Kultur eine koordinierte Teamadoption möglich ist, anstatt alleine zu beginnen. Dies reduziert ein gewisses Risiko bei der Wartung (da alle an Bord sind). (dh mehr Gewicht auf die tatsächlichen Fähigkeiten des Teams im Moment legen als auf den Code, den sie in der Vergangenheit geschrieben haben.)
Matt

+1. Einverstanden, eine gründliche und ausgewogene Antwort - gute Berücksichtigung einer Vielzahl von Szenarien. Wieder ein guter Kommentar von Giorgio.
Robert Johnson

1
In Bezug auf die Übernahme neuer Redewendungen, Technologien: Ich würde den Beginn eines neuen Projekts als einen guten Punkt betrachten, um neue Dinge einzuführen. Anschließend sollte der Stil des Codes während der gesamten Projektdauer so konsistent wie möglich gehalten werden. Ich musste kürzlich einen 5 Jahre alten Code ausgraben und war sehr froh, dass ich mich immer noch in diesem Code zurechtfinden konnte, da das gesamte Team an einer gemeinsamen Architektur und einer Reihe von Redewendungen festhielt, auf die wir uns geeinigt hatten (nicht ohne Mühe! ) zu Beginn des Projekts.
Giorgio

26

Konsequent zu bleiben hat aus meiner Sicht wenig Wert. Kontinuierliche Verbesserungen sind ein Muss.

Die Position Ihres Kollegen behindert Innovation wirklich. Das Konsistenzargument versetzt Sie in eine Situation, in der Sie beispielsweise LINQ nur verwenden können, wenn Sie den gesamten Code für die Verwendung von LINQ migrieren . Und dafür haben wir keine Zeit, oder?

Ich hätte lieber eine Inkonsistenz, wenn ein Teil des Codes noch foreachüber ArrayLists ausgeführt wird und andere Teile LINQ verwenden IEnumerable<T>, anstatt bis zum Ende der Zeit bei der ältesten Vorgehensweise zu bleiben.

Es liegt in der Verantwortung Ihrer Kollegen, relevant zu bleiben und neue Methoden zu erlernen.


3
"Es liegt in der Verantwortung Ihrer Kollegen, relevant zu bleiben und neue Methoden zu erlernen.": Eine Möglichkeit besteht darin, neue Redewendungen und Bibliotheken in neuem Code (neuen Modulen) zu verwenden und einen konsistenten Stil im Legacy-Code beizubehalten.
Giorgio

8

API-Konsistenz ist sehr wichtig, sowohl für öffentliche als auch für interne APIs.

Die Konsistenz der Code-Formatierung ist wichtig und sollte im Idealfall durch ein automatisches Formatierungs-Tool mit denselben Formatierungsregeln für alle erzwungen werden. Erleichtert das Leben mit gemeinsam genutzter versionskontrollierter Codebasis.

Namenskonventionen sollten konsistent sein, auch für Dinge wie lokale Variablen usw.

Statische Analyse-Tools sollten verwendet werden, um bestimmte andere Konventionen und bewährte Methoden durchzusetzen (aber befolgen Sie die Standardeinstellungen eines solchen Tools nicht blind, da die Standardeinstellungen manchmal an den Wahnsinn grenzen können) überprüfe (normalerweise mit einer Direktive in einem Kommentar) vorübergehend, ob du es rechtfertigen kannst.

Was in Funktionen / Methoden geschieht , muss abgesehen von den oben aufgeführten in keiner Weise konsistent sein, solange es sich um guten Code für sich handelt . Guter, verständlicher und gut kommentierter Code ist sehr wichtig, aber wenn Compiler und statische Analysetools davon ausgehen, dass es sich um konsistenten Code handelt, ist dies konsistent genug.


Über neue Sprachfunktionen wie LINQ (nun ja, das ist nicht gerade neu) muss nur nachgedacht werden, ob überall dort, wo der Code verwendet wird, eine ausreichend neue Version von Sprache / Bibliotheken verwendet wird. Im Zweifelsfall sollten Sie sich an Funktionen halten, von denen bekannt ist, dass sie kompatibel sind. Dies hindert Sie natürlich nicht daran, ein Versions-Upgrade im gesamten System durchzuführen, sodass Sie die neuen nützlichen Funktionen nutzen können.

Und jeder Entwickler, der mit Code arbeitet, sollte auf dem neuesten Stand sein, so dass jeder .NET-Entwickler LINQ kennen sollte, und wenn nicht, sollten sie gezwungen sein, zu ihrem eigenen Besten zu lernen (Sie wissen nie, wann Sie nach einem neuen suchen werden) Job in diesem Geschäft, aus dem einen oder anderen Grund).


6

Die Antwort darauf ist einfach.

Konsistenz ist von größter Bedeutung.

aber es kommt mit einer Einschränkung ...

Sie und Ihre Mitarbeiter sind wahrscheinlich besessen von der falschen Art von Konsistenz

Implementierungen sind verfügbar. Sie können je nach Qualität und Umfang der Testsuite mit unterschiedlichem Aufwand komplett überarbeitet werden. Machen Sie sich Gedanken über Dinge wie "Sollte dies eine Eigenschaft sein?", "Sollte Code nicht LINQ anstelle eines Konstrukts einer niedrigeren Ebene verwenden?" ist von zweifelhaftem Wert. Es ist sehr unterschiedlich, Messungen an den Wert der Konsistenz auf Implementierungsebene zu binden. Eine viel bessere Frage auf dieser Ebene ist "Funktioniert dieser Code wie angekündigt?". TL; DR-Implementierungskonsistenz ist der Punkt, an dem "kleine Geister" ihre Hobgoblins reizen.

Warum ist Konsistenz hier nicht so wichtig? Implementierungen haben in der Regel eine geringe Anzahl von Mitwirkenden. Die meisten Methoden werden geschrieben und nie wieder angerührt. Vom restlichen Code hat die Anzahl der Methoden, die zwei Mitwirkende haben, mit ziemlicher Sicherheit die Mehrheit. Dieses Muster setzt sich unendlich fort . In diesem Zusammenhang ist Konsistenz einfach nicht so wichtig. Wenn die Haltbarkeit des Codes ziemlich gering ist ( einige Jahre ), spielen die Vorteile einer aggressiven Konsistenz wahrscheinlich keine Rolle.

Das soll nicht heißen, dass Sie bei Ihren Implementierungen verrückt werden sollten. Es ist eher zu sagen, dass ein schönes, sauberes, einfaches Design für Ihren hypothetischen zukünftigen Betreuer um Größenordnungen wertvoller sein wird als die dumme Konsistenz der Kesselplatten von Methode zu Methode. Das bringt uns zum eigentlichen Punkt ...

APIs sind nicht verfügbar.

Dies sind alle APIs auf Code-Ebene, Webservices, SDKs usw. Diese müssen konsistent sein. Die Produktivitätsgewinne aus dieser Vielfalt von Konsistenz sind aus einer Reihe von Gründen enorm:

Integrationstests:

Wenn Sie Ihre APIs konsistent halten, können Sie eine Reihe von Integrationstests erstellen. Dadurch können Entwickler die Implementierungsdetails frei austauschen und eine sofortige Validierung durchführen. Willst du deine Arbeitskollegen auf LINQ tauschen? Laufen die Integrationstests? Es bietet auch eine Validierung bei der Vorbereitung der Produktionsaufnahme. Weil Computer schnell sind, kann ein einzelner Laptop die Arbeit von tausend Testern ausführen, die alltägliche Aufgaben ausführen. Dies ist gleichbedeutend mit einer erheblichen Erhöhung der Mitarbeiterzahl Ihres Unternehmens.

Produktivität

Wenn die APIs konsistent sind, können Sie Ratschläge zur Verwendung einer API abgeben, indem Sie einfach nachvollziehen, was Sie über die Verwendung anderer Teile der API gelernt haben. Dies liegt daran, dass die API ein natürliches, konsistentes "Look and Feel" bietet. Dies bedeutet, dass Ihr Kunde weniger Zeit für das Durchsuchen der Dokumentation benötigt. Onboarding ist einfacher und billiger. Es werden weniger Fragen an die Personen gestellt, die die API entwickelt haben. Konsistenz macht jeden zum Gewinner

Warum ist Konsistenz in diesem Szenario wichtig? Weil APIs das genau entgegengesetzte Problem von Implementierungen haben. Die Anzahl der Personen, die sie verwenden, ist in der Regel viel höher als die Anzahl der Personen, die zu ihren Implementierungen beitragen. Kleine Gewinne aus einer geringen Konsistenz werden vervielfacht und die Kosten für die Aufrechterhaltung dieser Konsistenz werden amortisiert.

Fazit

Konsistenz ist teuer. Auf den ersten Blick verringert es die Produktivität. Das schränkt Entwickler ein und macht ihnen das Leben schwerer. Sie schränkt die Art und Weise ein, wie sie ein Problem lösen können, und zwingt sie manchmal, es auf nicht optimale Weise zu lösen. Dies geschieht häufig aus Gründen, die sie nicht verstehen, schlecht verstehen oder die sie nicht kennen (Verträge, größere organisatorische oder organisationsübergreifende Richtlinien).

Raymond Hettinger hat in seinem Pycon 2015-Vortrag einige hervorragende Punkte in Bezug auf die Verwendung des PEP8-Styleguides für Teams von Python-Programmierern hervorgehoben. Er zeigte, dass die Besessenheit von stilistischer Konsistenz bei einem Teil des Codes dazu führte, dass Code-Reviewer schwerwiegende Logik- und Designfehler übersahen. Seine Hypothese lässt sich zusammenfassen, da es einfach ist, stilistische Inkonsistenzen zu finden. Es ist schwierig, die tatsächliche Qualität eines Codeteils zu bestimmen

Der Punkt hier ist kritisch. Identifizieren Sie, wo Konsistenz wichtig ist, und schützen Sie sie aggressiv. Wo es nicht wichtig ist, verschwende deine Zeit nicht. Wenn Sie keinen objektiven Weg finden, um den Wert der Konsistenz zu messen (in den oben genannten Fällen "effektive Mitarbeiterzahl", Kosten als Funktion der Produktivität), und Sie nicht nachweisen können, dass die Renditen erheblich sind, tun Sie dies wahrscheinlich nicht deine Organisation.


4

Nicht mit LINQ vertraut? Wenn ja, wäre mein Code für meine Kollegen nicht besser zu pflegen, wenn ich ihn nicht verwenden würde?

Die C # -Sprache entwickelt sich weiter. Wenn die Leute die Änderungen von C # 1 nicht kennen würden, würden sie Folgendes verpassen:

  • Generika
  • Teilstücke
  • Anonyme Methoden
  • Iteratoren
  • Nullable-Typen
  • Auto-Eigenschaften
  • Anonyme Typen
  • Erweiterungsmethoden
  • Leng
  • Lambdas
  • Asynchrone Methoden

Dies ist nur eine kleine Auswahl allgemeiner Merkmale, die im Wikipedia-Artikel zu finden sind. Der Punkt, den ich mache, ist, dass, wenn die Entwickler nicht lernen, die Codebasis in einem Vakuum bleibt. Man würde hoffen, dass sich Ihre Entwickler kontinuierlich verbessern und die Codebasis weiterentwickelt, unterstützt von einer vollständigen Testsuite. Erinnern Sie sich, wie schlecht es mit .NET 1 war, Eigenschaften manuell zu implementieren?

Linq macht das Leben leichter. Verwenden Sie es, wo Sie können. Sie könnten Ihre Teammitglieder motivieren.

Inwieweit sind Muster Teil des Codestils, und wo sollten wir die Grenze zwischen Konstanz und Verbesserungen ziehen?

Verbesserungen sind schrittweise. Für mich macht es keinen Sinn, alten Code beizubehalten, der weniger lesbar und möglicherweise weniger wartbar ist. Ihre Teammitglieder sollten zumindest in der Lage sein, herauszufinden, was los ist, auch wenn sie es nicht schreiben können.


2
Ich stimme dem, was Sie sagen, voll und ganz zu, aber meine Frage bezieht sich weniger auf neue Sprachfunktionen und die Verantwortung der Entwickler, diese zu erlernen, als vielmehr auf die allgemeinere Frage, ähnliche Probleme auf unterschiedliche Weise in einem relativ kleinen Bereich einer Codebasis zu lösen. Ich habe LINQ erwähnt, weil es ein gutes Beispiel für eine andere Art der Problemlösung ist. Mein Kollege nutzt gerne neue Sprachfunktionen, aber nur, wenn sie nicht gegen den Code verstoßen, an dem er gerade arbeitet.
Robert Johnson

@RobertJohnson Ich möchte Ihren Kollegen darauf hinweisen, dass Wartbarkeit die Konsistenz übertrifft. Selbst wenn also etwas gegen den Strich des vorhandenen Codes geht, sollten Sie es tun, wenn es besser wartbar ist. Ich bezweifle, dass die Verwendung des alten Stay-DAO besser zu warten wäre als Linq.
Andy

3

Sie sollten konsistent sein, aber nicht unbedingt mit dem alten Code. Das heißt, Ihr Team sollte sich auf die richtige Vorgehensweise einigen und diese verwenden, wenn neuer Code geschrieben oder wesentliche Änderungen vorgenommen werden.

Auf diese Weise profitieren Sie von den meisten Vorteilen der Konsistenz (insbesondere spielt es keine Rolle, wer den Code schreibt), können sich jedoch noch verbessern, wenn das Team einen klaren Vorteil sieht, wenn Sie die Dinge auf andere Weise erledigen.

In einer idealen Welt würden wir den gesamten alten Code neu schreiben, um ihn dem neuen richtigen Weg anzupassen. Dies ist zwar wirtschaftlich nicht tragbar, sollte aber technisch sinnvoll sein (andernfalls ist der neue Weg kein besserer) und Ihr langfristiger Plan sollte sein, ihn zu aktualisieren. Wenn sich das nicht lohnt, kümmern Sie sich nicht um den neuen Weg. Anders ausgedrückt, es muss ein klarer Vorteil für die neue Methode sein, sie für die richtige zu erklären.


1

Ich denke , es ist wichtig , um einen Code zu folgen Stil in einem Projekt zB. Namenskonventionen, Einrückungen usw.

Ich bin nicht einverstanden, dass Sie die Verwendung neuer Sprachkonstrukte oder Entwurfsmuster nur deshalb untersagen sollten, weil Ihre Kollegen sie nicht verstehen oder sie im Projekt noch nicht verwendet wurden.

Natürlich sollten diese Dinge gute Gründe für ihre Verwendung haben, z. Leistung oder Kürze, falls zutreffend.


Wofür war das Minus?
ozz

0

Ich würde sehr vorsichtig sein, wenn ich die aktuellen Designmuster blind verfolge. Wenn es keinen nennenswerten Nachteil gibt, sollte man natürlich immer versuchen, ähnliche Muster in der gesamten Codebasis zu verfolgen.

Es ist jedoch viel zu einfach, in Situationen zu geraten, in denen die Mehrheit der Entwickler das Gefühl hat, es sei "best practice", den vorhandenen schlechten Mustern zu folgen, was zu Situationen führt, in denen gute Entwickler schlechten, nicht wartbaren Code schreiben.

Auf der anderen Seite ist die Konsistenz wichtig. Wenn es um enorme Codebasen geht, ist es äußerst nützlich, ähnliche Muster zu verwenden, damit Entwickler zwar nicht jeden Zentimeter der Codebasis lesen, aber wissen, was sie zu erwarten haben.

Aus diesem Grund ist es meiner Meinung nach am besten, Richtlinien zu erstellen und zu aktualisieren, welche Muster Entwickler befolgen sollten, wenn dies möglich ist. Auf diese Weise stimmt jeder neue Code mit anderen neuen Codes überein.


-1

Wir haben regelmäßige, recht informelle technische Treffen, die jeder von uns abhalten kann. Wenn wir eine neue Technik finden, präsentieren wir sie beim Treffen. Sie bekommen in der Regel ein gutes Gefühl dafür, wie gut die Idee von Ihren Kollegen angenommen und verstanden wird. Dies hilft Ihnen bei der Entscheidung, ob es sinnvoll ist, es in Ihren Code aufzunehmen, hilft anderen, es zu entschlüsseln, wenn Sie dies tun, und stellt auch die Kontaktperson her, wenn andere Hilfe bei diesem Stil benötigen. Wenn niemand das Rad neu erfinden würde, würden wir immer noch Dinge auf Baumstämmen herumschleppen.


Wofür war die Gegenstimme?
Ant

Ich war nicht der Abwähler, aber das scheint nicht wirklich auf die Frage ausgerichtet zu sein. Es ist ein Teamprozess, der auf alles angewendet werden kann, anstatt Probleme mit dem Codierungsstil zu diskutieren. Meinen Sie nicht auch "das Rad erfunden" anstatt "das Rad neu erfunden"?

Ich nehme an, es ist semantisch, ob ein Baumstamm eine Art Rad ist oder nicht, aber es dreht sich, verringert die Reibung, hat eine Oberfläche, die in aufeinanderfolgendem Kontakt mit dem Boden steht und rund ist. Ich bin sicher, es gibt bessere Beispiele für das, was ich meine - ich werde das als Übung für den Leser belassen.
Ant
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.