2 Punkte von GN⁺ 2024-11-29 | 1 Kommentare | Auf WhatsApp teilen
  • Janet for Mortals ist ein kostenloses Online-Buch über die Programmiersprache Janet, aber der Rückblick konzentriert sich weniger auf das Buch selbst als auf den Entstehungsprozess eines technischen Buchs inklusive Web-REPL und Beispielprojekten
  • Die gesamte Arbeit dauerte 20 Wochen und lag damit über der Schätzung von 12 Wochen für das reine Schreiben, weil zusätzliche Arbeiten wie Website, C++-Bindings, Browser-Demos, CLI-Parser und Test-Tools hinzukamen
  • Die Buch-Website bietet ein eingebautes REPL mit CodeMirror und Lezer-Grammatik; die Autovervollständigung fragt die Janet-Umgebung per WebAssembly ab und (report) speichert Feedback in SQLite
  • cmd, judge, to do und Toodle.Studio dienen als grundlegende Beispiele dafür, dass Janet für Scripting, CLI-Tools, Tests, Browser-Ausführung und JavaScript-Interoperabilität eingesetzt werden kann
  • Unmittelbar nach dem Start gab es allein durch Einreichungen bei Hacker News und Lobsters am Freitag 30.025, am Samstag 9.568 und am Sonntag 3.777 eindeutige Besucher, aber die Zahl eindeutiger IPs, die mindestens 5 Kapitel gelesen hatten, wird auf 387 geschätzt

Umfang des Buchs und tatsächlicher Arbeitsaufwand

  • Janet for Mortals ist ein kostenloses Online-Buch über die Programmiersprache Janet
  • Die gesamte Produktionszeit betrug 20 Wochen in der Freizeit
    • Die ursprüngliche Schätzung lag bei 12 Wochen, und nur bezogen auf die Schreibzeit des englischen Haupttexts lag sie nicht allzu weit daneben
    • Im tatsächlichen Zeitplan steckte ein großer Anteil an begleitenden Coding-Projekten rund um das Buch
  • Der Endumfang beträgt 44.000 Wörter englische Prosa ohne Code-Schnipsel
    • Als Vergleich wird The Great Gatsby mit 47.000 Wörtern genannt
    • Es ist weniger als halb so lang wie eine frühere Artikelserie über Nix
  • Über 5 Monate hinweg wurden zusammen mit dem Buch auch folgende Arbeiten umgesetzt
    • die Buch-Website
    • jimmy: Bindings für eine C++-Bibliothek für persistente Datenstrukturen
    • Toodle.Studio: interaktiver Turtle-Graphics-Spielplatz
    • cmd: Bibliothek zum Parsen von Kommandozeilenargumenten
    • judge: Test-Framework für Inline-Snapshots
    • to do: Kommandozeilen-Manager für Aufgabenlisten

Website und eingebautes REPL

  • Das zentrale Element der Website von Janet for Mortals ist das eingebaute REPL
    • Nutzer können das REPL jederzeit mit der Escape-Taste öffnen
    • Das REPL ist am unteren Seitenrand fixiert und verdeckt den Haupttext kaum
  • Der Editor verwendet CodeMirror
    • CodeMirror unterstützt Janet standardmäßig nicht
    • Als Grundlage diente eine zuvor für Bauble erstellte Janet-Sprachunterstützung
    • Janet-Syntax wie multi`backtick`quoted-Strings, die im Bauble-DSL nicht wichtig war, wurde für das Buch benötigt
  • Beim Ausbau der von CodeMirror verwendeten Lezer-Grammatik wurde dieselbe Grammatik auch für das Syntax-Highlighting der Code-Schnipsel im Buch wiederverwendet
    • Unter den bekannten Static-Site-Generatoren ließ sich keiner finden, der Janet-Code-Highlighting unterstützt
    • Anfangs war das Buch schwarzweiß, später wurden Farben hinzugefügt, damit die ungewohnte Janet-Syntax vertrauter wirkt
  • Der Static-Site-Generator wurde selbst geschrieben und nutzt redo
    • Der Kern des Generators wurde in JavaScript geschrieben, sodass sich die Lezer-Grammatik einbinden ließ
    • Die Gesamtarchitektur war eine fragile Konstruktion, die mit Shell zusammengekettet wurde
  • Remark wurde sowohl zum Parsen des Buchquelltexts als auch im clientseitigen REPL verwendet
    • Es wurde eine einfache Erweiterung hinzugefügt, um Code-Blöcke zu beschriften
    • Die Docstrings der Janet-Standardbibliothek sind in Markdown geschrieben und werden für die REPL-Autovervollständigung on the fly als HTML gerendert

