Die Kunst, Code wie ein Pianist zu schreiben | JD Cloud Technology Team

Vorwort

Wie beurteilt man die Qualität eines Systems? Welche Art von System oder Software kann als hochwertig bezeichnet werden? Es kann aus drei Perspektiven betrachtet werden: Die erste ist das Architekturdesign, wie Technologieauswahl, Überlegungen zur Datenkonsistenz in verteilten Systemen usw. Die zweite ist das Projektmanagement. Unabhängig davon, ob es sich um agile Entwicklung oder Wasserfallentwicklung handelt, sollten technische Schulden bereinigt werden. , Refactoring des Codes usw., das Letzte ist untrennbar mit der Codequalität verbunden. Die Qualität des Codes wirkt sich direkt auf die Wartbarkeit und Skalierbarkeit des Systems aus. Es ist wie ein Auto. Es hat ein hochwertiges Interieur und ein schönes Aussehen, aber sein Fahrwerk ist schlecht und seine Leistung ist schwach. Man kann es kaum als gutes Auto bezeichnen. In diesem Artikel erfahren Sie, wie Sie als Programmierer aus subjektiver und objektiver Sicht sauberen und qualitativ hochwertigen Code schreiben.

subjektive Perspektive

Ingenieursgeist

Klicken Sie auf den JingME-Avatar, um zu sehen, dass unser interner Titel „xx Development Engineer“ und nicht „xx Code Writer“ lautet. Diese Abteilung kann als Master-Abteilung (Master) verstanden werden. Master-Programmierer betrachten das System als eine Geschichte, nicht als Schreiben es als Programm . Als Entwickler sollten Sie für den Code, den Sie schreiben, verantwortlich sein. Wenn Sie einer Klasse den Namen @author geben, sollten Sie das Gefühl haben, etwas erreicht zu haben. An einem Tag in der Zukunft, vielleicht in einem Jahr, zwei Jahren oder sogar fünf Jahren später, an einem anderen Kollegen werden nach dem Lesen dieses Codes aufrichtig „cool“ seufzen, anstatt sich darüber zu beschweren: „Was zum Teufel hast du geschrieben?“ Das von Doug Lea geschriebene Parallelitätspaket ist auch nach vielen Jahren immer noch berühmt.

Verbessern Sie die Lesbarkeit des Codes

Das erste, was erreicht werden sollte, ist, dass der Code so geschrieben ist, dass er von Menschen gelesen werden kann . Er ist nur grundlegend für die Ausführung durch Maschinen. Exzellenter Code benötigt nicht zu viele Kommentare. Der Code selbst ist ein Kommentar . Unter Lesbarkeit versteht man die Fähigkeit anderer Entwickler, die Absicht und Funktion des Codes schnell zu verstehen. Prägnanter Code ist einfacher zu verstehen, zu testen und zu warten. Zweitens: Vermeiden Sie Duplikate. Codeduplizierung ist die Wurzel allen Übels in der Software . Es wurden viele Prinzipien und Entwurfsmuster erstellt, um Duplikate zu vermeiden.

objektive Perspektive

Als nächstes geben wir aus objektiver Sicht Beispiele für häufige Probleme bei täglichen Codeüberprüfungen, um Ihnen eine Referenz zu geben.

versuchen/fangen verwenden

1. Der Try/Catch-Block sollte so klein wie möglich sein und Try/Catch nur für unvorhersehbare Situationen verwenden. Vorhersehbare Ausnahmen sollten vor dem Versuch überprüft werden.

Unvorhergesehene Umstände: Remote-Aufrufe, IO-Lesen und -Schreiben, APIs von Drittanbietern usw. Vorhersehbare Situationen: Ein Parameter ist leer, eine Liste enthält keine Elemente usw.



Welche Vorteile haben kleine Try/Catch-Blöcke?

  • Der Code ist aufgeräumt und kann die Einrückung anderer Codes reduzieren
  • Exquisite Ausnahmesteuerung, die für bestimmte Ausnahmen spezifische Eingabeaufforderungen, UMP-Alarme, Protokollausgaben oder Fehlercoderückgaben bereitstellen kann

