Heim >Web-Frontend >js-Tutorial >Entwirrender Spaghetti -Code: Wartungsbares JavaScript schreiben
Dieser Artikel wurde von Tom Greco, Dan Prince und Yaphi Berhanu geprüft. Vielen Dank an alle Peer -Rezensenten von SitePoint, die SitePoint -Inhalte so gut wie möglich gemacht haben!
Fast jeder Entwickler hat die Erfahrung gemacht, ein Legacy -Projekt aufrechtzuerhalten oder zu übernehmen. Oder vielleicht ist es ein altes Projekt, das wieder aufgegriffen wurde. Gemeinsame erste Gedanken sind, die Codebasis wegzuwerfen und von vorne zu beginnen. Der Code kann chaotisch, undokumentiert sein und es kann Tage dauern, bis alles vollständig ist. Aber mit ordnungsgemäßer Planung, Analyse und einem guten Workflow ist es möglich, eine Spaghetti -Codebasis in eine saubere, organisierte und skalierbare.
zu verwandeln.Ich musste viele Projekte übernehmen und aufräumen. Es gab nicht viele, die ich von vorne angefangen habe. Tatsächlich mache ich das derzeit genau. Ich habe viel über JavaScript gelernt und eine Codebasis organisiert und - vor allem - bei dem vorherigen Entwickler nicht verrückt ist. In diesem Artikel möchte ich Ihnen meine Schritte zeigen und Ihnen meine Erfahrung sagen.
Finden Sie heraus, welche Tools verwendet werden. JQuery? Reagieren? Äußern? Machen Sie eine Liste von allem, was wichtig ist, um es zu wissen. Nehmen wir an, das Projekt ist in Angular 2 geschrieben und Sie haben noch nicht damit gearbeitet, gehen Sie direkt zur Dokumentation und erhalten Sie ein grundlegendes Verständnis. Suche nach Best Practices.
Verstehe das Projekt auf einer höheren Ebene
geht es darum, Konsistenz festzustellen. Nachdem Sie alle Informationen über die Projekte Toolchain haben, kennen Sie die Struktur und wie die Logik miteinander verbunden ist, ist es an der Zeit, eine Basis zu erstellen. Ich empfehle, eine .DitorConfig -Datei hinzuzufügen, um die Codierungsstil -Führer zwischen verschiedenen Redakteuren, IDE und Entwicklern zu konsistent.
Die berühmte Frage (es ist eher ein Krieg ), ob Leerzeichen oder Registerkarten verwendet werden sollten, spielt keine Rolle. Ist die Codebasis in Leerzeichen geschrieben? Fahren Sie mit Räumen fort. Mit Registerkarten? Benutze sie. Nur wenn die Codebasis eine gemischte Eindrücke hat, ist es erforderlich, zu entscheiden, welches Gebrauch verwendet werden soll. Meinungen sind in Ordnung, aber ein gutes Projekt stellt sicher, dass alle Entwickler ohne Probleme arbeiten können.
Warum ist das überhaupt wichtig? Jeder hat seine eigene Art, einen Redakteur oder eine IDE zu verwenden. Zum Beispiel bin ich ein großer Fan von Codefalten. Ohne diese Funktion bin ich buchstäblich in einer Datei verloren. Wenn die Eindrücke nicht kohärent ist, schlägt diese Funktionen fehl. Jedes Mal, wenn ich eine Datei öffne, müsste ich die Eindrücke reparieren, bevor ich überhaupt anfangen kann zu arbeiten. Dies ist eine enorme Zeitverschwendung.
<span>// While this is valid JavaScript, the block can't </span><span>// be properly folded due to its mixed indentation. </span> <span>function foo (data) { </span> <span>let property = String(data); </span> <span>if (property === 'bar') { </span> property <span>= doSomething(property); </span> <span>} </span> <span>//... more logic. </span> <span>} </span> <span>// Correct indentation makes the code block foldable, </span><span>// enabling a better experience and clean codebase. </span><span>function foo (data) { </span> <span>let property = String(data); </span> <span>if (property === 'bar') { </span> property <span>= doSomething(property); </span> <span>} </span> <span>//... more logic. </span><span>} </span>
Stellen Sie sicher, dass die im Projekt verwendete Namenskonvention respektiert wird. Camelcase wird üblicherweise im JavaScript -Code verwendet, aber ich habe viel gemischte Konventionen gesehen. Zum Beispiel haben JQuery -Projekte häufig eine gemischte Benennung von JQuery -Objektvariablen und anderen Variablen.
<span>// Inconsistent naming makes it harder </span><span>// to scan and understand the code. It can also </span><span>// lead to false expectations. </span><span>const $element = $('.element'); </span> <span>function _privateMethod () { </span> <span>const self = $(this); </span> <span>const _internalElement = $('.internal-element'); </span> <span>let $data = element.data('foo'); </span> <span>//... more logic. </span><span>} </span> <span>// This is much easier and faster to understand. </span><span>const $element = $('.element'); </span> <span>function _privateMethod () { </span> <span>const $this = $(this); </span> <span>const $internalElement = $('.internal-element'); </span> <span>let elementData = $element.data('foo'); </span> <span>//... more logic. </span><span>} </span>
Während die vorherigen Schritte kosmetischer waren und hauptsächlich beim Scannen des Codes schneller beim Scannen des Codes beitragen, stellen wir hier die gängigen Best Practices sowie die Codequalität ein und gewährleisten. Eslint, JSlint und JSHINT sind heutzutage die beliebtesten JavaScript -Linter. Persönlich habe ich viel mit JSHINT gearbeitet, aber Eslint wurde begonnen, mein Favorit zu werden, vor allem wegen seiner benutzerdefinierten Regeln und der frühen Unterstützung der ES2015.
Wenn Sie mit dem Leinen beginnen, wenn viele Fehler auftauchen, beheben Sie sie! Fahren Sie mit nichts anderem fort, bevor Ihr Verstürfter glücklich ist!
Die Aktualisierung der Abhängigkeiten sollte sorgfältig durchgeführt werden. Es ist einfach, mehr Fehler einzuführen, wenn Sie nicht auf die Änderungen achten, die Ihre Abhängigkeiten durchlaufen haben. Einige Projekte funktionieren möglicherweise mit festen Versionen (z. B. v1.12.5), während andere Wildcard -Versionen (z. B. v1.12.x) verwenden. Falls Sie ein kurzes Update benötigen, wird wie folgt eine Versionsnummer erstellt: major.minor.patch. Wenn Sie nicht mit der Funktionsweise semantischer Versioning vertraut sind, empfehle ich diesen Artikel von Tim Oxley.
Es gibt keine allgemeine Regel für die Aktualisierung von Abhängigkeiten. Jedes Projekt ist anders und sollte als solches behandelt werden. Die Aktualisierung der Patchnummer Ihrer Abhängigkeiten sollte überhaupt kein Problem sein, und Moll ist normalerweise auch in Ordnung. Nur wenn Sie die Hauptnummer Ihrer Abhängigkeiten stoßen, sollten Sie nachsehen, was genau geändert hat. Vielleicht hat sich die API vollständig verändert und Sie müssen große Teile Ihrer Anwendung neu schreiben. Wenn das die Mühe nicht wert ist, würde ich es vermeiden, auf die nächste Hauptversion zu aktualisieren.
Wenn Ihr Projekt NPM als Abhängigkeitsmanager verwendet (und es keine Wettbewerber gibt), können Sie nach veralteten Abhängigkeiten mit dem praktischen Befehl npm veraltet von Ihrer CLI überprüfen. Lassen Sie mich dies mit einem Beispiel aus einem meiner Projekte namens Frontbook veranschaulichen, in dem ich häufig alle Abhängigkeiten aktualisiere:
Wie Sie sehen, habe ich hier viele große Updates. Ich würde sie nicht auf einmal aktualisieren, sondern nach dem anderen. Zugegeben, dies wird viel Zeit in Anspruch nehmen, aber es ist der einzige Weg, um nichts zu schützen (wenn das Projekt keine Tests hat).
Die Hauptnachricht, die Sie mitnehmen möchten, ist, dass das Aufräumen nicht unbedingt das Entfernen und Umschreiben großer Codeabschnitte bedeutet. Dies ist natürlich manchmal die einzige Lösung, aber es sollte nicht Ihr erster und einziger Schritt sein. JavaScript kann eine seltsame Sprache sein, weshalb generischer Ratschläge normalerweise nicht möglich sind. Sie müssen immer Ihre spezifische Situation bewerten und eine funktionierende Lösung finden.
Einheitstests stellt sicher, dass Sie verstehen, wie der Code funktionieren soll, und Sie brechen nichts zu versehentlich. JavaScript -Unit -Tests sind seine eigenen Artikel wert, sodass ich hier nicht viel ins Detail eingehen kann. Weit verbreitete Frameworks sind Karma, Jasmine, Mokka oder AVA. Wenn Sie auch Ihre Benutzeroberfläche testen möchten, werden Nightwatch.js und Dalekjs empfohlene Browser -Automatisierungswerkzeuge erhalten.
Der Unterschied zwischen Unit -Tests und Browserautomatisierung ist, dass der erstere Ihren JavaScript -Code selbst testet. Es stellt sicher, dass alle Ihre Module und allgemeinen Logik wie beabsichtigt funktionieren. Die Browserautomatisierung hingegen testet die Oberfläche - die Benutzeroberfläche - Ihres Projekts und sorgt dafür, dass Elemente wie erwartet richtig sind.
Kümmere dich um Unit -Tests, bevor du etwas anderes neu aufstellst. Die Stabilität Ihres Projekts wird sich verbessern und Sie haben noch nicht einmal über Skalierbarkeit nachgedacht! Ein großer Nebeneffekt ist nicht die ganze Zeit besorgt, in der Sie etwas gebrochen haben und nicht bemerkt haben.
Rebecca Murphey als geschriebener Artikel zu Schreibabteilungen für vorhandene JavaScript.
JavaScript -Architektur ist ein weiteres großes Thema. Das Aufstellen und Aufräumen der Architektur läuft darauf hinaus, wie viel Erfahrung Sie damit haben. Wir haben viele verschiedene Designmuster in der Softwareentwicklung, aber nicht alle passen gut, wenn es um Skalierbarkeit geht. Leider kann ich nicht alle Fälle in diesem Artikel abdecken, kann aber zumindest einen allgemeinen Rat geben.
Erstens sollten Sie herausfinden, welche Entwurfsmuster bereits in Ihrem Projekt verwendet werden. Lesen Sie über das Muster und stellen Sie sicher, dass es konsistent ist. Einer der Schlüssel zur Skalierbarkeit ist, sich an das Muster zu halten und keine Mischmethoden zu mischen. Natürlich können Sie in Ihrem Projekt unterschiedliche Designmuster für unterschiedliche Zwecke haben (z. eins mit einem anderen Muster.
Wenn Ihr Projekt keine Architektur gibt (vielleicht ist alles nur in einer riesigen App.js), ist es Zeit, dies zu ändern. Mach nicht alles auf einmal, sondern Stück für Stück. Auch hier gibt es keine generische Möglichkeit, Dinge zu tun, und jedes Projekt -Setup ist anders. Die Ordnerstrukturen variieren je nach Größe und Komplexität zwischen Projekten. Normalerweise-auf einer sehr grundlegenden Ebene-wird die Struktur in Bibliotheken, Module, Daten und Einstiegspunkte von Drittanbietern (z. B. index.js, main.js) aufgeteilt, in denen alle Ihre Module und Logik initialisiert werden.
Dies führt mich zur Modularisierung.
Modularisierung ist bei weitem nicht die Antwort auf die große JavaScript -Skalierbarkeitsfrage. Es fügt eine weitere API -Ebene hinzu, mit der Entwickler vertraut werden müssen. Dies kann jedoch den Ärger wert sein. Das Prinzip besteht darin, Ihre gesamte Funktionen in winzige Module aufzuteilen. Auf diese Weise ist es einfacher, Probleme in Ihrem Code zu lösen und in einem Team auf derselben Codebasis zu arbeiten. Jedes Modul sollte genau einen Zweck und eine Aufgabe haben. Ein Modul kennt die äußere Logik Ihrer Anwendung nicht und kann an verschiedenen Orten und Situationen wiederverwendet werden.
Wie teilen Sie eine große Funktion mit viel eng verbundener Logik auf? Lass uns das gemeinsam machen.
<span>// While this is valid JavaScript, the block can't </span><span>// be properly folded due to its mixed indentation. </span> <span>function foo (data) { </span> <span>let property = String(data); </span> <span>if (property === 'bar') { </span> property <span>= doSomething(property); </span> <span>} </span> <span>//... more logic. </span> <span>} </span> <span>// Correct indentation makes the code block foldable, </span><span>// enabling a better experience and clean codebase. </span><span>function foo (data) { </span> <span>let property = String(data); </span> <span>if (property === 'bar') { </span> property <span>= doSomething(property); </span> <span>} </span> <span>//... more logic. </span><span>} </span>
Dies ist nicht sehr modular. Alles ist eng miteinander verbunden und von den anderen Teilen abhängig. Stellen Sie sich dies mit größeren, komplexeren Funktionen vor und Sie müssten dies debuggen, weil etwas bricht. Vielleicht antwortet die API nicht, etwas im JSON oder was auch immer. Ein Albtraum, nicht wahr?
Lassen Sie uns die verschiedenen Verantwortlichkeiten trennen:
<span>// Inconsistent naming makes it harder </span><span>// to scan and understand the code. It can also </span><span>// lead to false expectations. </span><span>const $element = $('.element'); </span> <span>function _privateMethod () { </span> <span>const self = $(this); </span> <span>const _internalElement = $('.internal-element'); </span> <span>let $data = element.data('foo'); </span> <span>//... more logic. </span><span>} </span> <span>// This is much easier and faster to understand. </span><span>const $element = $('.element'); </span> <span>function _privateMethod () { </span> <span>const $this = $(this); </span> <span>const $internalElement = $('.internal-element'); </span> <span>let elementData = $element.data('foo'); </span> <span>//... more logic. </span><span>} </span>
Okay, wir haben jetzt drei neue Module. Lassen Sie uns den neu gestalteten Abrufanruf sehen.
<span>// This example uses the Fetch API to request an API. Let's assume </span><span>// that it returns a JSON file with some basic content. We then create a </span><span>// new element, count all characters from some fictional content </span><span>// and insert it somewhere in your UI. </span><span>fetch('https://api.somewebsite.io/post/61454e0126ebb8a2e85d', { method: 'GET' }) </span> <span>.then(response => { </span> <span>if (response.status === 200) { </span> <span>return response.json(); </span> <span>} </span> <span>}) </span> <span>.then(json => { </span> <span>if (json) { </span> <span>Object.keys(json).forEach(key => { </span> <span>const item = json[key]; </span> <span>const count = item.content.trim().replace(<span>/<span>\s+</span>/gi</span>, '').length; </span> <span>const el = <span>` </span></span><span><span> <div token interpolation"><span>${item.className}</span>"> </span></span><span><span> <p>Total characters: <span>${count}</span></p> </span></span><span><span> </div> </span></span><span><span> `</span>; </span> <span>const wrapper = document.querySelector('.info-element'); </span> wrapper<span>.innerHTML = el; </span> <span>}); </span> <span>} </span> <span>}) </span> <span>.catch(error => console.error(error)); </span>
Wir könnten auch die Logik in den .then () -Methoden nehmen und das trennen, aber ich glaube, ich habe gezeigt, was Modularisierung bedeutet.
Wie ich bereits erwähnt habe, fügt das Drehen Ihrer Codebasis in winzigen Modulen eine weitere API -Ebene hinzu. Wenn Sie das nicht wollen, aber es anderen Entwicklern leichter halten möchten, mit Ihrem Code zu arbeiten, ist es absolut in Ordnung, Funktionen größer zu halten. Sie können Ihren Code immer noch in einfachere Portionen zerlegen und sich mehr auf Testsable -Code konzentrieren.
Dokumentation ist ein stark diskutiertes Thema. Ein Teil der Programmiergemeinschaft setzt sich für die Dokumentation alles ein, während eine andere Gruppe der Meinung ist, dass selbstdokumentierter Code der richtige Weg ist. Wie bei den meisten Dingen im Leben denke ich, dass eine gute Balance von beiden Code -lesbar und skalierbar macht. Verwenden Sie JSDOC für Ihre Dokumentation.
JSDOC ist ein API -Dokumentationsgenerator für JavaScript. Es ist normalerweise als Plugin für alle bekannten Redakteure und IDE erhältlich. Lassen Sie uns ein Beispiel durchgehen:
<span>// While this is valid JavaScript, the block can't </span><span>// be properly folded due to its mixed indentation. </span> <span>function foo (data) { </span> <span>let property = String(data); </span> <span>if (property === 'bar') { </span> property <span>= doSomething(property); </span> <span>} </span> <span>//... more logic. </span> <span>} </span> <span>// Correct indentation makes the code block foldable, </span><span>// enabling a better experience and clean codebase. </span><span>function foo (data) { </span> <span>let property = String(data); </span> <span>if (property === 'bar') { </span> property <span>= doSomething(property); </span> <span>} </span> <span>//... more logic. </span><span>} </span>
Diese Funktion übernimmt zwei Parameter und iteriert über ein Objekt, das dann ein Array zurückgibt. Dies ist möglicherweise keine übermäßig komplizierte Methode, aber für jemanden, der den Code nicht geschrieben hat, dauert es möglicherweise eine Weile, um herauszufinden, was los ist. Darüber hinaus ist nicht offensichtlich, was die Methode tut. Lassen Sie uns dokumentieren:
<span>// Inconsistent naming makes it harder </span><span>// to scan and understand the code. It can also </span><span>// lead to false expectations. </span><span>const $element = $('.element'); </span> <span>function _privateMethod () { </span> <span>const self = $(this); </span> <span>const _internalElement = $('.internal-element'); </span> <span>let $data = element.data('foo'); </span> <span>//... more logic. </span><span>} </span> <span>// This is much easier and faster to understand. </span><span>const $element = $('.element'); </span> <span>function _privateMethod () { </span> <span>const $this = $(this); </span> <span>const $internalElement = $('.internal-element'); </span> <span>let elementData = $element.data('foo'); </span> <span>//... more logic. </span><span>} </span>
Ich habe nicht viel von dem Code selbst berührt. Durch die Umbenennung der Funktion und das Hinzufügen eines kurzen, dennoch detaillierten Kommentarblocks haben wir die Lesbarkeit verbessert.
Refactoring ist eine große Mission für sich. Um Ihre Änderungen immer rollen zu können (falls Sie etwas brechen und erst später bemerken), empfehle ich, jedes von Ihnen vorgenommene Update zu begehen. Eine Methode neu geschrieben? Git Commit (oder SVN Commit, wenn Sie mit SVN zusammenarbeiten). Einen Namespace, Ordner oder ein paar Bilder umbenannt? Git Commit. Sie haben die Idee. Es mag für manche Menschen mühsam sein, es zu tun, aber es hilft Ihnen wirklich, richtig aufzuräumen und organisiert zu werden.
Erstellen Sie einen neuen Zweig für die gesamte Refactoring -Anstrengung. Arbeite niemals am Meister! Möglicherweise müssen Sie schnelle Änderungen vornehmen oder Fehlerbehebungen in die Produktionsumgebung hochladen und möchten Ihren (möglicherweise nicht getesteten) Code erst im Testen und Fertigstellen bereitstellen. Daher wird empfohlen, immer an einem anderen Zweig zu arbeiten.
Wenn Sie ein kurzes Update benötigen, wie all dies funktioniert, gibt es eine interessante Anleitung von GitHub in ihrem Versionskontroll -Workflow.
Neben allen technischen Schritten, die für eine Aufräumarbeiten erforderlich sind, gibt es einen wichtigen Schritt, den ich selten überall gesehen habe: Nicht sauer auf den vorherigen Entwickler. Natürlich gilt dies nicht für alle, aber ich weiß, dass einige Leute dies erleben. Ich habe Jahre gebraucht, um das wirklich zu verstehen und darüber hinwegzukommen. Früher war ich ziemlich sauer auf den vorherigen Entwicklercode, ihre Lösungen und nur, warum alles so ein Chaos war.
Am Ende hat mich all diese Negativität nie irgendwohin gebracht. Es führt nur dazu, dass Sie mehr als nötig neu gestaltet, Ihre Zeit verschwendet und vielleicht Dinge brechen. Das macht dich immer mehr verärgerter. Sie könnten zusätzliche Stunden verbringen und niemand wird es Ihnen jemals danken, dass Sie ein bereits funktionierendes Modul neu geschrieben haben. Es lohnt sich nicht. Tun Sie, was erforderlich ist, und analysieren Sie die Situation. Sie können jedes Mal, wenn Sie zu einem Modul zurückkehren
Es gibt immer Gründe, warum Code so geschrieben wird, wie er ist. Vielleicht hatte der vorherige Entwickler nicht genug Zeit, um es richtig zu machen, wusste es nicht besser oder was auch immer. Wir waren alle dort.wickeln Sie es
Ich hoffe wirklich, dass dieser Artikel Ihnen geholfen hat. Lassen Sie mich wissen, wenn Sie mit einem der Schritte zu kämpfen haben oder vielleicht gute Ratschläge haben, die ich nicht erwähnt habe!
Das obige ist der detaillierte Inhalt vonEntwirrender Spaghetti -Code: Wartungsbares JavaScript schreiben. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!