Ich möchte eine Antwort auf diese Frage hinzufügen, da ich in letzter Zeit durch ein gutes, schlechtes, aber meist hässliches Java gestapft bin und eine ganze Reihe von groben Verallgemeinerungen über Java und Java-Entwickler im Vergleich zu JS und JS-Entwickler, die tatsächlich auf etwas basieren könnten, das der nützlichen Wahrheit vage ähnelt.
Es gibt IDEs, aber es kann hilfreich sein zu verstehen, warum es nicht viele gegeben hat
Ich habe Webstorm jetzt ausprobiert, da ich mich von der Node-Entwicklung angezogen fühle und es nicht schlecht genug ist, dass ich es tatsächlich gekauft habe, aber ich neige immer noch dazu, js-Dateien öfter in Scite zu öffnen als in WS. Der Grund dafür ist, dass Sie in JS viel mehr mit viel weniger erreichen können, aber auch, weil die Arbeit an der Benutzeroberfläche ein unmittelbares Feedback gibt, die Browser-Entwicklungstools (insbesondere Chrome und Firebug) eigentlich ganz hervorragend sind und (Kontexte ohne Browser berücksichtigen) ) Das erneute Ausführen von geändertem Code ist schnell und einfach, ohne dass ein Kompilierungsschritt erforderlich ist.
Eine andere Sache, von der ich ziemlich überzeugt bin, ist, dass IDEs im Grunde genommen ihre eigene Nachfrage erzeugen, indem sie schlampigen Code aktivieren, den Sie sich in JavaScript wirklich nicht leisten können. Möchten Sie erfahren, wie wir mit JS umgehen? Es kann hilfreich sein, zunächst zu versuchen, etwas Nicht-Triviales in Java ohne eine IDE zu schreiben und die Dinge genau zu beachten, mit denen Sie beginnen und über die Sie nachdenken müssen, um den Code tatsächlich zu warten / zu ändern, ohne dass sich eine IDE bewegt nach vorne. IMO, die gleichen Dinge sind immer noch entscheidend für das Schreiben von wartbarem Code, egal ob Sie eine IDE haben oder nicht. Wenn ich einen 4-jährigen Programmierlehrplan schreiben müsste, würden Sie in den ersten zwei Jahren keine IDE anfassen, um nicht die Werkzeuge und Abhängigkeiten zu verdrehen.
Struktur
Erfahrene JS-Entwickler, die sich mit komplexen Anwendungen befassen, können und strukturieren ihren Code. In der Tat ist es eine Sache, in der wir in der Regel mit einer frühen Geschichte besser umgehen müssen, in der IDEs fehlten, um den Code für uns zu lesen, aber auch, weil ausdrucksstarke Sprachen völlig unerreichbare Katastrophen-Codebasen sehr schnell ausdrücken können, wenn Sie nicht nachdenklich codieren.
Tatsächlich hatte ich in letzter Zeit eine ziemlich steile Lernkurve beim Verstehen unserer Java-Codebasis, bis mir schließlich klar wurde, dass nichts davon das richtige OOP war. Klassen waren nichts weiter als Bündel lose verwandter Methoden, die global verfügbare Daten, die in Beans oder DTOs oder statischen Gettern / Settern herumstehen, veränderten. Das ist im Grunde das gleiche alte Biest, das OOP ersetzen sollte. Also hörte ich auf, nach dem Code zu suchen und darüber nachzudenken. Ich habe gerade die Tastenkombinationen gelernt und die Unordnung durchgesehen, und alles lief viel reibungsloser ab. Also, wenn Sie es nicht schon gewohnt sind, denken Sie viel genauer über OOD nach.
Eine gut strukturierte JS-App auf höchster Ebene besteht in der Regel aus komplexen Funktionen (z. B. jQuery) und Objekten, die miteinander interagieren. Ich würde behaupten, dass das Merkmal einer gut strukturierten, einfach zu wartenden App in jeder Sprache ist, dass es perfekt lesbar ist, ob Sie sie mit einer IDE oder Notepad ++ betrachten. Das ist einer der Hauptgründe, warum ich die Abhängigkeitsinjektion und die Test-First-TDD äußerst kritisch sehe.
Und zum Schluss lassen Sie den Unterricht los. Erlernen Sie die prototypische Vererbung. Es ist eigentlich recht elegant und einfach zu implementieren, wenn Sie tatsächlich eine Vererbung benötigen. Ich finde jedoch, dass Compositing-Ansätze in JS tendenziell viel besser funktionieren, und ich persönlich fange an, krank zu werden und EXTJS-Nachtangst zu haben, wenn ich sehe, dass in einer Sprache mehr als ein oder zwei Ebenen der Vererbung stattfinden.
Grundprinzipien zuerst
Ich spreche über das Kernmaterial, aus dem sich alle anderen bewährten Methoden ableiten sollten: DRY, YAGNI, das Prinzip des geringsten Erstaunens, die saubere Trennung von Problemdomänen, das Schreiben auf eine Schnittstelle und das Schreiben von lesbarem Code sind mein persönlicher Kern. Alles, was etwas komplexer ist und das Aufgeben dieser Praktiken befürwortet, sollte als Kool Aid in jeder Sprache betrachtet werden, besonders aber in einer Sprache wie JavaScript, in der es sehr einfach ist, dem nächsten Mann ein Vermächtnis von sehr verwirrendem Code zu hinterlassen. Zum Beispiel ist lose Kopplung großartig, bis Sie es so weit bringen, dass Sie nicht einmal erkennen können, wo die Interaktion zwischen Objekten stattfindet.
Keine Angst vor dynamischem Tippen
Es gibt nicht viele Kerntypen in JavaScript. Dynamische Besetzungsregeln sind in der Regel praktisch und unkompliziert, aber es lohnt sich, sie zu lernen, damit Sie den Datenfluss ohne unnötige Besetzungen und sinnlose Validierungsroutinen besser verwalten können. Vertrau mir. Strikte Typen eignen sich hervorragend für die Leistung und das Erkennen von Problemen beim Kompilieren, schützen Sie jedoch nicht vor allem.
Lernen Sie den Mist aus JS-Funktionen und Closures
Die erstklassigen Funktionen von JS sind wohl der Hauptgrund, warum JS mit dem "Only Language Worth Touching the Client-Side Web With Award" ausgezeichnet wurde. Und ja, es gab tatsächlich Wettbewerb. Sie sind auch ein zentrales Merkmal von JS. Mit ihnen konstruieren wir Objekte. Alles ist auf Funktionen ausgelegt. Und sie haben praktische Funktionen. Wir können params über das Schlüsselwort arguments untersuchen. Wir können sie vorübergehend anhängen und im Kontext von Methoden anderer Objekte abfeuern. Und sie machen ereignisgesteuerte Herangehensweisen an Dinge, die obszön einfach zu implementieren sind, einfach. Kurz gesagt, sie machten JS zu einer absoluten Herausforderung, wenn es darum ging, die Komplexität zu reduzieren und die verschiedenen Implementierungen von JS selbst (vor allem aber die DOM-API) direkt an der Quelle anzupassen.
Bewerten Sie Muster / Praktiken vor der Übernahme neu
Erstklassige Funktionen und dynamische Typen machen viele der komplexeren Entwurfsmuster in JS völlig sinnlos und umständlich. Einige der einfacheren Muster sind jedoch aufgrund der hohen Flexibilität von JS unglaublich nützlich und einfach zu implementieren. Adapter und Dekoratoren sind besonders nützlich, und ich habe Singletons gefunden, die für komplexe UI-Widget-Fabriken hilfreich sind, die auch als Event-Manager für die von ihnen erstellten UI-Elemente fungieren.
Folgen Sie der Sprache und machen Sie mehr aus weniger
Ich glaube, einer der Java-Head Honchos argumentiert irgendwo, dass Ausführlichkeit ein positives Merkmal ist, das das Verständnis von Code für alle Beteiligten erleichtert. Hogwash. Wäre dies der Fall, wäre die juristische Sprache leichter zu lesen. Nur der Autor kann das, was er geschrieben hat, verständlicher machen, und Sie können dies nur tun, indem Sie sich gelegentlich in die Lage des anderen versetzen. Umfassen Sie also diese beiden Regeln. 1. Seien Sie so direkt und klar wie möglich. 2. Komm schon zum verdammten Punkt. Der Gewinn ist, dass sauberer, prägnanter Code um Größenordnungen einfacher zu verstehen und zu pflegen ist als etwas, bei dem Sie fünfundzwanzig Ebenen durchqueren müssen, um vom Auslöser zur tatsächlich gewünschten Aktion zu gelangen. Die meisten Muster, die sich in strengeren Sprachen für so etwas aussprechen, sind in der Tat Umgehungen für Einschränkungen, die JavaScript nicht hat.
Alles ist formbar und das ist in Ordnung
JS ist wahrscheinlich eine der am wenigsten protektionistischen Sprachen im Volksmund. Umarme das. Es funktioniert gut. Zum Beispiel können Sie Objekte mit unzugänglichen persistenten "privaten" Variablen schreiben, indem Sie einfach reguläre Variablen in einer Konstruktorfunktion deklarieren, und das mache ich häufig. Es ist jedoch nicht so, dass mein Code oder die Benutzer davon "vor sich selbst" geschützt werden (sie könnten ihn ohnehin zur Laufzeit durch ihre eigene Version ersetzen). Es geht vielmehr darum, die Absicht zu signalisieren, denn die Annahme ist, dass der andere kompetent genug ist, um Abhängigkeiten nicht zu zerstören, und dass Sie vielleicht aus einem guten Grund nicht direkt darauf eingehen sollen.
Es gibt keine Größenbeschränkungen, nur Problemdomänen
Das größte Problem, das ich mit all den Java-Codebasen habe, ist eine Überfülle an Klassendateien. Zuallererst ist SOLID nur eine verwirrende Wiederholung dessen, was Sie bereits über OOP wissen sollten. Eine Klasse sollte sich mit einer Reihe von Problemen befassen. Kein Problem mit einer Methode. Das bedeutet nur, dass Sie schlechten alten Funk-Spaghetti-C-Code nur mit der sinnlosen Klassensyntax zum Booten verketten müssen. Es gibt keine Größen- oder Methodenbeschränkung. Wenn es sinnvoll ist, einer bereits langen Funktion, Klasse oder einem Konstruktor etwas hinzuzufügen, ist dies sinnvoll. Nehmen Sie jQuery. Es ist ein Toolset mit einer gesamten Bibliothekslänge in einer einzigen Funktion, und daran ist nichts auszusetzen. Ob wir jQuery noch brauchen, ist in vernünftiger Weise umstritten, aber in Bezug auf das Design.
Wenn Java alles ist, was Sie wissen, versuchen Sie es mit einer Syntax, die nicht auf C basiert
Als ich anfing, mich mit Python zu beschäftigen, weil mir das, was ich über Django hörte, gefiel, lernte ich, die Syntax vom Sprachdesign zu trennen. Infolgedessen wurde es einfacher, Java und C als eine Summe ihrer Sprachentwurfsteile zu verstehen, als eine Summe von Dingen, die sie mit derselben Syntax unterschiedlich ausführen. Ein netter Nebeneffekt ist, dass je besser Sie andere Sprachen in Bezug auf Design verstehen, desto besser werden Sie die Stärken / Schwächen derjenigen verstehen, die Sie am besten durch Kontrast kennen.
Fazit
Lassen Sie uns nun, wenn wir das alles bedenken, alle Ihre Problempunkte treffen:
- Keine unmittelbare Möglichkeit, den Einstiegspunkt einer Funktion zu finden (außer einer Nur-Text-Suche, die zu einer nachfolgenden Suche nach Methoden weiter oben in der Aufrufhierarchie führen kann, nachdem Sie zwei oder drei vergessen haben, wo Sie begonnen haben)
Chrome und Firebug haben tatsächlich eine Anrufverfolgung. Aber sehen Sie sich auch meine Punkte zur Struktur und zur Übersichtlichkeit an. Je mehr Sie sich Ihre App als größere, gut gekapselte Konstrukte vorstellen können, die miteinander interagieren, desto einfacher ist es, herauszufinden, wessen Fehler es sind, wenn etwas schief geht. Ich würde sagen, dass dies auch für Java gilt. Wir haben klassenähnliche Funktionskonstruktoren, die sich perfekt für traditionelle OOP-Belange eignen.
function ObjectConstructor(){
//No need for an init method.
//Just pass in params and do stuff inside for instantiation behavior
var privateAndPersistent = true;
//I like to take advantage of function hoisting for a nice concise interface listing
this.publicAndPointlessEncapsulationMurderingGetterSetter
= publicAndPointlessEncapsulationMurderingGetterSetter;
//Seriously though Java/C# folks, stop with the pointless getter/setters already
function publicAndPointlessEncapsulationMurderingGetterSetter(arg){
if(arg === undefined){
return privateAndPersistent;
}
privateAndPersistent = arg;
}
}
ObjectConstructor.staticLikeNonInstanceProperty = true;
var instance = new ObjectConstructor();//Convention is to capitalize constructors
In meinem Code verwende ich die Objektliterale fast nie {}
als strukturelle App-Komponenten, da sie keine internen (privaten) Variablen haben und sie lieber für die Verwendung als Datenstrukturen reservieren. Das hilft, eine Erwartung zu setzen, die die Klarheit der Absichten bewahrt. (Wenn Sie Kurven sehen, handelt es sich um Daten, nicht um eine Komponente der App-Architektur).
- Parameter werden an Funktionen übergeben, ohne dass bekannt ist, welche Eigenschaften und Funktionen für diesen Parameter verfügbar sind (außer, dass das Programm ausgeführt wird, zu dem Punkt navigiert wird, an dem die Funktion aufgerufen wird, und mithilfe von console.logs alle Eigenschaften ausgegeben werden verfügbar)
Siehe auch hier moderne Browser-Tools. Aber auch, warum ist es so bescheuert, das Programm erneut auszuführen? Reload ist etwas, das ein clientseitiger Webentwickler normalerweise alle paar Minuten ausführt, weil es Sie absolut nichts kostet, es zu tun. Dies ist wieder ein weiterer Punkt, bei dem die App-Struktur hilfreich sein kann, aber es ist ein Nachteil von JS, dass Sie Ihre eigene Validierung durchführen müssen, wenn die Durchsetzung von Verträgen von entscheidender Bedeutung ist (was ich nur an Endpunkten tue, die anderen Dingen ausgesetzt sind, die meine Codebasis nicht tut) nicht kontrollieren). IMO, der Kompromiss ist die Vorteile wert.
- Die übliche Verwendung anonymer Funktionen als Rückrufe führt häufig zu einer Vielzahl verwirrender Codepfade, in denen Sie nicht schnell navigieren können.
Ja, das ist schlecht für alles Nicht-Triviale. Tu das nicht. Nennen Sie Ihre Funktionen Kinder. Es ist auch einfacher, Dinge zu verfolgen. Sie können eine einfache Trivialfunktion definieren, auswerten (für die Zuweisung erforderlich) und zuweisen, und zwar in Übereinstimmung mit:
doSomethingWithCallback( (function callBack(){}) );
Jetzt hat Chrome einen Namen für Sie, wenn Sie Anrufe verfolgen. Für nicht-triviale Funktionen würde ich es außerhalb des Aufrufs definieren. Beachten Sie auch, dass anonyme Funktionen, die einer Variablen zugewiesen sind, immer noch anonym sind.
- Sicher, JSLint erkennt einige Fehler vor der Laufzeit, aber selbst das ist nicht so praktisch, als wenn Sie rote Wellenlinien unter Ihrem Code direkt im Browser haben.
Ich fasse das Zeug nie an. Crockford hat der Community einige gute Dinge gegeben, aber JSLint überschreitet die Grenze zu stilistischen Vorlieben und schlägt vor, dass bestimmte Elemente von JavaScript schlechte Teile sind, ohne besonders guten Grund, IMO. Ignorieren Sie auf jeden Fall das eine an RegEx- und Negationsklassen, gefolgt von * oder +. Platzhalter führen zu einer schlechteren Leistung, und Sie können die Wiederholung leicht mit {} einschränken. Ignorieren Sie außerdem alles, was er über Funktionskonstruktoren sagt. Sie können sie problemlos in eine Factory-Funktion einbinden, wenn Sie das neue Schlüsselwort stört. CSSLint (nicht Crockfords) ist in Bezug auf schlechte Ratschläge noch schlimmer. Nehmen Sie immer Leute mit, die viel mit einem Körnchen Salz sprechen. Manchmal schwöre ich, sie versuchen nur, Autorität zu erlangen oder neues Material zu generieren.
Und wieder müssen Sie das, was Sie gelernt haben, mit diesem Laufzeitproblem, das Sie haben, verlernen. (Dies ist eine häufige Erscheinung, die ich bei vielen Java / C # -Entwicklern gesehen habe.) Wenn Sie 2 Jahre später immer noch Probleme mit Laufzeitfehlern haben, sollten Sie sich hinsetzen und Spam in einem Browser nachladen, bis er einsinkt ist keine Kompilierungs- / Laufzeit-Unterteilung (auch keine sichtbare - JS wird jetzt auf einer JIT ausgeführt). Es ist nicht nur in Ordnung, Fehler zur Laufzeit zu entdecken, es ist auch von großem Vorteil, wenn Sie Spam so billig und einfach nachladen und Fehler an jedem Haltepunkt entdecken, an dem Sie ankommen.
Und los geht's mit den Chrome-Entwicklertools. Sie sind direkt in das Webkit integriert. Klicken Sie mit der rechten Maustaste in Chrome. Element überprüfen. Erkunden Sie die Registerkarten. Viel Debug-Power mit der Möglichkeit, den Code in der Konsole während der Laufzeit zu ändern, ist eine der leistungsstärksten, aber weniger offensichtlichen Optionen. Ideal auch zum Testen.
In einem ähnlichen Zusammenhang sind Fehler Ihre Freunde. Schreiben Sie niemals eine leere catch-Anweisung. In JS tun wir nicht ausblenden oder begraben Fehler (oder zumindest sollten wir nicht husten YUI / Husten ). Wir kümmern uns um sie. Alles andere führt zu Schmerzen beim Debuggen. Und wenn Sie eine catch-Anweisung schreiben, um potenzielle Fehler in der Produktion auszublenden, protokollieren Sie den Fehler zumindest unbemerkt und dokumentieren Sie den Zugriff auf das Protokoll.