2. Wenn Sie wirklich versuchen müssen, die gesamte Methode abzufangen, ist es besser, eine neue Methode zu schreiben, um die Geschäftslogikverarbeitung und die Ausnahmebehandlung zu trennen.

Zum Beispiel:



Der Try/Catch-Codeblock enthält viel Inhalt, was darauf hinweist, dass die Codekontrollfähigkeit nicht gut genug ist . Wenn es einen Try gibt, stellen Sie sicher, dass sich der Try in der ersten Zeile befindet und kein anderer Inhalt vorhanden sein sollte nach dem Fang/endlich.

Methodenlänge

Methodenlinien sollten so kurz wie möglich sein, je kürzer desto besser. Es ermöglicht den Lesern zu verstehen, was diese Methode bewirkt, sobald sie darauf klicken. Zum Beispiel:



Dies ist eine Methode zur Preisabfrage. Der Screenshot dieser Methode ist zu lang, um auf eine Seite zu passen. Wenn Sie herausfinden möchten, was diese Methode bewirkt, können Sie es nicht einfach mit den Kommentaren im Methodenkörper klären.

Führen Sie einfach einige einfache Verarbeitungsverpackungen durch. Diese Methode kann leicht verständlich werden und es ist nicht erforderlich, eine Kommentarzeile zu schreiben.

Nach einfacher Umgestaltung:







Dem obigen Code nach zu urteilen, unterteilt der erste Absatz den Preisabfragecode in zwei Teile: Zuerst wird der Genehmigungsstatus der Abfrage analysiert und dann werden die Preise entsprechend dem Genehmigungsstatus separat abgefragt. Der zweite Absatz unterteilt die Preisabfrage in zwei Teile: Der eine besteht darin, den genehmigten Preis abzufragen, der andere darin, den Preis nach der Genehmigung abzufragen, und schließlich werden beide Teile kombiniert und zurückgegeben. Der dritte Absatz ist der Code zum Abfragen des Preises während der Genehmigung. Offensichtlich gibt es zwei Modi zum Abfragen des Preises während der Genehmigung: den Prozentmodus und den Mindestpreismodus. Nach der Abfrage der Ergebnisse wird die Kombination zurückgegeben, um den Kanalpreis des Produkts zu erhalten .

Im Vergleich dazu ist es nicht schwer zu erkennen, dass der ursprüngliche Codeblock zu lang und zu tief verschachtelt ist (eine for-Schleife verschachtelt if und dann if), was zu einer eingeschränkten Lesbarkeit führt. Wenn ich einen bestimmten Code ändern möchte, muss ich sorgfältig darüber nachdenken. Aber nach der Aufteilung können Sie den Zielcodeblock schnell finden, ohne sich Gedanken über die Auswirkungen auf andere Methoden machen zu müssen. Darüber hinaus erleichtert das Unit-Testen das Schreiben von Testfällen.

Es ist verboten, die Eingabeparameterdaten innerhalb der Methode zu ändern

Aus der Sicht des Systemkonzepts können Systeme im Allgemeinen in zwei Kategorien unterteilt werden: Ein Typ erhält eine Eingabe und erhält eine Ausgabe. Dieser Typ wird als reaktionsfähig bezeichnet. Der andere Typ erhält eine Eingabe, hat aber keine Ausgabe. Dieser Typ wird als „responsive“ bezeichnet Imperativ. In ähnlicher Weise erhalten reaktive Methoden bei Methoden einen Eingabeparameter und erhalten einen Ausgabeparameter. Zu den gebräuchlichen Methoden gehören Modellkonvertierung, Datenabfrage usw., während imperative Methoden das Senden von Nachrichten und das Ausführen eines Threads umfassen.

Aber egal wie sie sich ändern, eines haben sie gemeinsam: Sie werden die Eingabedaten nicht verändern .

