Ed Post über JavaScript (1/3)

Teil 1: Die wilden Jahre

Ed Post ist wohl einer der allgemein anerkanntesten Experten im Bereich der Programmiersprachen sowie deren Ökosysteme. Wir haben Ed Post nach seiner Keynote im Commnucation Convention Center »Mitte« getroffen, um mit ihm über das Thema “Ist JS (k)eine General Purpose Sprache?” zu diskutieren. Im folgenden Teil 1 dieses Interviews befassen wir uns mit den wilden Jahren von JavaScript, in Teil 2 sprechen wir über besondere JavaScript-Spezialitäten und in Teil 3 wagt Ed Post ein Fazit und eine Prognose zu JavaScript.

… Schon früh hat Ed Post am MIT mit seinen Thesen und Arbeiten zur Software-Programmierung auf sich aufmerksam gemacht und dabei eine Vorreiterrolle übernommen. Ihm ist es zu verdanken, dass ein allgemeines Umdenken im Bereich der Software-Entwicklung, insbesondere der Programmierung, mitte der 80er Jahre des letzten Jahrhunderts stattgefunden hat. Er hat damit den Weg in die moderne IT, wie wir sie heute kennen, erst ermöglicht …” [POS82]

Ist JS (k)eine General Purpose Sprache?

Frage: Das Web befindet sich in einem Dauer-Hype und hat längst in jeden Bereich unseres Lebens eingegriffen. So haben viele Programmiererinnen und Programmierer erst aufgrund der Perspektiven und des damit verbundenen gesellschaftlichen Status damit angefangen, zu programmieren, und zwar mit JavaScript

Ed Post: …der Lingua franca des Webs. Das Internet ist ja zum Glück mehr als nur das Web.

