2 Punkte von GN⁺ 2023-12-07 | 1 Kommentare | Auf WhatsApp teilen
  • Jepsen ist ein Werkzeug zur Überprüfung von Nebenläufigkeitssystemen wie Datenbanken; daher waren auch das Nebenläufigkeitsmodell und die Unterstützung echter Threads wichtige Auswahlkriterien für die Implementierungssprache
  • Die unveränderlichen, persistenten Datenstrukturen von Clojure und die Nebenläufigkeitswerkzeuge der JVM verringern die Fehleranfälligkeit von Testcode und passen gut zu Java-basierten Datenbank-Clients
  • Die Arbeit an Jepsen ähnelt eher Experimentieren und Erkunden als festgelegter Produktentwicklung; Clojure-Funktionen wie REPL, Makros, Threading-Makros und EDN sind bei komplexer Datenverarbeitung von Vorteil
  • Die Performance liegt nicht an der Spitze, aber idiomatisches Clojure ist normalerweise höchstens um ein bis zwei Größenordnungen langsamer als Java; kritische Stellen lassen sich durch Optimierung und JVM-Profiling-Tools behandeln
  • Schwächen wie eine kleine Community, das Fehlen eines breit erfolgreichen statischen Typsystems, umständlicher Umgang mit Primitives und Fehlermeldungen gibt es zwar, für Jepsen, das von 1 bis 3 Personen gepflegt und genutzt wird, waren sie aber ein vertretbarer Kompromiss

Sprachkriterien für ein Tool zum Testen von Nebenläufigkeit

  • Jepsen wurde entwickelt, um Nebenläufigkeitssysteme zu testen; die Testziele sind meistens Datenbanken
  • Clojure erfüllt die grundlegenden Anforderungen beim Schreiben von Nebenläufigkeitstestcode gut
    • Unveränderliche, persistente Datenstrukturen senken die Fehleranfälligkeit von Code, der mit gemeinsamem Zustand umgeht
    • Echte Threads, Promises, Futures, Atoms, Locks, Queues, Cyclic Barriers, java.util.concurrent usw. lassen sich verwenden
    • Auch Sprachen mit strengerer Kontrolle von Seiteneffekten, etwa Haskell, wurden erwogen, doch Clojures weniger dogmatischer Ansatz passte besser zu Jepsen
  • Datenbanktests erfordern Verbindungen zu unterschiedlichen Clients
    • Fast jede Datenbank stellt in der Regel einen JVM-Client bereit, der in Java geschrieben ist
    • Clojure hat eine gute Java-Interoperabilität, wodurch sich solche Clients leicht nutzen lassen

Clojure-Funktionen, die Experimente und Datenerkundung begünstigen

  • Jepsen-Tests sind experimentelle Arbeit; dafür brauchte es eine Sprache, die knapp, leicht änderbar und gut für Prototyping geeignet ist
    • Clojures knappe Syntax und Makrosystem passen gut zu dieser Arbeitsweise
    • Threading-Makros machen verkettete Transformationen leichter lesbar
    • Makros erleichtern die Implementierung wiederverwendbarer Fehlerbehandlung und Ressourcen-Scope-Steuerung
    • Die Clojure-REPL ist nützlich, um Ergebnisdaten aus Testläufen ad hoc zu erkunden
  • Im Testprozess müssen komplexe und verschachtelte Datenstrukturen dargestellt, transformiert und geprüft werden
    • Clojures Datenstrukturen und Funktionen der Standardbibliothek sind dafür stark
    • Beim umfangreichen Ausgeben strukturierter Daten auf Konsole und in Dateien passt die EDN-Datensyntax gut

