Lesbarkeit des Codes



Code wird zum Erstellen von Schnittstellen verwendet. Der Code selbst ist jedoch eine Schnittstelle.


Trotz der Tatsache, dass die Lesbarkeit von Code sehr wichtig ist, ist dieses Konzept schlecht definiert - und häufig nur in Form von Regeln: Verwenden Sie aussagekräftige Variablennamen, teilen Sie große Funktionen in kleinere auf und verwenden Sie Standardentwurfsmuster.

Zur gleichen Zeit musste sich sicher jeder mit einem Code befassen, der diesen Regeln entspricht, aber aus irgendeinem Grund ist es eine Art Chaos.

Sie können versuchen, dieses Problem zu lösen, indem Sie neue Regeln hinzufügen: Wenn die Variablennamen sehr lang werden, müssen Sie die Hauptlogik umgestalten. Wenn sich in einer Klasse viele Hilfsmethoden angesammelt haben, sollte sie möglicherweise in zwei unterteilt werden. Entwurfsmuster können nicht im falschen Kontext angewendet werden.

Solche Anweisungen werden zu einem Labyrinth subjektiver Entscheidungen, und um darin zu navigieren, benötigen Sie einen Entwickler, der die richtige Wahl treffen kann - das heißt, er muss bereits lesbaren Code schreiben können.

Daher ist eine Reihe von Anweisungen keine Option. Daher müssen wir ein umfassenderes Bild der Lesbarkeit von Code formulieren.

Warum Lesbarkeit benötigt wird


In der Praxis bedeutet eine gute Lesbarkeit normalerweise, dass der Code gut zu lesen ist. Bei einer solchen Definition kann man jedoch nicht weit kommen: Erstens ist sie subjektiv und zweitens verpflichtet sie uns, einen gewöhnlichen Text zu lesen.

Ein unlesbarer Code wird als Roman wahrgenommen, der vorgibt, ein Code zu sein: Viele Kommentare enthüllen die Essenz des Geschehens, Textblätter, die nacheinander gelesen werden müssen, intelligente Formulierungen, deren einzige Bedeutung darin besteht, „intelligent“ zu sein, Angst vor der Wiederverwendung von Wörtern. Der Entwickler versucht, den Code lesbar zu machen, zielt jedoch auf den falschen Lesertyp ab.

Textlesbarkeit und Codelesbarkeit sind nicht dasselbe.

Übersetzt nach Alconost

Code wird zum Erstellen von Schnittstellen verwendet. Der Code selbst ist jedoch eine Schnittstelle.

Wenn der Code schön aussieht, bedeutet das, dass er lesbar ist? Ästhetik ist ein angenehmer Nebeneffekt der Lesbarkeit, aber als Kriterium nicht sehr nützlich. Vielleicht hilft in extremen Fällen die Ästhetik des Codes im Projekt, Mitarbeiter zu binden - aber mit dem gleichen Erfolg können Sie ein gutes soziales Paket anbieten. Darüber hinaus hat jeder seine eigene Vorstellung davon, was „schöner Code“ bedeutet. Und im Laufe der Zeit wird diese Definition der Lesbarkeit zu einem Strudel von Streitigkeiten über Tabellierungen, Leerzeichen, Klammern, „Kamelnotation“ usw. Es ist unwahrscheinlich, dass jemand das Bewusstsein verliert, wenn er die falsche Einrückung sieht, obwohl dies bei der Überprüfung des Codes Aufmerksamkeit erregt.

Wenn der Code weniger Fehler erzeugt, kann er als besser lesbar angesehen werden? Je weniger Fehler, desto besser, aber welchen Mechanismus gibt es? Wie kann ich die vagen angenehmen Empfindungen zuschreiben, die Sie beim Lesen des Codes erleben? Unabhängig davon, wie stirnrunzelnd die Augenbrauen beim Lesen des Codes sind, werden dadurch keine Fehler hinzugefügt.

Wenn der Code leicht zu bearbeiten ist, ist er lesbar? Aber das ist vielleicht die richtige Richtung des Denkens. Anforderungen ändern sich, Funktionen werden hinzugefügt, Fehler treten auf - und irgendwann muss jemand Ihren Code bearbeiten. Und um keine neuen Probleme zu verursachen, muss der Entwickler verstehen, was genau er bearbeitet und wie die Änderungen das Verhalten des Codes ändern. Wir haben also eine neue heuristische Regel gefunden: Lesbarer Code sollte leicht zu bearbeiten sein.

