What kind of REPL do you use—command-line, CIDER’s REPL buffer, or integrated with your project files? If a file, which ones?
I’m a heavy Emacs+CIDER user. Most projects I do a cider-jack-in
to get started, or the project will include some custom script to start nREPL+cider middleware, so I can cider-connect
.
Once it’s up and running I’ll rarely look at the REPL buffer, except to look at stack traces, println
results, or to check if a command is blocking the thread (there’s a spinner in the modeline). The only things I sometimes type into the REPL are Chestnut-style workflow commands like (go)
(start the system), and (cljs-repl)
to switch to the Figwheel CLJS REPL.
For the most part I’m typing forms into buffers and eval’ing them, usually at the bottom of the namespace where the code will eventually live, or in the corresponding test namespace if I’m working on tests.
My workflow there is similar to @jackrusher’s, I’ll grab some concrete data (from an API or DB or a file), see what shape it has, and bit by bit build up code that works with that. I’ll use a couple of different eval commands for this, mostly eval-at-point or eval-outer-sexp, as well as eval-and-insert. I also have a variant of the latter which prefixes the result with ;;=>
, which is sometimes convenient to tell code from result.
I wasn’t aware of cider-pprint-eval-last-sexp
(thanks Jack!), instead I’ll eval-and-insert, then let cider format the result.
At the end most of the time I end up deleting this code. If it’s my own project and I feel it might still be useful later I might leave it in a comment block. Lately I’ve also started keeping separate “repl” files where I keep some of this exploratory code around. I like the idea of having this code “graduate” to become tests, that’s something I’m going to try to integrate more in my workflow.
How do you deal with state in the REPL, such as let bindings or other local vars?
Most of my code is pure, and all the arguments are right there in-line. If I’m debugging I might pull an inner expression out of a function, wrap it in a let block to define locals, then run it that way. It’s rare that I def
things just for local state, but it happens, especially for big chunks of data that I can toy around with.
Do you save your REPL explorations—other than any “official” result like a def’d function—off to a file? Where? Does that file go into source control?
If I leave them in comment blocks then they get checked in, for my own projects I might also check in the repl files (I put them in a top leve repl/
directory, so it’s out of the class path). On client projects I tend to keep them around but not check them in.
Do you write tests directly from what you write at your REPL, or separately? From where you run those tests—the shell, CIDER, only on a CI server?
When I’m writing them I mostly run tests from the buffer where I’m writing them, either with (test-name)
or with (run-tests)
. Before committing I’ll run a lein test
(or lein eftest
) to make sure they work on a clean slate.
Other things to mention
I use paredit heavily. I never got into expand-region, instead I’ll use paredit navigation (up/down/previous/next/forward/backward) plus sp-copy-sexp
or sp-kill-sexp
. I also rely on cider’s eldoc a lot (show signature of function at point). I started using aggressive-indent-mode
so code is always correctly indented. I like rainbow-delimiters to give matching parens matching colors.
I use clj-refactor, though not as much as I used to. Nowadays I mostly use it to add+hotload project dependencies (what people also use Pomegranate for). I really like having these operations like rename, move form, extract function, but the fact that some of them don’t work for CLJS, and that the project is generally quite flaky has left a bit of a bad taste.