Autovervollständigung und unidirektionales Feedback

  • Die REPL-Autovervollständigung wurde als wichtig für Leser betrachtet, die Janet zum ersten Mal begegnen
    • Beim Start des REPL wird die Janet-Umgebung dynamisch über WebAssembly abgefragt
    • Wenn Nutzer neue Symbole mit Docstring definieren, erscheinen diese nicht in der Autovervollständigung
    • Man könnte die Autovervollständigung nach jedem ausgeführten Befehl neu erzeugen, aber das erschien den Aufwand nicht wert
  • Die Funktion (report) nimmt einen String entgegen und schickt ihn per POST an einen einfachen Webserver, der ihn in einer SQLite-Datenbank speichert
    • Es ähnelt einem Kommentarfeld, nur dass das Senden direkt aus dem REPL erfolgt
    • Mit dieser Funktion wurde Feedback gelesen und etliche Fehler wurden behoben
    • Eine Möglichkeit zum Antworten wurde nicht implementiert
  • Das Report-Backend ist keine Janet-, sondern eine kleine Haskell-Anwendung
    • Sie nimmt lediglich POST-Anfragen entgegen und schreibt sie in eine SQLite-Datenbank
  • Der Webserver wurde nicht in Janet gebaut
    • Als wichtigsten Aspekt eines Webservers wird Sicherheit angesehen
    • Janet und die Janet-HTTP-Bibliothek wurden nicht als ausreichend erprobt betrachtet, um direkt mit dem Internet verbunden zu werden

jimmy: Experiment zur C++-Interoperabilität

  • jimmy ist ein Janet-Binding für immer
    • immer ist eine Bibliothek für persistente Datenstrukturen
  • Das Binding ist nicht fertig, und es wird wahrscheinlich auch nicht fertiggestellt, solange kein konkreter Einsatzfall entsteht
  • Trotzdem wird es als gelungenes Beispiel dafür betrachtet, wie man in Janet mit C++-Code interoperiert

Toodle.Studio und Janet im Browser

  • Bauble ist ein zuvor gebauter kleiner Kunst-Spielplatz und war die erste Erfahrung damit, Janet in den Browser einzubetten
    • Damals gab es nicht viel Material zum Einbetten von Janet
    • Die Kombination aus WebAssembly, Emscripten und TypeScript im Browser machte die Sache schwierig
  • Das Endergebnis von Bauble war eine Website, deren Anwendungslogik in Janet geschrieben war
    • Für die UI wurde viel JavaScript verwendet, aber die Kernlogik lag in Janet
  • Ein wichtiger Grund für das Schreiben des Buchs war der Wunsch, die Technik für den Einsatz von Janet im Browser zugänglicher zu machen
  • Im Buch wurde statt Bauble Toodle.Studio als Beispiel gebaut
    • Bauble war zustandslos und fast eine reine Funktion von String zu String, also aus Sicht der Interoperabilität eher simpel
    • Toodle.Studio ist ein offensichtlicher Fork von Bauble, aber die Interoperabilität zwischen JavaScript und Janet ist komplexer
  • Toodle.Studio hatte technische Eigenschaften, die es als Beispiel für das Buch geeigneter machten
    • Lang laufende Janet-Programme müssen über die Zeit asynchron ausgeführt werden
    • JavaScript-Code hält mehrere Referenzen auf denselben Janet-Wert, daher muss Speicherverwaltung berücksichtigt werden
    • Komplexe verschachtelte Datenstrukturen müssen über C++ zwischen Janet und JavaScript hin- und hergereicht werden
  • Das Logo von Toodle.Studio ist eine mit Bauble erstellte animierte Schildkröte
    • Nachdem Rückmeldungen kamen, dass einem Turtle-Graphics-Demo eine Schildkröte fehle, wurde sie ergänzt
    • Die Augen wurden so gebaut, dass sie dem Mauszeiger folgen