Welcher Code ist einfacher zu bearbeiten?


Ich möchte sofort verwischen: "Der Code ist einfacher zu bearbeiten, wenn die Namen der Variablen sinnvoll angegeben werden", aber wir benennen "Lesbarkeit" einfach in "Einfache Bearbeitung" um. Wir brauchen ein tieferes Verständnis und nicht das gleiche Regelwerk in einer anderen Gestalt.

Vergessen wir zunächst für einen Moment, dass es sich um Code handelt. Das mehrere Jahrzehnte alte Programmieren ist nur ein Punkt auf der Skala der Menschheitsgeschichte. Wenn wir uns auf diesen „Punkt“ beschränken, können wir nicht tief graben.

Betrachten wir daher die Lesbarkeit durch das Prisma des Entwerfens von Schnittstellen, auf die wir bei fast jedem Schritt stoßen - und nicht nur bei digitalen. Das Spielzeug verfügt über Funktionen, die es zum Fahren oder Quietschen bringen. Die Tür verfügt über eine Schnittstelle, über die Sie sie öffnen, schließen und verriegeln können. Die Daten im Buch werden auf Seiten gesammelt, was einen schnelleren Direktzugriff als das Scrollen ermöglicht. Wenn Sie Design studieren, können Sie viel mehr über diese Schnittstellen erfahren - fragen Sie das Designteam, wenn Sie können. Im Allgemeinen bevorzugen wir alle gute Schnittstellen, auch wenn wir nicht immer wissen, was sie gut macht.

Code wird zum Erstellen von Schnittstellen verwendet. Der Code selbst ist in Kombination mit der IDE eine Schnittstelle. Eine Schnittstelle für eine sehr kleine Gruppe von Benutzern - unsere Kollegen. Weiter werden wir sie "Benutzer" nennen - um im Bereich der Gestaltung der Benutzeroberfläche zu bleiben.

Betrachten Sie vor diesem Hintergrund die folgenden Beispiele für Benutzerpfade:

  • Der Benutzer möchte eine neue Funktion hinzufügen. Dies erfordert das Finden des richtigen Ortes und das Hinzufügen einer Funktion, ohne neue Fehler zu generieren.
  • Der Benutzer möchte den Fehler beheben. Er muss die Ursache des Problems finden und den Code bearbeiten, damit der Fehler verschwindet und keine neuen Fehler auftreten.
  • Der Benutzer möchte sicherstellen, dass sich der Code in Grenzfällen auf eine bestimmte Weise verhält. Er muss einen bestimmten Code finden, dann die Logik verfolgen und simulieren, was passiert.

Und so weiter: Die meisten Pfade folgen einem ähnlichen Muster. Um die Dinge nicht zu komplizieren, betrachten Sie bestimmte Beispiele - aber vergessen Sie nicht, dass dies eine Suche nach allgemeinen Prinzipien ist, keine Liste von Regeln.

Wir können davon ausgehen, dass der Benutzer den gewünschten Codeabschnitt nicht sofort öffnen kann. Dies gilt auch für Ihre eigenen Hobbyprojekte: Selbst wenn die Funktion von Ihnen geschrieben wurde, können Sie leicht vergessen, wo sie sich befindet. Daher sollte der Code so sein, dass es einfach ist, den richtigen darin zu finden.

Um eine bequeme Suche zu implementieren, benötigen Sie eine Suchmaschinenoptimierung - hier helfen uns aussagekräftige Variablennamen. Wenn der Benutzer die Funktion nicht finden kann und sich von einem bekannten Punkt aus entlang des Aufrufstapels bewegt, kann er eine Suche nach Schlüsselwörtern starten. Sie können jedoch nicht zu viele Schlüsselwörter in die Namen aufnehmen. Bei der Suche nach Code wird der einzige Einstiegspunkt gesucht, von dem aus Sie weiterarbeiten können. Daher muss der Benutzer helfen, an einen bestimmten Ort zu gelangen. Wenn Sie dies mit Schlüsselwörtern übertreiben, werden zu viele nutzlose Suchergebnisse angezeigt.

Wenn der Benutzer sofort überprüfen kann, ob auf einer bestimmten Logikebene alles korrekt ist, kann er die vorherigen Abstraktionsebenen vergessen und seinen Geist für die nächste freigeben.