1. Unerwartete Nebenwirkungen verursachen: Wenn eine Methode die übergebenen Parameter ändert und der Aufrufer sich auf den ursprünglichen Parameterwert verlässt, kann dies den Aufrufer beeinträchtigen, ohne es zu wissen. Dies kann dazu führen, dass das Verhalten des Programms unvorhersehbar wird, was die Komplexität des Codes und die Fehlerwahrscheinlichkeit erhöht.
2. Datenkonsistenz zerstören: Wenn mehrere Methoden dasselbe Objekt als Parameter verwenden und diese Methoden alle das Objekt ändern können, können sich diese Methoden gegenseitig stören, was dazu führt, dass der Datenstatus chaotisch und unvorhersehbar wird.
3. Dies kann die Schwierigkeit der Codewartung erhöhen: Wenn eine Methode die übergebenen Parameter ändert, muss sich der Code, der die Methode aufruft, möglicherweise auf dieses Änderungsverhalten verlassen. Dadurch wird die Kopplung des Codes erhöht, was dessen Verständnis, Wartung und Wiederverwendung erschwert. Wenn eine Methode geändert werden muss, müssen möglicherweise alle Stellen, an denen die Methode aufgerufen wird, gleichzeitig geändert werden, was die Wartungskosten des Codes erhöht.

Zum Beispiel:



Hier werden drei Set-Methoden aufgerufen, aber wer kann auf einen Blick erkennen, auf welches Objekt sie den Wert setzt? Sie müssen eine nach der anderen anklicken, um die spezifische Implementierung anzuzeigen und zu wissen, wo Werte zugewiesen werden müssen.

Wenn Sie den Wert eines Parameters wirklich ändern müssen, können Sie ein neues Objekt erstellen, um das geänderte Ergebnis zu speichern und an den Aufrufer zurückzugeben. Dadurch bleibt Ihr Code klar, wartbar und testbar und es werden unbeabsichtigte Nebenwirkungen und Datenkonsistenzprobleme reduziert.

Methodenparameter

Je weniger Parameter eine Methode hat, desto besser. Der ideale Parameter ist kein Parameter, gefolgt von einem einzelnen Parameter. Drei oder mehr Parameter sollten so weit wie möglich vermieden werden.

Wenn wir mit dem obigen Code fortfahren, lautet die letzte Zeile „Kanaltyp festlegen“. Die Set-Methode enthält zwei Eingabeparameter. Sie können das Zuweisungsobjekt extrahieren und einen Eingabeparameter wie folgt reduzieren:



Wenn die Verarbeitungslogik einer Methode nur auf den Daten eines bestimmten lokalen Variablenobjekts basiert, kann diese Methode innerhalb des Objekts platziert werden, um die Methodenparameter weiter zu reduzieren und die Wiederverwendbarkeit des Codes zu verbessern, zum Beispiel:



Unter diesem Gesichtspunkt wurden die beiden Parametereingabemethoden erfolgreich auf eine parameterfreie Methode reduziert. Im Vergleich zum Originalcode ist der Umfang der Originalcodemethode auf das Innere der Klasse beschränkt, und der endgültige Parameter- Die kostenlose Methode muss nur die Zielobjektinstanzen abrufen und kann überall aufgerufen werden, wodurch die Notwendigkeit reduziert wird, doppelten Code zu schreiben.

Einrückung reduzieren

Eine große Einrückung im Code beeinträchtigt offensichtlich das Lesen. Wenn möglich, sollten wir die Einrückung und die Ebene im Code so weit wie möglich reduzieren. Guter Code sollte sich wie eine Zeitung lesen, mit einem ordentlichen und eleganten Layout, anstatt Treppen zu steigen.

Schauen wir uns den folgenden Code an:



Es gibt zwei Ebenen der if-Verschachtelung im Code. Erstens können wir die erste Ebene der if-Verschachtelung vereinfachen und einfach die Beurteilungsbedingung von if umkehren, um den folgenden Code zu erhalten:



Dies reduziert die Einrückung um eine Ebene und führt dann zu einer Feinabstimmung der Variablen und Parameter:



Wird auf diese Weise im Vergleich zum vorherigen Code die Lesbarkeit verbessert?

Einzelverantwortung