Kompromisse bei Performance und langfristiger Wartung

  • Jepsen ist kein sehr großes System, verarbeitet aber eine ordentliche Menge an Daten und braucht daher „ausreichend gute“ Performance
    • Clojure ist nicht die schnellste Sprache
    • Idiomatisches Clojure bleibt in der Regel innerhalb eines Performance-Unterschieds von ein bis zwei Größenordnungen gegenüber Java
    • Bei wichtigen Engpässen lässt sich der Abstand verringern
    • Die Profiling-Tools der JVM funktionieren gut mit Clojure
  • Jepsen ist ein rund 10 Jahre altes Projekt, daher waren ein ausgereifter Kern und Stabilität wichtig
    • Clojure ist sowohl hinsichtlich des JVM-Targets als auch der Sprache selbst stabil
    • Bibliotheken „verrotten“ nicht so schnell wie bei Scala oder Ruby

Clojure-Schwächen, die man in Kauf nehmen muss

  • Clojure hat Nachteile, die bei der Größe von Jepsen beherrschbar sind, für größere Teams aber zur Belastung werden können
    • Die Engineering-Community ist klein
    • Es gibt kein breit akzeptiertes und erfolgreiches statisches Typsystem
    • Da Jepsen jeweils nur von 1 bis 3 Personen gepflegt und genutzt wird, fällt diese Einschränkung weniger stark ins Gewicht
  • Beim Umgang mit JVM-Primitives kann es frustrierend sein, wenn man nicht auf Java ausweicht; tatsächlich wird gelegentlich Java verwendet
  • Teile des Polymorphiesystems sind unzureichend, lassen sich aber durch Bibliotheken umgehen, und auch die Fehlermeldungen sind schlecht
  • Jepsen wurde nach Prototypen in mehreren Sprachen letztlich in Clojure umgesetzt und bleibt auch 10 Jahre später ein ziemlich guter Kompromiss