Sie können auch mithilfe der automatischen Vervollständigung suchen: Wenn Sie eine allgemeine Vorstellung davon haben, welche Funktion Sie aufrufen möchten oder welche Aufzählung Sie verwenden möchten, können Sie mit der Eingabe des beabsichtigten Namens beginnen und dann die entsprechende Option aus der Liste der automatischen Vervollständigung auswählen. Wenn die Funktion nur für bestimmte Fälle vorgesehen ist oder Sie ihre Implementierung aufgrund der Verwendungsmerkmale sorgfältig lesen müssen, können Sie dies durch einen authentischeren Namen angeben: Durch Scrollen durch die Liste der automatischen Vervollständigung vermeidet der Benutzer eher, was kompliziert aussieht - es sei denn, er ist sich sicher , Was macht.

Daher werden kurze reguläre Namen eher als Standardoptionen wahrgenommen, die für "Gelegenheitsbenutzer" geeignet sind. Bei Funktionen mit solchen Namen sollte es keine Überraschungen geben: Sie können keine Setter in Funktionen einfügen, die wie einfache Getter aussehen, aus demselben Grund, aus dem die Schaltfläche Ansicht in der Benutzeroberfläche keine Benutzerdaten ändern sollte.




In der Client-Oberfläche verzichten vertraute Funktionen wie eine Pause fast auf Text. Wenn die Funktionalität komplexer wird, verlängern sich die Namen, wodurch Benutzer langsamer werden und nachdenken. Screenshot - Pandora

Benutzer möchten schnell die richtigen Informationen finden. In den meisten Fällen nimmt die Kompilierung viel Zeit in Anspruch, und in einer laufenden Anwendung müssen Sie viele verschiedene Grenzfälle manuell überprüfen. Wenn möglich, lesen unsere Benutzer den Code lieber und verstehen, wie er sich verhält, als Haltepunkte zu setzen und den Code auszuführen.

Um den Code nicht ausführen zu können, müssen zwei Bedingungen erfüllt sein:

  1. Der Benutzer versteht, was der Code versucht.
  2. Der Benutzer ist sicher, dass der Code das tut, was er behauptet.

Abstraktionen helfen dabei, die erste Bedingung zu erfüllen: Benutzer sollten in der Lage sein, bis zur gewünschten Detailebene in Abstraktionsebenen einzutauchen. Stellen Sie sich eine hierarchische Benutzeroberfläche vor: Auf den ersten Ebenen wird die Navigation über umfangreiche Abschnitte ausgeführt und dann immer konkreter - auf der Ebene der Logik, die genauer untersucht werden muss.

Das sequentielle Lesen einer Datei oder Methode erfolgt in linearer Zeit. Wenn der Benutzer jedoch die Aufrufstapel auf und ab bewegen kann - dies ist eine Suche im Baum - und wenn die Hierarchie gut ausbalanciert ist, wird diese Aktion in einer logarithmischen Zeit ausgeführt. Es gibt sicherlich Platz für Listen in Schnittstellen, aber Sie sollten sorgfältig überlegen, ob in einem bestimmten Kontext mehr als zwei oder drei Methodenaufrufe vorhanden sein sollten.




In kurzen Menüs ist die hierarchische Navigation viel schneller. Im "langen" Menü rechts - nur 11 Zeilen. Wie oft passen wir in diese Zahl im Methodencode? Screenshot - Pandora

Unterschiedliche Benutzer haben unterschiedliche Strategien für die zweite Bedingung. In Situationen mit geringem Risiko sind Kommentare oder Methodennamen ein ausreichender Beweis. In riskanteren, komplexeren Bereichen sowie wenn der Code mit irrelevanten Kommentaren überladen ist, werden letztere wahrscheinlich ignoriert. Manchmal sind sogar die Namen von Methoden und Variablen zweifelhaft. In solchen Fällen muss der Benutzer viel mehr Code lesen und ein breiteres Logikmodell berücksichtigen. Hier hilft es auch, den Kontext auf kleine Bereiche zu beschränken, an denen man sich leicht festhalten kann. Wenn der Benutzer sofort überprüfen kann, ob auf einer bestimmten Logikebene alles korrekt ist, kann er die vorherigen Abstraktionsebenen vergessen und seinen Geist für die nächste freigeben.

In dieser Betriebsart gewinnen einzelne Token zunehmend an Bedeutung. Zum Beispiel ein boolesches Flag

