Richtlinien zum Schreiben von sauberem JavaScript-Code

Wenn Sie sich für den Code selbst und dessen Schreibweise interessieren und nicht nur damit beschäftigt sind, Arbeitsprogramme zu erstellen, bedeutet dies, dass Ihr Code sauber sein soll. Ein professioneller Entwickler schreibt Code nicht nur für Computer, sondern auch für sich selbst, der diesen Code in Zukunft kennengelernt hat, und für andere Programmierer. Der Code, den Sie schreiben, verschwindet nicht für immer im Darm des Computers. Es lebt, ändert sich und wenn es schlecht geschrieben ist, kann es jemanden sehr verärgern, der es bearbeiten muss, nachdem Sie es geschrieben haben. Es ist möglich, dass Sie dieser „Jemand“ sind.



Basierend auf diesen Ideen kann sauberer Code als Code definiert werden, der so geschrieben ist, dass er sich selbst erklärt. Dieser Code kann von Personen leicht verstanden werden, er kann leicht geändert oder erweitert werden.

Code- und WTF-Fragen


Die Essenz von WTF-Fragen wie „WTF ist das?“ Kommt auf extreme Überraschung und Ressentiments an. Auf Russisch können diese Gefühle durch die Frage „Was zur Hölle?“ Ausgedrückt werden. "Verdammt" kann je nach Situation durchaus etwas völlig Unbedruckbarem weichen. Wie oft haben Sie jemals einen Code hinzugefügt und ähnliche Fragen gestellt?

Wenn sich Programmierer WTF-Fragen zum Code eines anderen stellen, fragen sich die Programmierer, was es ist (WTF ist das?), Was der Autor des Codes versucht hat (WTF haben Sie hier gemacht?), Warum ist dieses oder jenes Konstrukt im Code vorhanden (WTF ist) das für?)

Hier ist ein Bild, nach dem der einzige verlässliche Indikator für die Codequalität die Anzahl der WTF-Fragen pro Minute ist.


Links ist guter Code. Rechts ist schlecht

Im Ernst, um Ihnen dabei zu helfen, über sauberen Code nachzudenken, zitieren wir Robert Martin, bekannt als Onkel Bob: „Auch schlechter Programmcode kann funktionieren. Wenn der Code jedoch nicht „sauber“ ist, beeinträchtigt dies immer die Entwicklung des Projekts. “

Schauen wir uns nun einige praktische Richtlinien zum Schreiben von sauberem Code an. Wir werden hier JavaScript verwenden, aber diese Empfehlungen können auf die Entwicklung in anderen Sprachen angewendet werden.

1. Strenge Gleichstellungsprüfungen


Versuchen Sie, === anstelle von == .

 //     == -       .     ,   ,   ,   -    . 0 == false // true 0 === false // false 2 == "2" // true 2 === "2" // false //  const value = "500"; if (value === 500) { console.log(value); //     } if (value === "500") { console.log(value); //    } 

2. Variablen


Benennen Sie die Variablen so, dass ihre Namen ihre Essenz und ihre Rolle im Programm enthüllen. Mit diesem Ansatz ist es bequem, im Code nach ihnen zu suchen, und jeder, der diesen Code sieht, kann die Bedeutung der von ihm ausgeführten Aktionen leichter verstehen.
Schlecht:

 let daysSLV = 10; let y = new Date().getFullYear(); let ok; if (user.age > 30) { ok = true; } 

Gut:

 const MAX_AGE = 30; let daysSinceLastVisit = 10; let currentYear = new Date().getFullYear(); ... const isUserOlderThanAllowed = user.age > MAX_AGE; 

Es ist nicht erforderlich, den nicht benötigten Variablennamen zusätzliche Wörter hinzuzufügen.

Schlecht:

 let nameValue; let theProduct; 

Gut:

 let name; let product; 

Sie sollten niemanden, der den Code liest, zwingen, sich an die Umgebung zu erinnern, in der die Variable deklariert ist.

