1. Why Clojure(Script)?
    1. Nate Wildermuth: ClojureScript and the Blub Paradox
  2. REPL-driven development
    1. Avoiding inconsistent state
      1. A. Unloading of changed namespaces
      2. B. Careful coding practices and tests
    2. Startup time
  3. Style and best practices
    1. Core
  4. Various
    1. Calling Clojure from Java
  5. Resources
    1. Community
    2. Learning
    3. Lib catalog
    4. Libs
      1. Convenience libraries - the missing “features” of clojure.core etc.
      2. Web
      3. Other libs
        1. Testing
        2. Data
    5. Development in general
    6. From Clojure to Java
  6. ClojureScript

Clojure-related resources and notes.

New to Clojure? Check Clojure for beginners first!

Content:

Why Clojure(Script)?

Clojure(Script) is simpler yet more expressive (than Java(Script)) - paraphrase of David Nolan in ClojureScript Next

Clojure (and thus ClojureScript) is one of the best designed programming languages, it is really well thought-through and great care is taken to ensure that the pieces do each a different thing yet fit perfectly together. It has been designed after years of painful experiences with production systems in Java, C++, Common Lisp and others to avoid the main sources of complexity and maintenance headaches. (For details see the Clojure Rationale and talks by Rich Hickey such as Effective Programs - 10 Years of Clojure.) It is also pragmatic, focused on getting stuff done, and it enables productive development thanks to tight feedback loops and powerful constructs. Its strength is data processing and thus it shines most in web services and applications, data analysis and processing pipelines, and similar.

Clojure enables interactive programming - you can connect a REPL to your application and develop it and interact with it from code while it is running. You cannot imagine the power and the insanely short feedback loop until you experience it. See the short screencast Interactive programming Flappy Bird in ClojureScript for an idea. Other languages also have REPL but Clojure was designed for evolving running applications in the REPL while managing state through these changes.

It has performant immutable data structures that make many concurrency-related defects impossible.

It has a powerful library of data transformation functions that can be effectively combined together.

When necessary, you can use macros to remove duplication and fit the language to your problem.

No matter whether you use Clojure core or a library, they use the ±4 generic Clojure data structures - that you can access and transform through the core functions you know and love. No more learning a custom API for every library! (Though you still need to learn and understand its data.)

It has also core.async for asynchronous/reactive programming,  clojure.spec to document, verify, use and test your data, and much more.

Clojure has also an active and friendly community. You always get help in the official Slack organization, one of the mailing lists, and other places.

Nate Wildermuth: ClojureScript and the Blub Paradox

(highlights and [insertions] mine)

That makes the important advantages of ClojureScript hard to perceive, as the essential difference [from JS] belongs in new patterns of problem solving rather than new syntax and grammar.

ClojureScript does the opposite. Instead of seeking to avoid the danger of using one bug-prone function, it provides three types of switch statements, each suited to different kinds of control flow. These options not only allow one to engage in high-level forms of abstraction, but actually encourage this kind of thinking. Moreover, the entire pattern of thought begins at a much higher level, seeking to recognize patterns even before fully understanding the solution. [The same applies for Clojure and Concurrency, having cca 4 ways to manage state instead of Java’s one -makes you think about what/why/how, which is a Good Thing ™]

ClojureScript, like JavaScript, doesn’t come with pattern matching. This would be a problem, except that ClojureScript comes with something better: macros.

Some languages run close to the “metal” — […]. Other languages take the opposite approach, running close to the “human metal” — our minds. The closer that a language can express (or in the case of macros, be modified to express) human thoughts, the closer we get to a program that we can understand natively. We no longer need to change our thoughts to fit the language. Instead, we change our language to fit the thoughts.

REPL-driven development

See the official REPL development guide and Eric Normand’s Repl-Driven Development in Clojure video course.

Avoiding inconsistent state

While changing things, you can end up with old state/vars still being available though they are not in the code anymore. So you can f.ex. call a function that doesn’t exist anymore. Restarting REPL to clear the environment isn’t a good solution because it takes time. Alternatives:

A. Unloading of changed namespaces