1 Kommentare

 
GN⁺ 2023-12-07
Hacker-News-Kommentare
  • Aus der Perspektive von jemandem, der seit etwa 10 Jahren ein SaaS mit Clojure/ClojureScript betreibt, stimme ich Kyles Beitrag voll und ganz zu
    Zusätzlich sehr wertvoll war, den Großteil des Domain-Codes in cljc-Dateien zu halten, sodass er sowohl für Server als auch Client kompiliert werden kann; außerdem werden Transducer und Transducer-Pipelines in Bezug auf Performance, Komponierbarkeit und Wiederverwendbarkeit unterschätzt, und man merkt der Sprache an, dass sie von Rich Hickey entworfen wurde: Stabilität und langfristige Kompatibilität sind hervorragend
    Abwärtskompatibilität ist enorm wichtig, weil man sich so auf die Anwendung konzentrieren kann, statt ständig wechselnden Tools hinterherzulaufen, und ich glaube auch nicht, dass es Zufall ist, dass der durchschnittliche Clojure-Programmierer mehr als 12 Jahre Berufserfahrung hat und im oberen Vergütungsquartil liegt

    • Ähnliche Situation. Auch mein SaaS läuft auf Clojure, und im Vergleich zu anderen Sprachen ist die Wartung traumhaft einfach
      Es geht fast nie etwas kaputt, und Upgrades sind ebenfalls leicht. Dank HMR, REPL und cljc-Dateien ist auch die Developer Experience hervorragend, und Clojure-Code zu schreiben macht einfach Spaß
    • Wie groß ist deiner Ansicht nach der Anteil der Gesamtvorteile, der auf die JVM zurückgeht, und wie groß der Anteil, der aus der Clojure-Sprache selbst kommt?
    • Gibt es in Clojure brauchbare Web-Frameworks?
    • Wenn Abwärtskompatibilität so wichtig ist, frage ich mich, warum sie ausgerechnet bei C und C++ wie eine Ausnahme behandelt wird
      Einerseits heißt es, es sei in Ordnung, Sprachen und Systeme zu verbiegen, damit funktionierende Dinge nicht kaputtgehen; andererseits erwartet man ausgerechnet von den zwei Sprachen, die einen großen Teil real laufender Software tragen, dass sie mit ihrer glanzvollen Vergangenheit und Gegenwart brechen. Ich verstehe nicht, warum
  • Das größte Problem von Clojure ist ganz klar das Ökosystem
    Wenn man sich die Verteilung zugänglicher und brauchbarer Tools ansieht, liegt sie entweder ganz weit links bei schrecklichen, aber leicht zugänglichen Tools, oder ganz weit rechts bei Tools, deren README ein Herr-der-Ringe-Zitat enthält und in denen alles Daten bis zur n-ten Potenz ist und die nur Drachen beherrschen, die blind kopfüber hängend Emacs-Plugins schreiben können
    Die Sprache selbst ist großartig, und auch die Java-Interoperabilität ist viel besser, als Aphyr sagt, aber wenn Clojure etwas wie Rails oder Django, besser noch Phoenix, hätte, wäre es sehr viel leichter zu vermitteln und vermutlich viel weiter verbreitet
    Gerade wenn man ein Team von einer imperativen Sprache der Algol-Familie zu Lisp bewegen will, muss der Gewinn größer sein als die Mühe, aber im Moment muss man in fast jedem Projekt, abgesehen von Basiselementen wie HTTP-Routing, das Rad praktisch neu erfinden
    Trotzdem ist es ein riesiger Vorteil, dass man jedes Maven-Paket nutzen kann und zu einem jar kompiliert wird; wo ein jar läuft, läuft auch Clojure

    • Man sollte sich unbedingt Calva ansehen, ein hervorragendes Plugin für VSCode. Es bietet nicht nur einen REPL, sondern auch Funktionen wie Live-Dokumentation, macht Clojure leicht nutzbar und ich verwende es täglich bei der Arbeit
      https://calva.io
    • Es klingt nicht so, als hättest du schon einmal beruflich mit Clojure programmiert. Das Clojure-Ökosystem und die Community sind gut gepflegt
      Clojure gibt es in mehreren Formen; hauptsächlich werden Clojure und ClojureScript verwendet, dazu kommen Babashka, Scittle usw., aber alle leiten sich von clj oder cljs ab
      Entwicklungswerkzeuge unterscheiden sich je nach Plattform und IDE-Vorlieben, also gibt es für Emacs, Neovim, VSCode und IntelliJ jeweils andere Tools, und auch die Build-Systeme variieren je nach Bedarf
      Für clj ist deps.edn derzeit am weitesten verbreitet, gefolgt von leiningen, und für cljs gibt es neben shadow-cljs noch weitere Optionen
      Für Einsteiger kann das überwältigend sein, aber die Community ist gut und hilft immer. Ich habe in vielen Sprachen beruflich programmiert, aber Clojure gefällt mir mit Abstand am besten
    • Mich würden Beispiele für „schreckliche, aber leicht zugängliche“ Tools interessieren
      Ich benutze Clojure seit etwa 2013, aber mir fällt nichts in diese Kategorie ein. Die meisten beliebten Bibliotheken sind hervorragend und liegen bei Stabilität, Abwärtskompatibilität und Einfachheit weit vor den meisten Ökosystemen, die ich kenne
    • Das wirkt weniger wie etwas zu Jepsen oder zum eigentlichen Artikel und eher wie ein beliebiger Clojure-Kommentar
    • Für Leute, die sich mit Clojure nicht gut auskennen, noch als Zusatz: Wie /u/jwr in diesem Thread sagte, läuft Clojure dank ClojureScript auch überall dort, wo es einen Browser gibt
      Dank gemeinsam nutzbarer .cljc-Quelldateien für Clojure und ClojureScript kann derselbe Clojure-Code sowohl im Frontend als auch im Backend ausgeführt werden
      Wie Rich Hickey sagt, „erreicht“ es nicht nur die JVM, sondern auch JavaScript
      Ich nutze Emacs schon lange und kann ihn nach Wunsch konfigurieren oder bei Bedarf am Ende auch den nötigen elisp-Code schreiben, aber ich würde keineswegs behaupten, gut in elisp zu sein
      Dass es schwierig ist und sich nur schwer vermitteln lässt, wenn jemand ohne jede Lisp-Erfahrung gleichzeitig Emacs, elisp und Clojure lernen soll, räume ich ein
      Inzwischen gibt es aber den Clojure-LSP-Server, und er läuft nicht nur in Emacs, sondern auch in anderen IDEs; selbst wenn viele Clojure-Entwickler Emacs nutzen, ist Emacs für die Clojure-Entwicklung also keine Voraussetzung
  • Ich arbeite seit 7 Jahren ausschließlich mit Clojure und betreue aktiv eine Clojure- + ClojureScript-Codebasis mit über 500.000 Zeilen; mein größter Kritikpunkt ist das Fehlen eines soliden Typsystems
    Ich stimme zu, dass Clojure ausdrucksstark ist, schnelles Vorankommen ermöglicht und einem nicht im Weg steht, aber es lässt eben auch unsaubere Laufzeitfehler zu, die schwer zu reproduzieren und zu debuggen sind
    Hätte Clojure ein breit akzeptiertes und erfolgreiches statisches Typsystem, wäre es großartig. Im Moment würde ich sagen: Wenn man Ruby oder Python mag, aber etwas Stärkeres will, ist es ziemlich gut; inzwischen frage ich mich aber, ob Go nicht der richtigere Weg ist

    • Für Bereiche, in denen statische Typisierung nachweislich hilft, kann man auch andere JVM-Sprachen wie Kotlin in ein Clojure-Projekt integrieren
  • Ich stimme voll zu, dass Clojure(Script) fast schon ein Segen ist und für viele Projekte, ob klein oder groß, eine hervorragende Wahl darstellt.
    Nachdem ich C, Python, PowerShell, Java, Bash und SQL für Uni-Aufgaben, Systemadministration oder die Analyse von Traffic-Dumps jeweils ein wenig verwendet hatte, war Clojure die erste Sprache, in der ich professionell programmiert habe.
    Ich baue OrgPad mit Clojure+ClojureScript, und selbst bei über 100.000 Zeilen Code halte ich das für eine gute Entscheidung.
    Der Einstieg ist leicht, und schon nach etwas geschriebenem Code habe ich ein ziemlich hohes Vertrauen, dass er so funktioniert, wie ich es mir vorgestellt habe. In Python, PowerShell oder Bash war das nie in diesem Maß der Fall; das fühlt sich nach einer ganz anderen Liga an.
    Auch der REPL-Workflow ist wirklich großartig, und ein Kollege hat dazu ein passendes Video gemacht: https://www.youtube.com/watch?v=4igO7Qbyj9o
    Heutzutage kann man sogar Funktionen, kurze Tasks und kleine Projekte, bei denen man sonst überlegen würde, von Bash zu Python zu wechseln, mit Babashka/nbb erledigen.

  • Als ich früher versucht habe, ein paar tausend Zeilen in Clojure und ClojureScript zu schreiben, war das größte Problem, dass die meisten Tools ziemlich chaotische Fehlerzustände hatten.
    Python hat etwas Ähnliches an sich: Wenn man die meisten Python-Programme mit Ctrl+C abbricht, bekommt man einen Stacktrace mit unbekanntem Zeug dazwischen, aber gerade als Einsteiger war es schwer, damit weiterzukommen.
    Ich denke, in der Sprache und im Ökosystem stecken viele innovative und interessante Ideen. Es lohnt sich zumindest, die historischen Papers zu Clojure zu lesen und die meisten ihrer Lehren zu verinnerlichen.
    Das klingt für alle wahrscheinlich ketzerisch, aber ich glaube, es gibt eine kleine Nische im Ökosystem für eine Skriptsprache ohne Klammern, die Performance und Ergonomie beim Schreiben von Code genauso ernst nimmt wie Clojure.
    Ich könnte auch gut auf die Konvention verzichten, nil speziell zu behandeln, aber immerhin gibt es dafür ein gewisses Fundament.
    Ich weiß, dass (f x y) besser ist als f(x, y), aber mein eigentliches Problem liegt eher bei Fällen, in denen let-Formen Einrückung erzeugen. Nur um Werten Namen zu geben, sollte man nicht gleichzeitig den Preis von Einrückung und Klammern zahlen müssen.
    Wenn man aus einer Sprache wie Python kommt, in der Einrückung ohnehin im Code steckt und dann als Information verwendet wird, wirken solche Dinge manchmal einfach wie Rauschen.

    • Dass let-Formen Einrückung erzeugen, ist eher ein Zeichen dafür, dass man let zu oft benutzt.
      In einem funktionalen Stil muss man Zwischenargumenten, die zwischen Funktionen weitergereicht werden, nicht oft Namen geben.
      Normalerweise reicht man Argumente implizit mit den Threading-Makros -> und ->> an die nächste Funktion weiter oder definiert die Transformation selbst als pure Funktion und legt sie auf die oberste Ebene.
      Ich verstehe aber, dass man in manchem Interop-Code viel let braucht, vor allem bei Java-JWT-Bibliotheken, die in prozeduralen Ketten Argumente verändern.
    • Wenn man in Clojure oder Python den REPL-Workflow verwendet, lernt man manches durch Fehler.
      Man debuggt eine ganze Weile und merkt dann, dass man nicht neu geladen oder reinitialisiert hat.
      Für mich landet das meistens einfach auf der Prüfliste für Situationen, in denen ich denke: „Das kann doch nicht sein.“ Zum Beispiel: „Ich füge mal Debug-Ausgaben ein, um zu prüfen, ob meine Codeänderung tatsächlich aufgerufen wird.“
      Natürlich ist das nur ein Sicherheitsnetz, und meistens versucht man, solche Situationen durch andere REPL-Gewohnheiten zu vermeiden.
    • Mein Gehirn leidet, weil es so wirkt, als müsste man es (+ clojure clojurescript) lesen.
  • Clojure macht vieles richtig, und deshalb mag ich es sehr.
    Wenn echte Teams echte Webarbeit mit Clojure bauen, ist eine Sache, die sie verlangsamt, meiner Meinung nach der fast schon dogmatische Drang, alles zusammenzukleben, indem man unzählige Bibliotheken kombiniert, die jeweils ihren ganz eigenen Ansatz haben.
    Ich glaube, Clojure wäre viel beliebter und angenehmer zu verwenden, wenn die Community zusätzlich zum bisherigen Ansatz auch ein aktiv gepflegtes, batteries-included und allgemein brauchbares Web-Framework hätte. Ich frage mich, ob Biff diese Rolle erfüllt.
    Es wäre gut, wenn es auch für Leute einen alternativen Weg gäbe, die die Sprache mögen, aber nicht selbst ein Monster zusammensetzen wollen.
    Vielleicht liegt das auch daran, dass ich von Ruby on Rails verwöhnt bin.

    • Für viele Leute liegt der Reiz von Clojure gerade darin, Dinge nicht unnötig zu verkoppeln.
      Das ist der Ansatz aus dem berühmten Vortrag von Rich Hickey: nicht complecten, sondern komponieren: (https://github.com/matthiasn/talk-transcripts/blob/master/Hi...)
    • Biff kommt einem batteries-included Ansatz sehr nahe, aber einige Voreinstellungen weichen etwas vom Mainstream ab. Statt SQL verwendet es XTDB und HTMX/Hyperscript, was für Neulinge immer noch schwierig sein kann.
      Clojure, eine Graphdatenbank und je nach Fall auch noch HTMX zu lernen, ist ziemlich viel. Trotzdem ist bereits viel Konfiguration vorhanden, die Authentifizierung ist durchdacht und einfach, und die Server-Konfigurationsdateien sind gut kommentiert.
      Es gibt auch Deployment-Skripte, die einen Linux-Server einrichten und per SSH in einen Produktions-REPL gehen. Wenn man XTDB verwenden möchte, ist Biffs Ansatz für die Dokumentvalidierung wirklich gut.
      Persönlich mag ich das mehr als Apps, die mit ClojureScript laufen. Es gibt viele ClojureScript-Wrapper um React, und das ist fast schon ein Meme geworden, aber als React-Entwickler hatte ich bei keinem davon das Gefühl, dass er einfacher wäre als React selbst.
      Eher im Gegenteil: Es wirkt komplex und liegt mir nicht gut in der Hand. HTMX/Hyperscript hingegen passt sehr gut zu Clojure, weil HTML-Syntax dort nur Arrays und Objekte sind, mit denen sich leicht arbeiten lässt.
      Zum ersten Mal fühlte sich das Clojure-Mantra „Code ist Daten“ wirklich real an.
    • Wie oben schon geschrieben, lohnt es sich, Luminus oder Kit anzuschauen.
    • Von den Dingen, die ich ausprobiert habe, gefällt mir Biff am besten.
  • Früher habe ich mehrmals versucht, ein wenig OCaml zu benutzen, aber das übermäßig strenge Typsystem hat mir nicht gefallen.
    Ich hatte das Gefühl, mehr Zeit darauf zu verwenden, den Compiler zufriedenzustellen, als Code zu schreiben. In Clojure, Common Lisp und C hat man mehr Freiheit, den Compiler oder das Typsystem in die gewünschte Richtung zu biegen.
    Natürlich gibt es Vor- und Nachteile, aber ich möchte beim Schreiben von Code nicht gestört werden. Vielleicht ist das nur mein Stil, aber ich habe viele Menschen mit derselben Ansicht getroffen.
    Ich glaube, statische Typsysteme sind eine Geschmacksfrage, und das andere Lager sieht das anders. Trotzdem ist es gut, wenn es gegensätzliche Lager gibt, weil man viel voneinander lernen kann.
    Rich Hickey hat mehrfach gesagt, dass Clojure eine Host-Sprache ist und es deshalb in Ordnung ist, bei Bedarf auf Java oder JavaScript herunterzugehen.
    Ich persönlich halte das für eines der stärksten Merkmale des Clojure-Ökosystems. Es ist einfach deutlich pragmatischer.
    Ich habe oft Versuche gesehen, immer wieder dasselbe in einer Sprache neu zu implementieren, die man mag, nur weil man „diese schmutzige Bibliothek aus einer anderen Sprache“ nicht anfassen will. Die Begründungen reichen von langsam über unsicher bis unflexibel.
    So etwas gab es oft in Common Lisp und in der Rust-Community, und es gibt es bis heute.

    • Typprüfung ist tatsächlich eine Geschmacksfrage. Ich persönlich mag es ziemlich, wenn die Sprache triviale Fehler verhindert, deshalb füge ich in Common-Lisp-Code viele Typdeklarationen ein.
      SBCL hilft dabei, diese Deklarationen so gut wie möglich zu garantieren, und hat mir pro Projekt vermutlich einige Minuten Kopfschmerzen erspart.
      Und CL ist sehr pragmatisch; zum Beispiel zuckt niemand mit der Wimper, weil woo auf einer C-Bibliothek basiert.
    • Als ich in Big Tech ein High-Reliability-Team leitete, wollte ich am liebsten schon gestern überall strenge statische Typen haben.
      Alle Produktionsprobleme hingen mit kleinen, subtilen Themen zusammen. Etwa wenn sich durch ein Runtime-Upgrade die Reihenfolge von JSON-Keys änderte und ein alter Client kaputtging, der JSON manuell auseinandergenommen hat, oder wenn eine Bibliothek tief im Stack begann, HTTP-Codes als Integer statt als String zurückzugeben und dadurch das Fehler-Parsing zerbrach.
      Bei unserer Betriebsgröße führten schon Auswirkungen auf einen kleinen Prozentsatz der Kundschaft zu Hunderten Problemberichten, daher war jeder Ausfall eine große Sache.
      Jetzt arbeite ich in einem kleinen Startup, und dort ist alles völlig anders. Wegen der Art der Arbeit und der verfügbaren Ressourcen haben wir uns für eine statische Sprache entschieden, aber ich vermisse die Zeit, in der ich mit dynamischen Sprachen gearbeitet habe.
      Weil wir schnell releasen, leidet die Codequalität wirklich. Aus Zeitgründen kämpft man eher mit dem Typsystem, statt sauber zu refaktorieren, und kopiert mehrere leicht unterschiedliche Versionen derselben Objektstruktur an verschiedene Stellen.
      Weil die Typformen das Generalisieren schwierig machen, trennt man Funktionalität nicht ab und referenziert sie an mehreren Stellen, sondern kopiert dieselbe Logik zehnmal per Copy-and-paste.
      Ich denke, je nach Problembereich ist eine andere Lösung richtig. Wenn man wegen subtiler Bugs mitten in der Nacht angerufen wird, sind strenge statische Typen wahrscheinlich die richtige Wahl.
      Wenn man schnell iterieren muss und sich Probleme mit einer E-Mail oder einer Slack-Nachricht lösen lassen, können dynamische Typen besser sein.
      Der Trick ist, im dynamischen Paradigma nicht zu viele Altlasten aufzubauen, falls man später wächst und zu einem statischen Paradigma wechseln muss.
      Sprachen mit vielen leidenschaftlichen Fans scheinen leider leicht in die Haltung abzurutschen: „Ich will keine Bibliotheken aus anderen Sprachen benutzen.“
  • Clojure ist mit Abstand meine Lieblingssprache und fühlt sich für mich ganz natürlich an.
    Zwei Dinge aus anderen Sprachen vermisse ich allerdings wirklich: verständliche Fehlermeldungen und Type Hints.
    Ich musste in der Firma großen Code refaktorieren, und das war schmerzhaft. Es ist schwer zu wissen, welche Funktion eine Exception wirft und welche einfach nil zurückgibt, und ebenso schwer, ob eine zentrale Funktion einen Vektor, eine Sequenz oder irgendeine andere Collection zurückliefert.
    Es gibt Projekte wie spec, malli und typed clojure, die das lösen wollen, aber sie fühlten sich für mich nicht wie ein Ersatz an, der an Typen in Python oder TypeScript herankommt.

    • Vielleicht liegt es daran, dass ich mich an moderne Sprachen mit solchen Funktionen gewöhnt habe, oder daran, dass Sprachen ohne diese Funktionen sie nachträglich ergänzen, wie bei Python oder TypeScript, aber ich frage mich, wie man das aushält.
      Eine Sprache, die einem nicht sagen kann, was in eine Funktion hineingeht und was herauskommt, wirkt in einer Codebasis von mehr als ein paar Dateien fast wertlos.
      Zu versuchen, aus dem abzuleiten, was der aktuelle Code scheinbar mit einem Objekt machen kann, welchen Typ es wohl hat, ist freiwillige Selbstquälerei.
  • Wenn du Clojure zum ersten Mal anschaust, lohnt sich dieses interaktive Tutorial: https://tryclojure.org

  • Clojure macht Spaß.

    • Das wird unterschätzt. Es klingt vielleicht nicht professionell, aber Spaß ist auch der Grund, warum Basecamp und Ruby on Rails in Ruby geschrieben wurden.
      Rails dominierte die Webentwicklung der 2010er Jahre, und viele enorm erfolgreiche Startups wurden darauf aufgebaut.
      Viele verspotten Ingenieure dafür, dass sie „mit Spielzeug spielen“, aber ein beträchtlicher Teil der guten Dinge, die wir heute haben, war irgendwann einmal Spielzeug. Linux ist ebenfalls ein gutes Beispiel.
    • Das trifft dieses Gefühl perfekt. Ich habe früher sogar einmal über dieses Gefühl geschrieben [1].
      Das Tückische an sehr „spaßigen“ Sprachen ist, dass man anfängt anzunehmen, man könne alles mit dieser Sprache lösen.
      Am Ende schreibt man sehr viel Code, und später merkt man vielleicht, dass auch eine Lösung ohne zusätzlichen Code vollkommen ausreichend gewesen wäre.
      [1] https://franz.hamburg/writing/clojure-makes-happy.html