In der objektorientierten Programmierung bedeutet das „Single-Responsibility-Prinzip“ (SRP), dass eine Klasse oder ein Modul nur einen Grund für ihre Änderung haben sollte, d. h. eine Klasse oder ein Modul sollte nur eine Hauptverantwortung oder ein Hauptziel haben. Durch die Verfeinerung von Funktionen und Verantwortlichkeiten können die Wartbarkeit, Wiederverwendbarkeit und Skalierbarkeit des Codes verbessert werden.

Schauen Sie sich den folgenden Code an:



Aus Sicht der Deklaration wird diese Methode zum Speichern von Aufgabendaten verwendet. Wenn jedoch einige Daten in den Eingabeparametern nicht leer sind (tatsächlich ist es schwierig, die spezifischen Daten auf einen Blick zu erkennen, wenn man sich die Implementierung ansieht). Methode), wird der Aktualisierungsvorgang durchgeführt. Diese Schreibweise verwirrt nicht nur die Leser, sondern verringert auch die Skalierbarkeit des Codes.

F: Verstößt die Methode „compareAndSet“ von AtomicInteger gegen die Einzelverantwortung? A: Sie verstößt nicht gegen das Prinzip der Einzelverantwortung. Die Methode „compareAndSet“ ist eine atomare Operation, die von der Klasse „AtomicInteger“ bereitgestellt wird. Sie wird verwendet, um zu vergleichen, ob der aktuelle Wert einem bestimmten erwarteten Wert entspricht. Bei Gleichheit wird der aktuelle Wert auf einen neuen Wert gesetzt. Die Aufgabe dieser Methode besteht darin, atomare Vergleichs- und Set-Operationen zu implementieren, um die Thread-Sicherheit in einer Multithread-Umgebung sicherzustellen. Die Methode „compareAndSet“ ist als eine der Operationen darauf ausgelegt, spezifische Anforderungen zu erfüllen und verstößt nicht gegen das Prinzip der Einzelverantwortung. Das Prinzip der Einzelverantwortung erfordert, dass eine Klasse oder ein Modul nur eine Hauptverantwortung hat, und die Hauptverantwortung der AtomicInteger-Klasse besteht darin, atomare Ganzzahloperationen bereitzustellen. Die Methode CompareAndSet ist Teil davon und Teil der Hauptverantwortung der Klasse. Daher verstößt die Methode „compareAndSet“ nicht gegen das Prinzip der Einzelverantwortung.     

Verwenden Sie eine aussagekräftige Benennung

Im folgenden Code ist der Rückgabewert von checkParam ein boolescher Wert, aber als Leser weiß ich nicht, ob er „True“ zurückgeben soll, wenn die Prüfung erfolgreich ist, oder „True“, wenn die Prüfung fehlschlägt.



Im Allgemeinen wird check am Anfang als Methodenname verwendet und hat keinen Rückgabewert. Wenn die Prüfung fehlschlägt, wird eine Ausnahme ausgelöst. Methoden, die boolesche Werte zurückgeben, beginnen normalerweise mit is. Mal sehen, ob es einfacher zu lesen wäre, wenn wir es anders schreiben würden.



Verwenden Sie eine aussagekräftige Benennung

Typisch ist hier der bedingte Beurteilungsknoten in der Flussanordnungsdatei, der bedeutungslose Zahlen wie 0 und 1 verwendet. Es ist schwierig, auf einen Blick zu erkennen, was gesagt wird. Sie müssen einzeln darauf klicken, um das zu sehen Logik, um es zu sortieren und in etwas Sinnvolles umzuwandeln. Benennen Sie es zum leichteren Verständnis.



Benennungsregeln für Klassen und Methoden

Klassennamen verwenden Substantive oder Nominalphrasen, Namen verwenden Verben oder Gerundiumstrukturen

Dies ist leichter zu verstehen, daher werde ich vorerst keine Beispiele nennen.

Hinterlassen Sie keine irrelevanten Inhalte

Überprüfen Sie vor dem Einleiten von MR, ob der Code „kommentierten Code“ und TODO enthält.