See Reloading Woes (2/2018). You can use clojure.tools.namespace, namely its unload to completely forget everything about a namespace - though this will also reset all your state, if any, despite defonce.

B. Careful coding practices and tests

Clojure’s iterative code evaluation has its limits. https://github.com/aredington/clojure-repl-sufficient-p has examples where simply re-evaluating a changed piece of code does not work (protocols, multi-methods etc.) - though there are workarounds for at least some of those described below.

You can employ a few tricks (such as preceding each (defmulti multi-fn ..) with (def multi-fn nil)) and detect stale code / wrong order by continually running your code outside of the REPL, f.ex. by creating an (initially) empty test for each namespace and have a runner run it - thus loading your code - upon each change. Sean Corfield described this approach in 4/2019:

FWIW, I’ve never needed any sort of “refresh all” in my workflow. I have a REPL running with all the dependencies of our monorepo across a dozen or so subprojects, and it runs for days and days and days. I probably restart it once a week at most…

[…]

Yes, we use Component very heavily. No, we don’t use its reset function.

No, I don’t run into problems with multimethods: you can use (def multi-fn nil) to remove a multimethod definition so it can be predictably redefined (putting that above your defmulti should be enough).

No, I don’t run into problems with ordering in namespaces. I suspect that’s a combination of 8+ years of Clojure experience, being careful to check for first use of functions when I do move things around, and never typing directly into the REPL (I always eval code from a source file, so I use “Rich Comment Forms” for non-production/exploratory code in my source files).

Also, we have a stub test namespace for every single source file so when we run clj -A:test:runner we get a failure if there’s an ordering problem – and we run our automated tests a lot, locally! We have a script that generates a stub test namespace for any source file that doesn’t already have one: it requires the source namespace and refers all symbols as a baseline for “can this source file be loaded” successfully.

Perhaps another aspect of my workflow that helps with all this: whenever I change any code at all, I always eval the top-level form that it’s in – so the REPL always has the up-to-date version of my code. That’s just habit, but it’s also part of a good REPL-Driven Development workflow: make small changes and always test every change in the REPL as you go. That means that instead of making a slew of changes across multiple namespaces and hoping you got it all correct, you work from the bottom up, testing each changed file as you go.

There are also a few built-in tools you can use to clean up some state:

  • ns-unmap - “Removes the mappings for the symbol from the namespace.”

  • remove-ns - “Removes the namespace named by the symbol. Use with caution.” A “nuclear” option that I use sometimes. You might be unable to require it again with the same alias unless you remove-ns (and reload) also the current, requiring ns.

Startup time

Style and best practices

Core

  • Threading do’s and don’ts: use → and →> only for navigation or transformation; prefer to keep the same type (but the last transf.) - break if necessary; avoid anonymous functions to change order type - likely doing too much already (if really necessary, use as→ which is intended to be used exactly & only inside →).

Various

Calling Clojure from Java

See this great discussion of Java → Clojure interop(erability) (don’t get confused by the title of it being in the opposite direction). From Alex Miller:

You have several options:

  1. Use the Clojure Java API to invoke the Clojure runtime - here you’re leveraging the Clojure runtime’s Java impl core to call into Clojure (Stu’s example)

  2. Use protocols, records, and/or genclass to actually produce Java classes

  3. Define your interface as a set of Java interfaces. Implement this interface in Clojure. You will need a small amount of glue code to provide the API impl (some kind of a factory to give you the impl of the Java interface - either written in Java or using #1). (example code)

#1 is straightforward but tedious - it’s really only worthwhile if you have a small amount of this code and hide the use of it. #2 has significant downsides - needing to compile everything, all methods are just > going to take/return Java Objects, no javadoc on apis, etc. #3 has advantages in all those areas. You write your Java interface where you can best write it … in Java (with Javadoc, and Java interfaces, and all the niceties Java users want). IDEs can autocomplete on the Java interfaces. You don’t have to AOT - factories can reify or load protocol instances as needed as they return objects. You can even reload internal vars with a connected REPL without restarting the app.

Side-note on AOT:

[Didier:] When you go with Option #2, you do not have to AOT everything, but AOT is transitive. So as you AOT the gen class, all code it requires and all code they in turn require will also be AOT. [..] [Alex Miller:] With AOT, you generally shouldn’t ever exclude part of the AOT’ed code. Most problems with AOT’ed code stem from having AOT’ed code call into non-AOT’ed code, so anything “downstream” should also be AOT’ed. [Sean Corfiled:] The approach I’ve taken around :gen-class has been to ensure that the namespace offering the Java class via :gen-class has no static dependencies at all – instead it requires/resolves any other namespaces/symbols it needs at run time. That way AOT creates the .class you need but doesn’t spread to anything else. This is even easier in Clojure 1.10 with the addition of requiring-resolve.

Resources

Community

Learning

Lib catalog

Libs

Convenience libraries - the missing “features” of clojure.core etc.

  • ztellman / potemkin - “a collection of facades and workarounds for things that are more difficult than they should be” - f.ex. import-vars so that we can expose a single namespace with everything to users while having the code split in multiple files, def-map-type so that we only need to implement the 4 essential functions, def-derived-map - as a view on another object, f.ex. JavaBean, definterface+ - same syntax as defprotocol but creating an interface with its memory/performance benefits ⇒ easy to switch, fast-memoize and more

  • cloojure/tupelo (and cloojure/tupelo-datomic) - convenience features “missing” from clojure.core - e.g. the awesome (spy[x[x]]) for logging the expression [+type] going through a threading macro or a fn, …)

  • marick/suchwow - Functions and behaviors not present in Clojure core. Support for creating and using your own “favorite functions” namespace. Better docstrings for clojure.core functions. More expansive versions of clojure.core functions.

  • plumatic/plumbing - Prismatic’s Clojure(Script) utility belt (including Graph - a simple and declarative way to specify a structured computation)

  • weavejester/medley - A lightweight library of useful Clojure(Script) functions (a tighter focus than useful and plumbing, and limits itself to a small set of general-purpose functions.)

  • flatland/useful

  • parallelism:

    • claypoole - variants of future/pmap/for backed by configurable threadpool(s) (Clojure uses a fixed-size threadpool shared by all, core.async is an overkill, reducers are not configurable)

    • tesser - “Clojure reducers, but for parallel execution: locally and on distributed systems [hadoop].” Also has parallelized math/statistical aggregations.

Web

Other libs

Testing
  • juxt iota - simplify running multiple checks on a (complex) data structure

  • specmonstah - use the power of clojure.spec to set up unit test fixtures, generating and manipulating deeply-nested, hierarchical graphs of business data

Data
  • Typed Clojure

  • Prismatic Schema

  • structural-typing - runtime data checks similar to Schema, inspired by Elm. ‘Tailored to “flow-style” programming, where complex structures flow through a series of functions, each of which makes a smallish change.’ Highlights: (1) Extra keys are to be preserved but not otherwise meddled with. (2) We want to check more then types (e.g. is a num in a range?)

  • Balagan, Clojure (Script) data transformation and querying library ClojureWerkz - this is something I’ve been looking for in quite a while. Ex.:

    (b/select {:a {:b {:c 1}} ..} [:a :* :c] (fn [val path] ...))
  • DataScript - Immutable database and Datalog query engine for Clojure, ClojureScript and JS

  • Specter (Clj(s))- queries and transformations on complex/nested data structures made extremely concise and elegant; high-quality, high-performance, top-notch!

  • Meanderε - a Clojure/ClojureScript library that empowers you to write transparent data transformation code that allows you to plainly see the input and output of these transformations

  • Use Datomic’s Datalog to query data structures

  • tupelo.forest - searching & manipulating tree-like data structures (examples)

Interop

  • bean-dip - Bidirectional translation between Clojure maps and Java beans that’s declarative and reflection-free (contrary to clojure.core/bean, java.data, gavagi - see the README for a comparison)

  • deeto - A Java dynamic proxy factory for interface-typed data transfer objects

  • proxy+ - faster, more convenient replacement for proxy that supports multi-arity methods better

