Ich lerne seit einigen Wochen Clojure und vor kurzem habe ich angefangen Open Source Code zu lesen: Clojure und Clojurescript Compiler und einige Bibliotheken wie om, boot, figwheel.
Ich habe bemerkt, dass einige Clojure-Dateien sehr lang sind, einige von ihnen mehr als tausend LOC. Da der clojure-Code sehr knapp und wenig zeremoniell ist, bedeutet dieser Code viel mehr Code als eine Datei, die in anderen Sprachen so groß ist.
Wenn Sie von einem OO-Hintergrund kommen, wo Sie normalerweise eine Klasse pro Datei haben und Sie versuchen, Ihre Klassen kurz zu halten (SRP), fand ich das ein bisschen komisch.
Ich weiß, dass clojure code hauptsächlich aus reinen Funktionen besteht, und sie sind viel einfacher zu verstehen als irgendeine veränderbare Klasse, in der Sie den aktuellen Zustand im Hinterkopf behalten müssen, und ich finde, dass ich die meisten lesen und verstehen kann funktioniert einzeln. Aber die meisten dieser Funktionen sind sehr gut gestaltet, so dass sie nicht voneinander abhängen: Obwohl Sie (filter odd?)
verwenden können, bedeutet dies nicht, dass filter
und odd?
verwandt sind. Aber für "jeden Tag" -Code (LOB-Apps, Web-Apps, etc.) ist es sehr schwer, die Funktionen so eigenständig zu halten wie diese (zumindest ist das meine Erfahrung mit der OO-Programmierung).
Ich habe auch einige Demos von Clojurescript-Anwendungen (om, Reagenz usw.) gesehen, in denen sie alle Komponenten in derselben Datei deklarieren. Ich weiß nicht, ob das so ist, weil es nur eine Demo ist und in einer realen Anwendung ein product.clj
und ein category.clj
oder das ist nur der Clojure Weg: eine Datei pro Namespace / Modul / bounded-context zu haben .
Ich denke, wenn ich einen Ordner öffne und ich product.clj
, category.clj
, order.clj
usw. sehe, kann ich auf einen Blick sehen, worum es in diesem Ordner geht, besser als nur eine components.clj
oder% Code%.
Meine Fragen sind also:
1: Ich habe mir das ziemlich große non-library clojure-Projekt angesehen, an dem ich gerade arbeite, und habe das ausgeführt:
%Vor%und öffne ein repl und rannte
%Vor%Ich sehe, dass bei einem Projekt mit 17k LOC unsere durchschnittliche clojure Datei 200 Zeilen enthält . Ich habe einen mit 1k LOC gefunden.
2: Ja, ich werde anfangen, diese lange zu brechen, sobald ich Freizeit habe. einige sehr lange wie clojure.core sind sehr lang, weil clojure nur einen Durchlauf hat und selbst bootstrapen muss. Sie müssen beispielsweise die Möglichkeit schaffen, viele Namespaces zu haben, bevor sie dies tun können. Für andere ausgefallene Bibliotheken kann es gut sein, dass sie einen anderen Designgrund für eine große Datei hatten, obwohl es in der Regel ein Fall von "Pull Request welcome" ist.
3: Ich arbeite in einem großen Team mit ein paar großen Dateien, wir bearbeiten Zusammenführungskonflikte mit Git, obwohl, weil Änderungen dazu neigen, innerhalb einer Funktion zu sein, kommen diese für mich viel seltener vor als in anderen Sprachen. Ich finde, das ist einfach kein Problem.
Sie neigen dazu, lange zu werden, wenn Sie sie entwickeln. Angenommen, Sie benötigen eine Funktion foo, um Prozeduren [ab ...] auf Datenstruktur K auszuführen. Sie definieren zuerst die Signatur der Funktion und setzen dann Hilfsfunktionen ab ... fort, da sie wahrscheinlich alle reine Funktionen und die Funktionalität sind Sie brauchen von foo ist komplex der Namensraum neigt dazu, lang zu werden.
Manchmal, aber das repl ist ein wirklich nützliches Werkzeug, um die Hauptfunktionalität einer neuen Bibliothek zu verstehen. Ich benutze oft clojure.repl / source für die Funktion und arbeite mich rückwärts in die Hilfsfunktionen. Ich finde, dass eine Menge Zeit Clojure-Bibliotheken Dokumentation ist entweder kryptisch oder nicht existent, aber wie viele in der Gemeinschaft gerne sagen, Clojure Funktionen 'Quelle ist selbst dokumentieren.
Ich habe keine Erfahrung in einem großen Team zu arbeiten, aber Arthur Ulfeldt hat recht, dass die meisten Änderungen in einer einzigen Funktion passieren, ich erfahre es aus dem Lesen der Diffs von Pull-Anfragen mit Githubs Blame-Funktion.
Zusätzlich zu den Antworten, die andere gegeben haben, sind hier zwei weitere.
Es kann sein, dass einige Dateien lang sind, da es in Clojure am einfachsten ist, eine Datei pro Namespace zu verwenden. Wenn Sie alle diese Definitionen im selben Namespace haben möchten, ist es einfacher, sie in eine Datei zu schreiben. Ein Grund dafür, dass sich Definitionen im selben Namespace befinden sollten, finden Sie in # 2.
Der Clojure-Compiler erlaubt bestimmte Arten zyklischer Abhängigkeiten zwischen Namespaces nicht (andere zyklische Abhängigkeiten zwischen Namespaces sind in Ordnung). Eine Möglichkeit, eine illegale zyklische Abhängigkeit zu vermeiden, besteht darin, die interdependenten Definitionen in denselben Namensraum zu stellen. Wenn Sie das tun, kann es sinnvoll sein, andere Definitionen, die zu den problematischen gehören, auch in den einzelnen Namensraum zu ziehen. Für den Rest dieser Antwort siehe # 1.
(Mein eigener Geschmack ist für mehrere kleinere Dateien, obwohl nicht so klein wie viele Java-Klassen-Dateien. Auch: Code ist normalerweise nicht so selbst-Dokumentieren, wie der Autor denkt. Dies kann sogar halten, wenn der Autor und die Person die Code später sind die gleichen Personen.)