element.visible = true/false 

Es ist leicht, isoliert vom Rest des Codes zu verstehen, aber dies erfordert die Kombination von zwei verschiedenen Token im Kopf. Wenn zu verwenden

 element.visibility = .visible/.hidden 

Dann kann der Wert des Flags sofort verstanden werden: In diesem Fall müssen Sie den Variablennamen nicht lesen, um herauszufinden, dass er mit der Sichtbarkeit zusammenhängt. Wir haben ähnliche Ansätze beim Entwerfen von Client-orientierten Schnittstellen gesehen. In den letzten Jahrzehnten haben sich die Schaltflächen OK und Abbrechen zu aussagekräftigeren Elementen der Benutzeroberfläche entwickelt: "Speichern" und "Abbrechen", "Senden" und "Bearbeitung fortsetzen" usw., um zu verstehen, was getan wird. Es reicht aus, wenn der Benutzer die vorgeschlagenen Optionen betrachtet, ohne den gesamten Kontext zu lesen.


Die Zeile „Offline-Modus“ im obigen Beispiel zeigt an, dass die Anwendung offline ist. Der Schalter im folgenden Beispiel hat dieselbe Bedeutung, aber um ihn zu verstehen, müssen Sie sich den Kontext ansehen. Screenshot - Pandora

Unit-Tests helfen auch dabei, das erwartete Verhalten des Codes zu bestätigen: Sie dienen als Kommentare - denen jedoch in größerem Maße vertraut werden kann, da sie relevanter sind. Richtig, sie müssen auch die Montage abschließen. Bei einer gut etablierten CI-Pipeline werden jedoch regelmäßig Tests ausgeführt, sodass Sie diesen Schritt überspringen können, wenn Sie Änderungen an vorhandenem Code vornehmen.

Theoretisch folgt Sicherheit aus einem ausreichenden Verständnis: Sobald unser Benutzer das Verhalten des Codes versteht, kann er Änderungen sicher vornehmen. In der Praxis muss man bedenken, dass Entwickler normale Menschen sind: Unser Gehirn verwendet dieselben Tricks und ist auch faul. Je weniger Aufwand Sie für das Verständnis des Codes aufwenden müssen, desto sicherer sind unsere Aktionen.

Lesbarer Code sollte die meisten Fehlerprüfungen an den Computer übergeben. Eine Möglichkeit hierfür ist die Verwendung der Debugging-Prüfungen "Assert". Sie erfordern jedoch auch die Montage und den Start. Schlimmer noch, wenn der Benutzer Grenzfälle vergessen hat, hilft die Behauptung nicht weiter. Unit-Tests zur Überprüfung auf häufig vergessene Grenzfälle können besser durchgeführt werden. Sobald der Benutzer Änderungen vorgenommen hat, müssen Sie warten, bis die Tests ausgeführt werden.

Zusammenfassend: Lesbarer Code sollte einfach zu verwenden sein. Und als Nebeneffekt kann es schön aussehen.

Um den Entwicklungszyklus zu beschleunigen, verwenden wir die im Compiler integrierte Fehlerprüffunktion. In solchen Fällen ist normalerweise keine vollständige Baugruppe erforderlich, und Fehler werden in Echtzeit angezeigt. Wie kann ich diese Gelegenheit nutzen? Im Allgemeinen müssen Sie Situationen finden, in denen Compilerprüfungen sehr streng werden. Beispielsweise prüfen die meisten Compiler nicht, wie umfassend die "if" -Anweisung beschrieben wird, sondern überprüfen den "switch" sorgfältig auf fehlende Bedingungen. Wenn ein Benutzer versucht, eine Bedingung hinzuzufügen oder zu ändern, ist es sicherer, wenn alle vorherigen ähnlichen Operatoren umfassend waren. Und wenn sich die Bedingung "case" ändert, markiert der Compiler alle anderen Bedingungen, die überprüft werden müssen.