Wenn andere Entwickler später eingreifen, sind sie für den auskommentierten Code sehr verwirrt. Warum sollten diese beiden Codezeilen auskommentiert werden? Sind sie wichtig? Sind sie da, weil sie eines Tages gebraucht werden? Oder haben Sie damals einfach vergessen, es zu löschen? Oder soll es als Erinnerung für zukünftige Änderungen dienen? Diese Bedenken können andere Entwickler daran hindern, den kommentierten Code zu bereinigen, was dazu führen kann, dass der Code dauerhaft erhalten bleibt und „Geistercode“ entsteht.

Für TODO wird empfohlen, dass Sie beim Schreiben von ToDo Ihr ERP im Auge behalten, wer das Problem lösen wird, wie es gelöst werden soll und wann die Frist abläuft. Denn in den meisten Fällen ist Later gleich never . Mit der Zeit vergaß selbst ich diese Aufgabe, warum ich sie damals geschrieben hatte und wie ich damit umgehen sollte, was versteckte Gefahren für das System aufzeigte.



Wie oben erwähnt, ist der Kollege, der dieses TODO geschrieben hat, zurückgetreten, und jetzt weiß nur noch Gott, was das TODO ist.

aufzählen

Entwickeln Sie eine gute Angewohnheit. Wenn Sie durch Aufzählungen definierte Variablen verwenden, ziehen Sie einen Verweis auf die Aufzählung, um anderen Entwicklern das Lesen zu erleichtern.

Zum Beispiel:



Dies ist eine erschöpfbare Variable (da die Zustände begrenzt sind), aber der Leser kennt die spezifischen Zustände nicht. Damit ist tatsächlich eine Aufzählung verbunden.



Um das Lesen zu erleichtern, können Sie die @see/@link-Methode von javaDoc verwenden, in der die Variable definiert wird, um den Aufzählungsbereich dieser Variablen anzugeben.



Gerätetest

Die Bedeutung eines einzelnen Tests liegt auf der Hand. Lassen Sie uns hier zuerst ein Loch graben und später einen separaten Artikel schreiben.

Abschluss

Am Ende des Schreibens möchte ich jedem ein klassisches Buch „Code Cleanliness“ empfehlen. Tatsächlich wurde das Buch früher veröffentlicht, und einige der im Buch enthaltenen Kenntnisse sind möglicherweise etwas veraltet, aber die ersten paar Kapitel sind immer noch lesenswert. Sauberer Code erfordert die gemeinsamen Anstrengungen des Teams. Teammitglieder sollten einheitliche Codierungsstile und -standards befolgen, Codeüberprüfungen und Wissensaustausch durchführen und gemeinsam die Codequalität aufrechterhalten und verbessern. Es handelt sich nicht nur um einen Codierungsstil, sondern um eine Denkweise und Werte . Eleganter Code ist wie ein Kunstwerk, und wie der Titel schon sagt, sollte er wie ein Pianist geschrieben werden.

Autor: JD Retail Tan Lei

Quelle: JD Cloud Developer Community Bitte geben Sie beim Nachdruck die Quelle an

Lei Jun: Die offizielle Version von Xiaomis neuem Betriebssystem ThePaper OS wurde verpackt. Das Popup-Fenster auf der Lotterieseite der Gome App beleidigt seinen Gründer. Ubuntu 23.10 ist offiziell veröffentlicht. Sie können den Freitag genauso gut für ein Upgrade nutzen! Ubuntu 23.10-Release-Folge: Das ISO-Image wurde dringend „zurückgerufen“, da es Hassreden enthielt. Ein 23-jähriger Doktorand behob den 22 Jahre alten „Ghost Bug“ in Firefox. RustDesk Remote Desktop 1.2.3 wurde veröffentlicht, verbessertes Wayland zur Unterstützung von TiDB 7.4 Release: Offiziell kompatibel mit MySQL 8.0. Nach dem Abziehen des Logitech USB-Empfängers stürzte der Linux-Kernel ab. Der Master verwendete Scratch, um den RISC-V-Simulator zu rubbeln, und führte den Linux-Kernel erfolgreich aus. JetBrains startete Writerside, ein Tool zur Erstellung technischer Dokumente.
{{o.name}}
{{m.name}}

Ich denke du magst

Origin my.oschina.net/u/4090830/blog/10120040
Empfohlen
Rangfolge