September 1st, 2024

Clojure Interactive Development 101

The article emphasizes interactive development in Clojure using REPL for efficient coding, structural editing for code boundaries, and tools like "snitch" and "clj-reload" to enhance debugging and workflow.

Read original articleLink Icon
Clojure Interactive Development 101

The article discusses the concept of interactive development in Clojure, emphasizing the use of REPL (Read-Eval-Print Loop) for efficient coding practices. It highlights that developers rarely need to type directly into the REPL, instead using commands from their source files to evaluate expressions. The author explains the significance of structural editing in Lisp languages, which allows editors to easily identify code boundaries using parentheses. The piece outlines practical techniques for driving the REPL, such as evaluating the last expression or the entire function, which facilitates debugging without restarting applications or using external tools like Postman. The author also introduces additional tools like "snitch" and "clj-reload" that enhance the debugging process by allowing variable instrumentation and namespace management. The article concludes by encouraging developers to embrace interactive development to streamline their coding workflow and reduce reliance on traditional edit-compile-restart cycles.

- Interactive development in Clojure minimizes direct REPL input, focusing on evaluating expressions from source files.

- Structural editing in Lisp languages simplifies code manipulation by using parentheses to define boundaries.

- Techniques like evaluating the last expression or entire functions aid in debugging without restarting applications.

- Tools like "snitch" and "clj-reload" enhance debugging by allowing variable tracking and namespace cleanup.

- Embracing interactive development can improve coding efficiency and reduce reliance on traditional development cycles.

Link Icon 2 comments
By @dmichulke - 7 months
I'd love to use all this but the fact that you have to substitute in variables just makes this very not-useful.

Ideally in functional programming everything is a (pure) function (and this is how I program), so you never have your variables defined.

Instead, my standard setup is to debug a function by saving its arguments in a vector, e.g.

  (defn buggy-function [a b c]
   (def test-bf [a b c]) ;; <- add this
   ... function body ...
  )
Then I can call buggy-function with

  (apply buggy-function test-bf)
and modify the code until it behaves as expected.

This is also where immutability has its grand appearance.

By @mjdiloreto - 7 months
> Note that def we have inserted, to define a global variable request. This is a powerful debug mechanism, but a better way to use it is a tool like [snitch](https://github.com/AbhinavOmprakash/snitch).

Wow, wish I knew about snitch earlier! I have been using a similar, much less powerful, set of macros for this: https://gist.github.com/mjdiloreto/9e7c65023fff691b5ab7d297d...

In my experience, this is a phenomenal way to develop. You just replace whatever `defn` or `let` you are working on with `defn` and `let`, and interact with your app normally (click around in the UI, trigger the frontend or backend functions you are examining). Combined with a tool like portal (https://github.com/djblue/portal) you can quickly get an overview of your system while it is running!