Ein weiteres häufiges Problem der Lesbarkeit ist die Verwendung von Grundelementen in bedingten Ausdrücken. Dieses Problem ist besonders akut, wenn die Anwendung JSON analysiert, da Sie nur "if" -Anweisungen um die Gleichheit von Zeichenfolgen oder Ganzzahlen hinzufügen möchten. Dies erhöht nicht nur die Wahrscheinlichkeit von Tippfehlern, sondern erschwert den Benutzern auch die Ermittlung möglicher Werte. Bei der Überprüfung von Grenzfällen gibt es einen großen Unterschied zwischen dem Zeitpunkt, zu dem eine Linie möglich ist, und dem Zeitpunkt, zu dem nur zwei oder drei separate Optionen verfügbar sind. Selbst wenn die Grundelemente in Konstanten festgelegt sind, sollten Sie sich einmal beeilen und versuchen, das Projekt rechtzeitig abzuschließen. Andernfalls wird ein beliebiger Wert angezeigt. Wenn Sie jedoch speziell erstellte Objekte oder Aufzählungen verwenden, blockiert der Compiler die ungültigen Argumente und gibt eine bestimmte Liste gültiger Argumente an.

Wenn einige Kombinationen von Booleschen Flags nicht zulässig sind, ersetzen Sie sie durch eine einzelne Aufzählung. Nehmen Sie zum Beispiel eine Komposition, die sich in den folgenden Zuständen befinden kann: Sie wird gepuffert, vollständig geladen und abgespielt. Wenn Sie sich den Lade- und Wiedergabezustand als zwei Boolesche Flags vorstellen

 (loaded, playing) 

Der Compiler erlaubt die Eingabe ungültiger Werte

 (loaded: false, playing: true) 

Und wenn Sie die Aufzählung verwenden

 (.buffering/.loaded/.playing) 

dann ist es unmöglich, einen ungültigen Zustand anzuzeigen. In der clientorientierten Oberfläche sollte standardmäßig ungültige Kombinationen von Einstellungen verhindert werden. Wenn wir jedoch Code in die Anwendung schreiben, vergessen wir oft, uns den gleichen Schutz zu bieten.




Ungültige Kombinationen werden im Voraus deaktiviert. Benutzer müssen nicht darüber nachdenken, welche Konfigurationen nicht kompatibel sind. Screenshot - Apple

Wir folgten den betrachteten Benutzerpfaden und kamen zu den gleichen Regeln wie am Anfang. Aber jetzt haben wir ein Prinzip, nach dem sie unabhängig formuliert und je nach Situation geändert werden können. Dazu fragen wir uns:

  • Wird es für den Benutzer einfach sein, nach dem gewünschten Code zu suchen? Werden die Suchergebnisse mit Funktionen überfüllt sein, die nicht mit der Abfrage zusammenhängen?
  • Kann ein Benutzer, nachdem er den erforderlichen Code gefunden hat, schnell die Richtigkeit seines Verhaltens überprüfen?
  • Bietet die Entwicklungsumgebung eine sichere Bearbeitung und Wiederverwendung von Code?

Zusammenfassend: Lesbarer Code sollte einfach zu verwenden sein. Und als Nebeneffekt kann es schön aussehen.

Hinweis


  1. Es mag den Anschein haben, dass boolesche Variablen bequemer wiederzuverwenden sind, aber diese Wiederverwendungsoption impliziert Austauschbarkeit. Nehmen wir zum Beispiel die tippbaren und zwischengespeicherten Flags , die Konzepte darstellen, die sich auf völlig unterschiedlichen Ebenen befinden: die Fähigkeit, auf ein Element zu klicken, und den Caching-Status. Wenn beide Flags jedoch boolesch sind, können Sie sie versehentlich austauschen und einen nicht trivialen Ausdruck in einer Codezeile erhalten. Dies bedeutet, dass das Zwischenspeichern mit der Möglichkeit verbunden ist, auf ein Element zu klicken. Bei der Verwendung von Aufzählungen müssen wir zur Bildung solcher Beziehungen eine explizite, überprüfbare Logik für die Umrechnung der von uns verwendeten „Maßeinheiten“ erstellen.


Über den Übersetzer

Der Artikel wurde von Alconost übersetzt.

Alconost lokalisiert Spiele , Anwendungen und Websites in 70 Sprachen. Muttersprachliche Übersetzer, Sprachtests, Cloud-Plattform mit API, kontinuierliche Lokalisierung, Projektmanager rund um die Uhr, jedes Format von Zeichenfolgenressourcen.

Wir machen auch Werbe- und Schulungsvideos - für Websites, die verkaufen, Image, Werbung, Schulung, Teaser, Expliner, Trailer für Google Play und den App Store.

Lesen Sie mehr

Source: https://habr.com/ru/post/de443678/


All Articles