Frage: Aus JS-Kreisen höre ich, dass JavaScript und das JavaScript-Ökosystem allen anderen Programmiersprachen sowie deren Ökosystemen (C#, Go, Java oder Rust, Anm.d.Red.) weit überlegen sein soll. Vereint es doch alle guten Konzepte wie funktional oder objektorientiert in einer einzigen Programmiersprache. Dennoch hört man hier und da von widerspenstigen Entwickelnden, die sich geradezu renitent weigern, nach JavaScript zu konvertieren.

JavaScript ist die Lingua franca des Webs […]

… aber das Internet, als Obermenge des Webs, wird mit mehr als nur einer Programmiersprache entwickelt. Da spielt JavaScript eine untergerodnete Rolle.

Ed Post: Sie stellen sich die Frage zum “warum”? Woher kommt diese Renitenz?

Frage: Genau, diese Frage möchte ich mit Ihnen gerne klären. Deshalb auch der provokative Titel dieser Runde: “Ist JS (k)eine General Purpose Sprache?

Ed Post: … wobei Sie die Antwort auf die Frage natürlich schon kennen? Aber eines nach dem anderen…

Die wilden Jahre

Frage: Sollen wir als Einstieg mit einem kurzen Überblick zur Geschichte von JavaScript beginnen? Ich denke, daraus werden sich weitere Fragen ergeben, deren Beantwortung JavaScript-Verweigerern die Augen öffnen sollten, sind diese noch rationalen Argumenten gegenüber offen.

Ed Post: Einverstanden! JavaScript, damals noch als Mocha und dann als LiveScript bekannt, wurde 1995 von Brendan Eich in 10 Tagen (sagt man) entwickelt [JAV18].

Brendan Eich hat den Grundstein für JavaScript in 10 Tagen gelegt […]

… mit ürsprünglich Mocha für den Netscape Navigator über LiveScript bis hin zu JavaScript sowie ECMAScript.

Frage: Man sagt ja, JavaScript ist Scheme mit C Syntax. Wovon wurde JavaScript eigentlich inspiriert bzw. gibt es Vorbilder?

Ed Post: Brendan Eich liebte zwar Scheme, was salopp gesagt einen Lisp-Dialekt ist, war aber wohl hauptsächlich von Self inspiriert, als er mit der Umsetzung von JavaScript begann [NYS13].

Ist JavaScript ein Scheme mit C-Syntax? […]

… Brendan Eich liebte zwar Scheme, JavaScript ist aber von Self inspiriert.

Frage: Es gab doch bestimmt einen Grund für die Entwicklung von JavaScript, wofür wurde denn damals JavaScript entwickelt?

Ed Post: Brendan Eich sagt dazu:

… We aimed to provide a ‘glue language’ for the Web designers and part time programmers who were building Web content from components such as images, plugins, and Java applets…” [RAU11]

Frage: Wie ging es denn weiter mit der Entwicklung von JavaScript? Seit 1995 sind ja doch einige Jahre vergangen…

Die unübersichtliche Versionsgeschichte von JavaScript […]

… beschreibt recht gut den wirren Werdegang von JavaScript nebst ECMAScript.

Ed Post: Gute Frage, erscheinen die Versionen auf den ersten Blick unübersichtlich: So gibt es die Versionsgeschichte von JavaScript wie auch die von ECMAScript. Auf Wikipedia kann man zur Geschichte ganz gut erkennen, dass JavaScript, anfangs mit klassenloser Objektorientierung gestartet ist, seit 2015 aber das Konzept der Klasse kennt:

… Neue Syntax für komplexe Applikationen wie Klassen und Module…” [JSG18].

Frage: Bevor wir uns mit der Objektorientierung befassen, was ist ECMAScript bezüglich JavaScript?

Ed Post: Mit ECMAScript wurde JavaScript mit all seinen Ecken und Kanten in einen quasi Standard verwandelt:

… It was created to standardize JavaScript, so as to foster multiple independent implementations …” [ECM18]

Von Prototypen, Objekten und Klassen

Frage: Kommen wir zurück zur Objektorientierung, wie kann ich klassenlose Objektorientierung verstehen?

Ed Post: Bei der klassenlosen Objektorientierung handelt es sich um prototypenbasierte Programmierung, bei der auf das Sprachelement der Klasse verzichtet wird. Salopp gesagt werden Objekte nicht durch Instanziierung einer Klasse, sondern durch Klonen bereits existierender Objekte - den Prototypen - erzeugt [PRO18]. Sie werden sozusagen Programmiert. Objekte bleiben zur Laufzeit strukturell veränderbar.

Klassenbasierte Objektorientierung findet zur Compilezeit statt […]

… während prototypenbasierte Objektorientierung erst zur Laufzeit stattfindet - und damit werden entsprechende Fehler erst beim Kunden sichtbar.

Frage: Was mich interessiert, sind die Vorteile der prototypenbasierten Programmierung. Nachteile gibt es offensichtlich nicht, denn ich bin flexibler. Ich kann meine Objekte zur Laufzeit weiterhin verändern, während bei einer klassenbasierten Objektorientierung eine feste Klassenstruktur zur Compilezeit vorab(!) festgelegt wird.

Ed Post: Diese Flexibilität die Struktur von Objekten zur Laufzeit zu verändern, wird durch eine schlechtere Wartbarkeit des Programmcodes und dem Fehlen des “Principle of Least Astonishment” [PRI18] erkauft [WIN14]. So kann sich ein JS-Programmierer bei der Verwendung fremden Codes nicht wirklich auf die zu erwartende Struktur eines Objektes verlassen. Und da JavaScript eine interpretierte Sprache ist, lassen sich darauf beruhende Fehler meist erst zur Laufzeit feststellen. Also erst, wenn es zu spät ist.

Die Einfachheit von JavaScript wird durch Fehlen das ‘Principle of Least Astonishment’ [PRI18] teuer erkauft.” [WIN14]

Frage: Welche Auswirkungen sollte es denn bitteschön haben, wenn sich der Kontrakt, hier die Objektstruktur, schwer einhalten lässt?

Ed Post: Der Kontrakt lässt sich theoretisch schon einhalten, nur ist es in JavaScript mit seiner schwachen Typisierung und dem dynamischen Typsystem sehr viel einfacher als bei klassenbasierter Objektorientierung (stark typisierter Programmiersprachen, Anm.d.Red.), unbemerkt Änderungen in die Objektstruktur zu schmuggeln.

Frage: Dafür kann sich mit JavaScript der Typ einer Variablen jederzeit zur Laufzeit ändern. Und eine Konvertierung von einem Typ zu einem anderen Typ wird dabei implizit vorgenommen. Wir haben es hier also mit einem dynamischen Typsystem (mit schwacher Typisierung, Anm.d.Red.) zu tun. Damit lösen sich solche Probleme doch von allein.

… Some programming languages make it easy to use a value of one type as if it were a value of another type. This is sometimes described as “weak typing …” [WEA18]

Ed Post: Anders herum: Bei (stark typisierter, Anm.d.Red.) klassenbasierter Objektorientierung meckert der Compiler sofort, wenn der Kontrakt nicht mehr mit den Erwartungen der Entwickelnden übereinstimmt. Abgesehen davon, wenn ich keinen großen Aufwand betreibe [DEL16], kann jeder JavaScript-Code zur Laufzeit meine Objekte strukturell verändern, so dass ich sie nachher nicht mehr wiedererkenne.

Frage: Ich bleibe dabei: Wo liegt das Problem? Ich sehe keines, wechseln doch meine Werte implizit den Typ, ohne dass ich etwas unternehmen müsste.

Ed Post: So ein veränderter Kontrakt eines Objekts kann durchaus problematisch sein, beispielsweise wenn sich der Typ eines Attributs von Zahl auf String ändert. Wenn ich etwa eine Zahl erwarte mit der ich addieren will, aber anstelle der Zahl einen String erhalte.

Frage: Sie meinen, wenn ich die Version einer verwendeten JS-Bibliothek aktualisiere und danach bei einem Funktionsaufruf ein String bekomme, obwohl vorher eine Zahl geliefert wurde?

Ed Post: Ja, zum Beispiel. Wie sieht das Ergebnis meiner Addition bei impliziter Umwandlung von String nach Zahl aus oder werden nun zwei Strings addiert, also konkateniert? Und wo oder wann bemerke ich diesen Fehler? Kann ich die Ursache schnell finden?

Bei prototypenbasierter Objektorientierung gibt es keinen verlässlichen Kontrakt für unsere Objekte […]

… in Kombination mit impliziter Umwandlung von Typen entstehen Fehlersituationen, deren Ursprünge sich schwer identifizieren lassen.

Frage: Wir haben von JS-Bibliotheken gesprochen. Hat die prototypenbasierte Objektorientierung damit Auswirkungen auf das JS-Ökosystem?

Stabile JS-Bibliotheken und prototypenbasierte Objektorientierung […]

… sind ein Widerspruch in sich, man kann das Eine nicht mit dem Anderen haben.

Ed Post: Wir bekommen mit der prototypenbasierten Objektorientierung keinen verlässlichen Kontrakt für unsere Objekte, weshalb sich JS-Bibliotheken sehr schwer tun, stabile Schnittstellen über einen längeren Zeitraum hinweg - man spricht von gerade einmal 12 Monaten - anzubieten [MOS15]. Ember.js hat jüngst den LTS (“Long Term Support”) einer Version nach 12 Monaten eingestellt [EMB16]. Bei vielen verwenden JS-Bibliotheken in einem Projekt wird der Upgrade-Pfad daher sehr steinig. In anderen Bereichen der IT spricht man bei LTS von 5 oder 10 Jahren…

Die Wahrheit zu LTS und JavaScript ist, dass […]

… LTS (long term support, Anm.d.Red.) bei JavaScript quasi nicht vorhanden ist.

Frage: Ich habe gehört, dass ein typisches JavaScript Projekt gerne mehrere hundert externen JS-Bibliotheken anzieht. Wie steinig ist denn da der Upgrade-Pfad nach sagen wir 12 oder 24 Monaten?

Ed Post: Sie meinen, was passiert, wenn ich 24 Monate meinen Code nicht anfasse, weil das Projekt beendet ist? Ein typische Node.js Projekt hat gerne um die 100, 500, 1000 oder mehr, auch transitive, Abhängigkeiten. Die Auswirkungen des praktisch nicht vorhandenen LTS bei 300 externen Abhängigkeiten bedeuten über so einen Zeitraum eine Änderungsrate, die hoch genug ist, dass mein Code danach mit den dann aktuellen JS-Bibliotheken praktisch nicht mehr Lauffähig ist.

Frage: Das kann man Entwickelnden doch nicht ernsthaft zumuten wollen. Ganz abgesehen von der damit verbundenen Fleißarbeit, die JS-Bibliotheken in einem aktuellen und zueinander konsistenten Zustand zu halten…

Ed Post: Es muss also Aufwand allein darin investiert werden, dass der Code mit den neuen Versionen der verwendeten JS-Bibliotheken überhaupt wieder läuft. Wenn denn die Entwicklung der jeweiligen JS-Bibliotheken dann überhaupt noch betrieben wird. Kritisch sind vor allem die unerkannten Inkompatibilitäten, da sich viele Probleme erst zur Laufzeit zeigen. JavaScript ist ja immer noch eine interpretierte Script-Sprache…

Kurzlebige JS-Bibliotheken (und deren Abhängigkeiten) bescheren einen teuren Upgrade-Pfad […]

… denn Fehler zeigen sich häufig erst zur Laufzeit, im schlimmsten Fall erst beim Kunden.

Frage: Und was für ein Fazit ziehen sie aus den Merkmalen der prototypenbasierten Programmierung in Bezug auf JavaScript?

Ed Post: Die prototypenbasierte Programmierung ist einfach ungeeignet, um eine stabile API für eine JS-Bibliothek zu entwerfen. Zusammenfassend gibt es dafür mehrere Gründe: Prototypen werden Programmiert und sind im auszuführenden Code verteilt oder gar versteckt. Daher ist die Struktur von Objekten schwer zu erkennen und noch schwieriger zu dokumentieren.

Amorphe Datenstrukturen

Frage: Sie wollen damit sagen, dass die Objekte oder Datenstrukturen irgendwo im Code verteilt ausprogrammiert worden sein können?

Ed Post: Da die Struktur eines Objektes bei der prototypenbasierten Programmierung “programmiert” wird, kann sie darüber hinaus auch noch leicht und unbemerkt an ganz anderen Stellen im Code verändert werden. Um dem entgegenzuwirken, wird unter anderem TypeScript in vielen Projekten eingesetzt. Fehlende statische Typisierung ist eben ungeeignet, stabile Objektstrukturen zu erhalten. Und ohne Verlässlichkeit auch kein LTS.

Frage: Was hat dieses Konzept für Auswirkungen auf die Entwicklung?

Ed Post: Da die Datenstrukturen von JS-Bibliotheken erst zur Laufzeit bekannt sind, können die Entwickelnden eigentlich auch erst zur Laufzeit wissen, welche konkreten Datenstrukturen diese JS-Bibliotheken in ihren Schnittstellen anbieten …

Wie der Begriff Datenstruktur schon besagt, handelt es sich dabei um eine Struktur […]

… und nicht etwas amorphes oder gar beliebig formloses. Algorithmen brauchen stabile Datenstrukturen, um deterministische Ergebnisse zu produzieren

Ed Post: … Und die Entwickelnden müssen Datenstrukturen programmieren, was dem Sinn einer Datenstruktur zuwider läuft, denn sie ist eine Struktur und nicht etwas amorphes oder gar formloses (Antonyme, Anm.d.Red.). Damit Operationen bzw. Algorithmen auf den Datenstrukturen sinnvoll arbeiten können, müssen die Datenstrukturen verlässlich sein… [DST18]

Prototypen sind im auszuführenden Code verteilt oder gar versteckt […]

… da sie programmiert werden: Sie können sich in jedem Code-Schnipsel befinden. Allein, eine Datenstruktur benötig Programmlogik für ihre Ausformulierung, sie steht nicht für sich selber und kann sich jederzeit ändern.

Frage: Wie kann ich mich dennoch in JavaScript vor Unwägbarkeit bezüglich der dynamischen Objektstruktur wappnen?

Ed Post: Duck-Typing ist charakteristisch für objektorientierte Skriptsprachen. Es ist eigentlich von Sprachen wie Python, Groovy, PHP oder Ruby bekannt, kann aber auch mit JavaScript verwendet werden [YOU08]. Ein Zitat beschreibt Duck-Typing wie folgt:

“… When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck …” [DUC18]

Frage: Dabei werden Objekte zur Laufzeit auf das Vorhandensein bestimmter Methoden oder Attribute geprüft.

Ed Post: Auf solche Methoden zurückzugreifen um ungewollte Effekte zu vermeiden, ist meiner Meinung nach Ausdruck großer Hilflosigkeit.

Frage: Kann hier nicht das Konstrukt der Klasse, seit ECMAScript 2015 Bestandteil von JavaScript, Abhilfe schaffen?

Ed Post: Trotz dem Konstrukt der Klasse sind Objekte in JavaScript weiterhin dynamisch manipulierbar. Klassen sind ja nichts weiter als ein bequemer Weg, old-school Konstruktor-Funktionen zu erstellen.

Die Objektorientierung in JavaScript ist zwiespältig […]

… reicht sie doch von der prototypenbasierten Programmierung zur - als schnöder Aufsatz der prototypenbasierten Programmierung realisierten - klassenbasierten Objektorientierung.

Sloppy Mode, strict Mode

Frage: Apropos ECMAScriptECMAScript 5 unterstützt den strict mode. Dadurch wird JavaScript ja noch besser. Was hat es eigentlich mit dem strict mode auf sich?

JavaScript wird dank des strict mode weiter verkompliziert […]

… fügt es doch eine neue Ausführungssemantik neben dem unsäglichen sloppy mode ein.

Ed Post: Der strict mode ist nicht nur einfach eine Untermenge des sloppy modes. Er verwendet - beabsichtigt - auch teilweise eine andere Semantik für den gleichen Code gegenüber dem sloppy mode, was auch für Fehler sorgt: Der strict mode kann auf ganze Skripts angewendet werden oder auf einzelne Funktionen, aber nicht in Blöcken ({...}). In Blöcken bleibt eine Anweisung use strict wirkungslos.

… JavaScript’s strict mode, introduced in ECMAScript 5, is a way to opt in to a restricted variant of JavaScript, thereby implicitly opting-out of sloppy mode. Strict mode isn’t just a subset: it intentionally has different semantics from normal code…” [STR18]

Frage: Und was ist der sloppy mode, und weshalb hat man den strict mode eingeführt? “Sloppy” bedeutet ja so viel wie nachlässig oder schlampig…

Ed Post: Mit sloppy mode bezeichnet man den weniger durchschaubaren Modus, in dem JavaScript bei nicht aktiviertem strict mode ausgeführt wird. Was vor ECMAScript 5 ganz normal war. Man muss sich den strict mode jedoch genau auf der Zunge zergehen lassen: Im strict mode ergibt derselbe Code zur Laufzeit andere Ergebnisse als im normalen, dem sogenannten sloppy mode. Diese Nachbesserung von JS kann kaum als Qualitätsmerkmal der Sprache JS herausgestellt werden [SLO18].

Der strict mode führt JavaScript-Code mit einer anderen Semantik aus […]

… als der sloppy mode, was allein schon zum Problem werden kann.

JavaScript … ECMAScript … TypeScript … WebAssembly

Frage: Kommen wir zurück zu den JavaScript bzw. zu den ECMAScript Versionen. Wie wirken sich diese auf JavaScript-Projekte aus?

Ed Post: Sehen wir uns das einmal genauer an: ECMAScript 5.1 (2011), ECMAScript 2015 bzw. Version 6 mit komplett neuer Syntax für Klassen und Module, solche grundlegenden Änderungen findet man so nicht bei anderen Programmiersprachen. Dann ECMAScript 2016, ECMAScript 2017, ECMAScript 2018. Zusätzlich gibt es noch TypeScript, wovon immer mal wieder etwas in einen neuen ECMAScript-Standard hineinrutscht. Sprachkonstrukte von TypeScript wie Klassen, Vererbung, Module, anonyme Funktionen oder Generics wurden dann auch in ECMAScript 6 übernommen [TYP18].

Dank der JS-Versionsvielfalt sagt ein “Ich kann JavaScript” gar nichts aus […]

… das kann ein echtes Problem für das Projekt-Staffing sein.

Frage: Aber warum wird dann nicht gleich eine neue Programmiersprache entworfen oder eine andere Programmiersprache verwendet?

Ed Post: (lacht) Weil JS-Entwickelnde nicht willens sind, eine neue Sprache zu lernen? Nein, im Ernst, zu JavaScript gab es lange Zeit keine Alternativen, weshalb auf JavaScript sogar das Klassenkonzept aufgesattelt wurde, ohne dass der Unterbau dafür geeignet wäre. Ich erwähnte ja schon die dynamischen Objektstrukturen…

Frage: Aber am Ende ist doch alles JavaScript?

Ed Post: Zwischen ECMAScript 5.1, ECMAScript 6 und TypeScript gibt es Riesenunterschiede. “Ich kann JavaScript” sagt gar nichts aus. Das kann ein echtes Problem für das Projekt-Staffing sein.

Frage: Sie sagten “zu JavaScript gab es lange Zeit keine Alternativen”. Gibt es denn jetzt Alternativen?

Ed Post: Mit WebAssembly macht sich gerade ein Bytecode-Standard auf, das Web zu erobern. Dieser Standard ist auf dem Vormarsch und in JavaScript-Kreisen wird schon gegen das Binärformat Stimmung gemacht. Es scheint also Befürchtungen zu geben, dass WebAssembly JavaScript demnächst ablösen könnte. Aber das wird so bald nicht passieren.

Wovor viele JS-Entwickelnden Angst haben, ist WebAssembly […]

… denn mit WebAssembly wächst eine echte Alternative zu JavaScript heran.

Frage: Vielleicht, weil JS-Entwickelnde nicht willens sind, eine neue Sprache zu lernen?

Ed Post: (lacht) Vielleicht. Auch muss WebAssembly noch vieles lernen, z.B. den Zugriff auf das DOM oder die Unterstützung von Programmiersprachen, die einen Garbage-Collector voraussetzen (wovon JavaScript selber eine ist, Anm.d.Red.) [GAR17].

Weiter geht es mit Teil 2, in dem wir über besondere JavaScript-Spezialitäten sprechen…

In Teil 1 dieses Interviews haben wir uns mit den wilden Jahren von JavaScript befasst, in Teil 2 sprechen wir über besondere JavaScript-Spezialitäten und in Teil 3 wagt Ed Post ein Fazit und eine Prognose zu JavaScript.


[ABO18]: MDN, 2018
[ARR18]: MDN, 2018
[BER13]: Michael Berry, 2013
[BIG18], Chrome Platform Status, 2018
[BLA18]: Wikipedia, 2018
[BÖC18]: Hanno Böck, 2018
[BUC18]: Craig Buckler, 2018
[CLA18]: Luc Claustres, 2018
[COM18]: Wikipedia, 2018
[CRO10]: Angus Croll, 2010
[CRO11]: Angus Croll, 2010
[CUN10]: Cunningham & Cunningham, 2010
[DAT18]: MDN, 2018
[DEL16]: Carlos Delgado, 2016
[DON19]: Node.js, 2019
[DST18]: Wikipedia, 2018
[DEV16]: Anne Dev, 2016
[DIS16]: Peter DiSalvo, 2016
[DUC18]: Wikipedia, 2018
[ECM18]: Wikipedia, 2018
[EMB16]: Ember, 2016
[ENG15]: Richard Kenneth Eng, 2016
[ENG16]: Richard Kenneth Eng, 2016
[ENG17]: Richard Kenneth Eng, 2017
[EPO19]: Ed Post, 2019
[FUN18]: Wikipedia, 2018
[GAR17]: Andreas Rossberg, 2017
[GIL18]: David Gilbertson, 2018
[GRO18]: MDN, 2018
[HOR18]: Wikipedia, 2018
[ION17]: Ionică Bizău, 2017
[JAV18, Wikipedia, 2018
[JSC16]: Jordan Scales, 2016
[JSG18]: Wikipedia, 2018
[JVM18]: Wikipedia, 2018
[KLI13]: Felix Kling, 2013
[LYN18]: WebAssembly, 2018
[MCC17]: Judy McConnell, 2017
[MIC15]: James Mickens, 2015
[MOS15]: Brian Moschel, 2015
[MWV18]: Wikipedia 2018
[NUM18]: MDN, 2018
[NYS13]: Bob Nystrom, 2013
[OBS18]: Wikipedia, 2018
[PAR18]: Matthias Parbel, 2018
[PET12]: Ke Pi, 2012
[POS82]: Ed Post, 1982
[PRI18]: Wikipedia, 2018
[PRO18]: Wikipedia, 2018
[RAJ16]: Raja Rao, 2016
[RAU11]: Dr. Axel Rauschmayer, 2011
[REA18]: Wikipedia, 2018
[RIN14]: Brian Rinaldi, 2014
[RUN18]: MDN, 2018
[SIG18]: NPM, 2018
[SLO18]: MDN, 2018
[SMT18]: Wikipedia, 2018
[STR18]: MDN, 2018
[SYM18]: Wikipedia, 2018
[TAR18]: MDN, 2018
[TCO18]: Wikipedia, 2018
[TYP18]: Wikipedia, 2018
[UND18]: Wikipedia 2018
[UMA18]: u/marosurbanec, 2016
[UNP18]: NPM, 2018
[UPR18]: u/ProbablyNotCanadian, 2018
[USE18]: MDN, 2018
[VER18]: Wikipedia, 2018
[WEA18]: Wikipedia, 2018
[WEB18]: Wikipedia, 2018
[WIL16]: Chris Williams, 2016
[WIN14]: Topher Winward, 2014
[WTF16]: Brian LeRoux & Andrew Lunny, 2016
[YOU08]: Michael Youssef, 2008