cmd: CLI-Argument-Parser für Janet

  • cmd ist eine Bibliothek zum Parsen von Kommandozeilenargumenten
    • Im Buch taucht sie nur in etwa drei Absätzen auf, war aber nötig, um klar zu zeigen, dass Janet eine gute Scripting-Sprache ist
  • cmd ist stark von Core.Command aus OCaml beeinflusst
    • Core.Command wird als die beste Bibliothek zum Parsen von Kommandozeilenargumenten betrachtet, die je verwendet wurde
    • In Janet sollte dieses Nutzungserlebnis nachgebildet werden
  • cmd ist nicht so gut wie Core.Command
    • Mit Typen wäre alles deutlich einfacher
    • Trotzdem deckt es 95 % der als wichtig erachteten Funktionen ab und ist dank knapper Syntax für ad-hoc-Skripte bequemer zu verwenden
  • Eine Funktion zum Erzeugen von Bash-Autovervollständigung fehlt noch
    • Core.Command erzeugt diese automatisch
    • Die API von cmd wurde so entworfen, dass sich diese Funktion später ergänzen lässt

judge: Test-Framework für Inline-Snapshots

  • judge war eines der ersten Dinge, die 2021 in Janet gebaut wurden
  • Nachdem Janet besser verstanden wurde, wurde es von Grund auf neu geschrieben
    • Die API wurde angenehmer in der Nutzung
    • Auch die Implementierung wurde wesentlich einfacher und leichter veränderbar
  • Der wichtigste Unterschied zwischen Judge v1 und v2 betrifft Test-Orte und Helper
    • Tests können nicht nur im Verzeichnis test/, sondern auch in normalen Quelldateien stehen
    • Die Helper test-macro und test-stdout wurden hinzugefügt
  • Das OCaml-Gegenstück von test-stdout sei im Berufsalltag fast die einzige Art gewesen, Tests zu schreiben
    • In OCaml gibt es keinen besonders guten Weg, beliebige Daten in Quellcode einzubetten, deshalb wird alles in Strings umgewandelt
  • Nach der Veröffentlichung des Buchs wurde Judge um einen --interactive-Modus erweitert

to do: Aufgaben-Tool in Janet statt Bash

  • to do wurde als Beispiel für das Scripting-Kapitel ausgewählt
    • Es war ein bereits zuvor in Bash gebautes nichttriviales Tool, und die Bash-Implementierung war schmerzhaft
  • In Bash waren besonders Text-Parsing und Datumsverarbeitung schwierig
    • Mehrzeiligen Text mit Sed zu parsen, machte keinen Spaß
    • date-Manipulationen, die unter macOS und Linux gleich funktionieren, wurden praktisch als unmöglich angesehen
  • In Janet konnten mit PEG, sh, cmd schneller mehr Funktionen gebaut werden als in der ursprünglichen Bash-Aufgabenliste
    • Als Beispiel wurde eine Mehrfachauswahl mit fzf ergänzt
    • In Bash ist es schwierig, null-terminierte Strings aufzubauen
  • Im Buch wird nur eine vereinfachte Version behandelt
    • Es gibt keine Terminplanung für zukünftige Aufgaben
    • Es gibt kein Konzept, Aufgaben zu „überspringen“
    • Die Kernfunktionen sind das Hinzufügen von Einträgen zur Liste und das Abschließen von Aufgaben
  • Zusammen mit zsh-autoquoter wird es als überraschend nützliche App betrachtet