Domain-specific

  • clash - Clojure Data Analysis Shell - A clojure project for quick interactive analysis of structured text files (ex: logs, csv, etc.), within the REPL. Define a representative structure with matching regular expressions for the text, then load the file into memory. This is useful for identifying trends and gaining insight from smaller datasets (~ millions of rows), before starting a time consuming Hadoop or Spark job. Pivot, frequency, and count/collect functions have flags for single/multi threaded executions.

Development in general

Essential

Visual REPL

ClojureScript

  • Chestnut (10/2014) - A Leiningen template for a Clojure/ClojureScript app based on Om, featuring a great dev setup, and easy deployment. Highlight: well-functioning browser-connected REPL, see a demo by D. Nolen who labels it “one of the coolest bits of ClojureScript tech I’ve encountered in a very long time.” The REPL is “always ready to go even if you kill the web server, refresh the web page, or have a JS exception on the page.” and there is live reload upon file change without corrupting the app state.

  • lein-figwheel - Figwheel builds your ClojureScript code and hots loads it into the browser as you are coding - live code and CSS reloading

  • weasel - WebSocket-connected REPL environment for ClojureScript - especially useful if the standard REPL doesn’t work because the page does not allow for iframes and/or does not use http://

  • clj-devtools - Better presentation of ClojureScript values in Chrome DevTools

Debugging and troubleshooting

  • philoskim/debux - A trace-based debugging library for Clojure(Script) - key being the dbg macro that returns it body’s result unchanged, while also pretty-printing the form and its value(s) into the REPL / browser Console. Special handling of let and threading macros, which prints every sub-form. There is also dbgn, which prints similarly every nested form and its result and dbgt for transducers. You can also use the tagged literals #d/dbg etc. instead of calling the macros.

  • clojure/tools.trace - trace calls, f.ex. run (trace-ns my.ns) to print call with params and return value of each function

  • Schmetterling - Debug running clojure processes from the browser! - upon an exception, the process will pause and S. will show the stack, which you can navigate and see locals and run code in the context of any stack frame; you can also trigger it from your code. It can be used nicely also in pre/post-conditions.

  • miracle.save - automatically save arguments and return values of selected functions / all in a ns.

  • scope-capture - help you save and restore the local environment of a piece of code with minimal effort. (Wrap an expression in spy to save, fns to restore into defs or a let; brk-point to pause the execution.)

  • postmortem - A tiny value-oriented debugging tool for Clojure(Script), powered by transducers

  • hashtag - (ab)use data readers to make it easier to get debugging data - define a tag: (defhashtag pp pprint) and use it in code (let [.. bob #pp (person :bob) ..]); when run will pprint {:result "Bob", :form (person :bob)}

Lein

  • lein-ancient - analyzes your project.clj and lets you know which dependencies are out of date.

  • lein-try - start a REPL with various dependencies without needing a project. Great for exploring new libraries!

  • Eastwood - a lint tool for Clojure.

  • lein-shorthand - a plugin to make useful functions (such as pprint, source) accessible in any namespace by copying them into a new namespace . so you can invoke (./pprint …).

From Clojure to Java

  • UncleJim (“Unmodifiable Collections for Java™ Immutability”)  is a very interesting looking library, with these main features:

    • Type-safe versions of Clojure’s immutable collections, implementing the generic java.util collection interfaces.

    • A simplified immutable alternative to Java 8 Streams, wrapping checked exceptions and avoiding primitives.

    • A tiny, type-safe data definition language of brief helper functions: vec(), set(), map(), and tup(), (like Clojure’s vector [], set #\{}, and map \{}).

    • Extend Tuples to make your own immutable Java classes (with correct equals(), hashCode(), and toString() implementations) almost as easily as writing case classes in Scala.

ClojureScript

Cljs: 23kB

(-> (dom/getElement "app")
(dom/setTextContent (join ", " ["Hello" "World\!"])))

jQuery: 29kB (+ 45kB Immutable.js)

$("#app").text(["Hello", "World"\.join(", "));

Source: [SeatleJS - ClojureScript for Skeptics by @derekslager](https://drive.google.com/file/d/0B8PcNdmU12GXVmdYeHNFU2hYc28/view)


Copyright © 2024 Jakub Holý
Powered by Cryogen
Theme by KingMob