Schlecht:

 const users = ["John", "Marco", "Peter"]; users.forEach(u => { doSomething(); doSomethingElse(); // ... // ... // ... // ... //    ,    WTF- "   `u`?" register(u); }); 

Gut:

 const users = ["John", "Marco", "Peter"]; users.forEach(user => { doSomething(); doSomethingElse(); // ... // ... // ... // ... register(user); }); 

Sie müssen Variablennamen nicht mit redundanten Informationen über den Kontext versehen, in dem sie verwendet werden.

Schlecht:

 const user = { userName: "John", userSurname: "Doe", userAge: "28" }; ... user.userName; 

Gut:

 const user = { name: "John", surname: "Doe", age: "28" }; ... user.name; 

3. Funktionen


Verwenden Sie lange beschreibende Namen für Funktionen. Da eine Funktion eine Beschreibung einer bestimmten Aktion ist, sollte ihr Name ein Verb oder eine Phrase sein, die das Wesen der Funktion vollständig beschreibt. Die Namen der Argumente müssen so ausgewählt werden, dass sie die von ihnen dargestellten Daten angemessen beschreiben. Funktionsnamen sollten dem Codeleser mitteilen, was genau diese Funktionen tun.

Schlecht:

 function notif(user) { //  } 

Gut:

 function notifyUser(emailAddress) { //  } 

Vermeiden Sie lange Listen mit Argumenten. Im Idealfall sollten Funktionen zwei oder weniger Argumente haben. Je weniger Argumente eine Funktion hat, desto einfacher ist es, sie zu testen.

Schlecht:

 function getUsers(fields, fromDate, toDate) { //  } 

Gut:

 function getUsers({ fields, fromDate, toDate }) { //  } getUsers({ fields: ['name', 'surname', 'email'], fromDate: '2019-01-01', toDate: '2019-01-18' }) 

Verwenden Sie die Standardargumente und geben Sie ihnen den Vorzug vor bedingten Konstrukten.

Schlecht:

 function createShape(type) { const shapeType = type || "cube"; // ... } 

Gut:

 function createShape(type = "cube") { // ... } 

Eine Funktion sollte ein Problem lösen. Stellen Sie sicher, dass eine Funktion nicht viele Aktionen ausführt.

Schlecht:

 function notifyUsers(users) { users.forEach(user => {   const userRecord = database.lookup(user);   if (userRecord.isVerified()) {     notify(user);   } }); } 

Gut:

 function notifyVerifiedUsers(users) { users.filter(isUserVerified).forEach(notify); } function isUserVerified(user) { const userRecord = database.lookup(user); return userRecord.isVerified(); } 

Verwenden Sie Object.assign , um die Eigenschaften von Objekten standardmäßig Object.assign .

Schlecht:

 const shapeConfig = { type: "cube", width: 200, height: null }; function createShape(config) { config.type = config.type || "cube"; config.width = config.width || 250; config.height = config. height || 250; } createShape(shapeConfig); 

Gut:

 const shapeConfig = { type: "cube", width: 200 //   'height'   }; function createShape(config) { config = Object.assign(   {     type: "cube",     width: 250,     height: 250   },   config ); ... } createShape(shapeConfig); 

Verwenden Sie keine Flags als Parameter. Ihre Verwendung bedeutet, dass die Funktion mehr Aktionen ausführt, als sie hätte ausführen sollen.

Schlecht:

 function createFile(name, isPublic) { if (isPublic) {   fs.create(`./public/${name}`); } else {   fs.create(name); } } 

Gut:

 function createFile(name) { fs.create(name); } function createPublicFile(name) { createFile(`./public/${name}`); } 

Verschmutzen Sie nicht den globalen Geltungsbereich. Wenn Sie ein vorhandenes Objekt erweitern müssen, verwenden Sie ES-Klassen und Vererbungsmechanismen, anstatt Funktionen in der Prototypkette von Standardobjekten zu erstellen.

Schlecht:

 Array.prototype.myFunc = function myFunc() { //  }; 

Gut:

 class SuperArray extends Array { myFunc() {   //  } } 

4. Bedingte Konstruktionen


Versuchen Sie, die booleschen Variablen nicht so zu benennen, dass ihre Namen negiert werden. Gleiches gilt für Funktionen, die boolesche Werte zurückgeben. Die Verwendung solcher Entitäten in bedingten Konstrukten erschwert das Lesen von Code.

Schlecht:

 function isUserNotBlocked(user) { //  } if (!isUserNotBlocked(user)) { //  } 

Gut:

 function isUserBlocked(user) { //  } if (isUserBlocked(user)) { //  } 

Verwenden Sie die Kurzform für bedingte Konstruktionen. Vielleicht mag diese Empfehlung trivial erscheinen, aber es ist erwähnenswert. Verwenden Sie diesen Ansatz nur für logische Variablen und wenn Sie sicher sind, dass der Wert der Variablen nicht undefined oder null .

Schlecht:

 if (isValid === true) { // - ... } if (isValid === false) { // - ... } 

Gut:

 if (isValid) { // - ... } if (!isValid) { // - ... } 

Vermeiden Sie nach Möglichkeit logische Konstruktionen. Verwenden Sie stattdessen Polymorphismus und Vererbung.

Schlecht:

 class Car { // ... getMaximumSpeed() {   switch (this.type) {     case "Ford":       return this.someFactor() + this.anotherFactor();     case "Mazda":       return this.someFactor();     case "McLaren":       return this.someFactor() - this.anotherFactor();   } } } 

Gut:

 class Car { // ... } class Ford extends Car { // ... getMaximumSpeed() {   return this.someFactor() + this.anotherFactor(); } } class Mazda extends Car { // ... getMaximumSpeed() {   return this.someFactor(); } } class McLaren extends Car { // ... getMaximumSpeed() {   return this.someFactor() - this.anotherFactor(); } } 

5. ES-Klassen


Klassen wurden vor relativ kurzer Zeit in JavaScript angezeigt. Sie können als syntaktischer Zucker bezeichnet werden. Was bei der Verwendung von Klassen passiert, basiert nach wie vor auf Prototypen von Objekten. Der Code, der die Klassen verwendet, sieht jedoch anders aus. Im Allgemeinen sollten ES-Klassen nach Möglichkeit regulären Konstruktorfunktionen vorgezogen werden.

Schlecht:

 const Person = function(name) { if (!(this instanceof Person)) {   throw new Error("Instantiate Person with `new` keyword"); } this.name = name; }; Person.prototype.sayHello = function sayHello() { /**/ }; const Student = function(name, school) { if (!(this instanceof Student)) {   throw new Error("Instantiate Student with `new` keyword"); } Person.call(this, name); this.school = school; }; Student.prototype = Object.create(Person.prototype); Student.prototype.constructor = Student; Student.prototype.printSchoolName = function printSchoolName() { /**/ }; 

Gut:

 class Person { constructor(name) {   this.name = name; } sayHello() {   /* ... */ } } class Student extends Person { constructor(name, school) {   super(name);   this.school = school; } printSchoolName() {   /* ... */ } } 

Organisieren Sie Methoden so, dass sie verkettet werden können. Viele Bibliotheken verwenden dieses Muster, z. B. jQuery und Lodash. Infolgedessen ist Ihr Code kompakter als ohne Verwendung dieses Musters. Der Punkt ist, dass Sie dies am Ende jeder Funktion der Klasse zurückgeben müssen. Auf diese Weise können Sie Aufrufe solcher Funktionen zu Ketten zusammenfassen.

Schlecht:

 class Person { constructor(name) {   this.name = name; } setSurname(surname) {   this.surname = surname; } setAge(age) {   this.age = age; } save() {   console.log(this.name, this.surname, this.age); } } const person = new Person("John"); person.setSurname("Doe"); person.setAge(29); person.save(); 

Gut:

 class Person { constructor(name) {   this.name = name; } setSurname(surname) {   this.surname = surname;   //  this           return this; } setAge(age) {   this.age = age;   //  this           return this; } save() {   console.log(this.name, this.surname, this.age);   //  this           return this; } } const person = new Person("John")   .setSurname("Doe")   .setAge(29)   .save(); 

6. Was ist besser nicht zu tun


Jeder, der möchte, dass sein Code sauber ist, sollte versuchen, ihn nicht zu wiederholen. Es geht darum, Situationen zu vermeiden, in denen Sie denselben Code schreiben müssen. Darüber hinaus müssen Sie keine nicht verwendeten Funktionen und Programmfragmente belassen, die niemals in der Codebasis ausgeführt werden.

Doppelter Code kann aus verschiedenen Gründen auftreten. Beispielsweise kann ein Projekt zwei leicht unterschiedliche Funktionen haben. Die Art dieser Unterschiede oder Zeitmangel zwingt den Programmierer beispielsweise dazu, zwei unabhängige Funktionen zu erstellen, die nahezu identischen Code enthalten. In einer solchen Situation bedeutet das Entfernen von doppeltem Code, die Unterschiede zu abstrahieren und auf einer höheren Ebene mit ihnen zu arbeiten.

Lassen Sie uns nun über nicht verwendeten Code sprechen. Dies ist Code, der in der Codebasis vorhanden ist, aber absolut nichts tut. Dies geschieht zum Beispiel, wenn in einem bestimmten Entwicklungsstadium entschieden wird, dass ein bestimmtes Fragment des Programms keinen Sinn mehr hat. Um solche Codefragmente zu entfernen, müssen Sie die Codebasis sorgfältig überprüfen und entfernen. Es ist am einfachsten, solchen Code zu entfernen, wenn entschieden wird, dass er nicht mehr benötigt wird. Später können Sie vergessen, wofür es verwendet wurde. Dies wird den Kampf mit ihm sehr erschweren.

Wenn Sie den Kampf gegen unnötigen Code verschieben, ähnelt das Programm dem in der folgenden Abbildung gezeigten.


Manchmal sieht mein Code wie dieser Balkon aus. Ich weiß nicht, welche Aufgabe er löst, aber ich habe Angst, ihn loszuwerden.

Zusammenfassung


Hier haben wir nur einen kleinen Teil der Maßnahmen erörtert, die zur Verbesserung des Codes ergriffen werden können. Der Autor dieses Materials glaubt, dass die hier diskutierten Prinzipien oft vergessen werden. Programmierer versuchen, ihnen zu folgen, aber aus verschiedenen Gründen gelingt dies nicht immer. Vielleicht erinnert sich jeder zu Beginn des Projekts an die Bedeutung von sauberem Code, weshalb das Programm ordentlich ist. Wenn sich die Fristen nähern, wird die Reinheit des Codes oft vergessen, wobei nur auf das geachtet wird, was als TODO oder REFACTOR gekennzeichnet ist. In solchen Fällen besteht der Projektkunde darauf, dass das Projekt pünktlich abgeschlossen wird und nicht, dass sein Code sauber ist.

Sehr oft veröffentlichen wir Materialien zum Problem des Schreibens von qualitativ hochwertigem JavaScript-Code. Wenn Sie sich für dieses Thema interessieren, finden Sie hier einige Links.


Wir hoffen, dass das, was Sie durch das Lesen dieses Artikels gelernt haben und was Sie in anderen Veröffentlichungen finden, Ihnen bei Ihrer Suche nach sauberem JavaScript-Code helfen wird.

Liebe Leser! Haben Sie jemals WTF-Fragen gestellt, während Sie den Code eines anderen gelesen haben?



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


All Articles