Code-Arbeit während des Schreibens und Wartung

  • Von den 20 Wochen Arbeit am Buch entfiel fast die Hälfte auf das Schreiben von Code
    • 8 Wochen waren Coding-Arbeit, und in manchen Phasen liefen Schreiben und Coden parallel
  • Anfangs wurden nur Verbesserungen an Judge und das Schreiben eines Argument-Parsers erwartet
    • Die Implementierung des Argument-Parsers war deutlich schwieriger als erwartet
    • Dass Bauble zu simpel war und deshalb noch ein neuer Art-Spielplatz gebaut werden würde, war nicht absehbar
  • Der eigentliche Text wurde in Markdown in Sublime Text geschrieben
    • Sublime Text ist der bevorzugte Editor für lange Prosa
  • Während des Schreibens erschienen 2 neue Versionen von Janet
    • Die Kapitel zu Debugging und nativen Modulen mussten an die Sprachänderungen angepasst werden
    • Geplant ist, das Buch an aktuelle Janet-Releases anzupassen

Reaktionen zum Start und wie viel tatsächlich gelesen wurde

  • Die Werbung für das Buch bestand im Wesentlichen aus Einreichungen bei Hacker News, Lobsters und einigen Tweets
    • Auf Hacker News war es den ganzen Tag auf der Startseite und eine Zeit lang auf Platz 1
  • Laut den Nginx-Access-Logs gab es folgende eindeutige Besucherzahlen
    • Freitag: 30.025
    • Samstag: 9.568
    • Sonntag: 3.777
  • Diese Zahlen liegen eher nahe an der Zahl der Leute, die auf den Link geklickt haben; die Zahl derjenigen, die das Buch wirklich gelesen haben, dürfte viel kleiner sein
  • Auf der Site gibt es keine clientseitige Verhaltensanalyse
    • Daher wird nur grob anhand der Access-Logs geschätzt
  • Der Besuchsfluss zwischen den Kapiteln sah nach schwacher Bindung aus
    • Kapitel 1: 22 % der Besucher der Homepage
    • Kapitel 2: 20 % der Besucher von Kapitel 1
    • Kapitel 3: 69 % der Besucher von Kapitel 2
    • Kapitel 4 „Pegular Expressions“ und Kapitel 9 „Xenofunctions“ hatten mehr Besucher als Kapitel 3
  • Zum Ende des Veröffentlichungswochenendes lag die beste Schätzung für die Zahl echter Leser bei 387
    • Grundlage war die Zahl eindeutiger IPs, die 5 oder mehr verschiedene Kapitel geladen hatten

Herkunft des Namens und Grenzen, die das Feedback zeigte

  • Der Name der Sprache Janet stammt von Janet, dem unsterblichen Wesen aus The Good Place
    • Diese Figur hilft mortals bei der Bewegung durch das Jenseits, was auch den Buchtitel erklärt
  • Das am wenigsten besuchte Kapitel war „Testing and Debugging“
    • Es ist das drittletzte Kapitel des Buchs
    • Die letzten drei Kapitel werden als die interessantesten des Buchs angesehen
    • Der dort vorgestellte Testansatz wird als einer der größten Produktivitätsschübe der eigenen Ingenieurskarriere betrachtet
  • Über die Report-Funktion des eingebauten REPL gingen 494 Feedbacks ein
    • Viele davon waren „gutes Buch“ oder Testnachrichten
    • Dutzende waren Meldungen zu Tippfehlern, Bitten um Erläuterung oder nützliche Kommentare
  • Einige Nutzer schickten Fragen ohne Kontaktmöglichkeit, und da es keine Antwortfunktion gab, konnte nicht reagiert werden
    • Die Report-Funktion wurde als sehr primitive unidirektionale Feedback-Funktion umgesetzt

1 Kommentare

 
GN⁺ 2024-11-29
Meinungen auf Hacker News
  • Ebenfalls nicht zu übersehen ist https://bauble.studio/ vom selben Autor.
    Im Browser auf meinem alten Computer läuft es nicht, aber wenn ich beim Lernen in der Bibliothek eine Pause machen will, spiele ich auf einem Bibliothekscomputer etwa 30 Minuten mit bauble herum.
    Es ist erstaunlich, welche Grafiken man erzeugen kann, indem man nur Zahlen hin und her ändert, und ich hoffe, dass Janet lange Bestand hat.

    • Auf einem MacBook Pro M1 Max von 2021 mit MacOS 15.1.1 funktioniert es in Chrome, aber in Firefox gibt es den Compile-Fehler unknown symbol twist.
      error: script:16:1: compile error: unknown symbol twist
      in evaluate [lib/evaluator.janet] on line 81, column 7
      in bauble-evaluator/evaluate [lib/init.janet] on line 8, column 12
  • Es ist interessant, Janet mit GNU Guile zu vergleichen.
    Guiles ursprünglicher Vorteil ist, dass es als Sprache entwickelt wurde, die sich leicht neben C verwenden lässt, aber weil es eine ältere Sprache ist, scheint es moderne Ansätze wie einen standardmäßig in die Sprach-Toolchain integrierten Paketmanager noch nicht übernommen zu haben.
    Was mir an Guile gefällt, ist, dass viel Mühe darauf verwendet wurde, die Kompatibilität mit den RNRS-Standards zu erklären.
    Ich weiß nicht, wie Scheme-artig Janet in der Praxis wirklich ist, aber es macht mich neugierig.

    • Janet ist überhaupt nicht Scheme-artig.
      Es ist eher so, als hätte jemand Clojure auf Lua gebaut.
  • Das Buch ist https://janet.guide/, und die Sprache ist https://janet-lang.org/.

  • Mir gefiel der praxisorientierte Ansatz dieses Buchs, und er ist ein wichtiger Grund, warum ich gerade Everybody Codes in Janet löse und dabei lerne.
    https://everybody.codes

  • Die Formulierung „die Schildkröte ist eine Metapher“ finde ich unglücklich.
    Die Schildkröte war keine Metapher, sondern real: http://classicacorn.computinghistory.org.uk/8bit_focus/logo/...
    Natürlich passt es zur Definition von Metapher als „etwas, das für etwas anderes steht, ein Symbol“, aber es klingt wie der Witz, jemand habe das Disketten-Speicher-Icon für einen Kühlschrank gehalten.
    Es fühlt sich so an, als fehle der Kontext, dass es früher tatsächlich lustige und niedliche Hardware-Schildkröten gab.

    • Was auf dieser Seite zu sehen ist, scheint schwerlich als „echte“ Schildkröte gelten zu können.
  • Vom Titel her dachte ich zunächst, es sei ein weiterer KI-Assistent, angelehnt an Janet aus The Good Place, war dann aber angenehm überrascht, dass es tatsächlich eine Programmiersprache ist.
    Die Sprache Janet ist nach Janet benannt, dem unsterblichen Wesen aus The Good Place, das Menschen hilft, sich im Jenseits zurechtzufinden; der Titel ist also ein dazu passender, cleverer Witz.
    Unerwartet fand ich auch, dass sie statt einer Standard-Regex-Engine PEGs (Parsing Expression Grammars) mitbringt.
    Ich habe mir immer gewünscht, dass Sprachen, die eine Standard-Regex-Bibliothek anbieten, auch ein ordentliches PEG mitliefern.

    • GNU Guile hat ebenfalls eine PEG-Bibliothek in der Standardbibliothek.
      Siehe <https://www.gnu.org/software/guile/manual/html_node/PEG-Pars...>
    • Janets Modul spork nimmt in etwa die Rolle einer libc ein, und es hat auch ein Regex-Untermodul, sodass es wahrscheinlich installiert ist.
      Mit Janet bin ich zum ersten Mal mit PEGs in Berührung gekommen, und mir gefällt, wie leistungsfähig und einfach zu verwenden sie sind.
      Obwohl ich mich seit über 20 Jahren immer wieder ein bisschen mit regulären Ausdrücken beschäftigt habe, habe ich PEGs innerhalb weniger Monate besser verstanden.
      In der Janet-Community gibt es auch viele Anspielungen auf The Good Place, und mehrere Third-Party-Module sind nach Figuren der Serie benannt.
    • Elm verfolgt einen ähnlichen Ansatz.
      elm/regex und elm/parser sind zwar nicht eingebaut, aber elm/regex empfiehlt stattdessen die Nutzung von elm/parser.
      Die Herkunft des Namens gefällt mir, aber eine Sprache namens Janet scheint auch die Pflicht zu haben, Kontrolle zu priorisieren.
  • Ich habe das Buch gelesen; es wirkte ziemlich interessant und spielerisch, wodurch das Lernen von Janet deutlich mehr Spaß gemacht hat.
    Die Sprachdokumentation war allerdings in vielerlei Hinsicht unzureichend.
    Funktionen oder Befehle waren einfach aufgelistet, häufig ohne Beispiele oder Erklärungen, oder es fehlte eine Beschreibung dessen, was sie tun.
    Oft konnte ich Funktionen, die ich im Buch gesehen hatte, in der Dokumentation nicht finden, und das wurde trotz meiner Sympathie für Janet einer der Gründe, warum ich aufgehört habe, es zu lernen.
    Mir gefällt, dass es viele vernünftige Defaults hat und eher Gemeinsamkeiten mit Mainstream-Sprachen aufweist, statt stur an alten Lisp-Konventionen festzuhalten.
    Letztlich ist es keine cons-Liste und damit eigentlich kein Lisp, aber das ist in Ordnung.
    Das Problem ist, dass die Sprache nicht ausreichend dokumentiert ist.

    • Ich würde gern wissen, ob du dich an Funktionen oder Befehle erinnerst, die nicht dokumentiert waren.
      Ich bin in der Janet-Community einigermaßen aktiv; wenn ich wüsste, wo etwas fehlt, könnte ich zur Verbesserung der Dokumentation beitragen.
    • Abgesehen davon, dass ich das Buch nicht gelesen habe, hatte ich genau dieselbe Erfahrung.
      Oft gab es nur eine Funktionssignatur und keinerlei weitere Erklärung.
      Ich verstehe, dass umfassende Dokumentation viel Zeit und Mühe kostet, aber das kam so häufig vor, dass ich es beiseitegelegt und angefangen habe, nach einem anderen Lisp zu suchen, das zu Binaries kompiliert.
  • Ich bin mit Janet nicht richtig warm geworden; ich weiß nicht, ob das an mir liegt.
    Das einzige andere Lisp, das ich länger verwendet habe, ist Emacs Lisp, und Janet ist ähnlich genug, aber auf subtile Weise anders, sodass mir ständig kleine Fehler unterlaufen sind.
    Die PEG-Funktionen wirkten in der Dokumentation reizvoll, aber die Syntax war umständlich und verwirrend.
    Die Dokumentation war in dem Sinne vollständig, dass alle Funktionen beschrieben waren, aber sie war sehr knapp und es fehlten Beispiele oder nützliche Anwendungshinweise.
    Grundlegende Funktionen wie JSON-Parsing schienen ebenfalls nicht enthalten zu sein.
    Wenn man für eine Sprache, mit der man schnelle Skripte schreiben will, zuerst einen JSON- oder XML-Parser schreiben muss, ist die Aufgabe bereits gescheitert.
    Das war vor etwa vier Jahren, also könnte das Ökosystem inzwischen besser geworden sein, und vielleicht waren auch meine Maßstäbe für die Bewertung von Janet als Skriptsprache selbst falsch.
    Trotzdem macht mir dieser Beitrag Lust, es noch einmal zu installieren.

    • Dinge wie JSON und reguläre Ausdrücke wurden in das Modul spork ausgelagert, das in etwa die Rolle einer libc hat.
      Es gibt eine starke interne Tendenz, den Kern schlank zu halten.
      Da viele Projekte von spork abhängen, ist es wahrscheinlich schon früh installiert.
      Die Dokumentation ist ganz ordentlich, aber ich stimme zu, dass es bei praktischen Beispielen noch Lücken gibt.
      Diese Lücke schließt https://janetdocs.com teilweise; dort wird für jede Funktion auf „Community-Beispiele“ verlinkt.
  • Etwas abseits vom Thema: Ein anderer Blogbeitrag des Originalautors hat mich dazu gebracht, eine geteilte mechanische Tastatur zu verwenden.
    Ich hatte jahrelang Schulter- und Handgelenkschmerzen, und sie hat geholfen; ich empfehle dringend, sich auch Ians andere Beiträge anzusehen.

  • Die Entscheidung, jederzeit mit Esc die unten angeheftete eingebaute REPL zu öffnen, ist vielleicht keine gute.
    Browser haben bereits ein Standardkürzel für Esc, und Firefox verlässt beim Drücken von Esc den Vollbildmodus.