A Clojure REPL Workflow For Beginners
I’ve been getting questions from beginner Clojure developers on how to effectively use their REPL and interactive development.
Quite a few of these people are coming from languages like Java, where they would have to compile their application and wait before running any code.
Integrate your REPL with your editor
You must have your REPL integrated with your editor. Whether that’s a text editor like emacs with cider, or an IDE like IntelliJ with Cursive, you have to be able to evaluate code in your REPL from the editor.
I see beginners with a REPL in their terminal, editing code in a text editor, and then copying and pasting code into their REPL to see the results.
Don’t do that.
You should be able to send a file, region of code, or a single s-expression to your REPL from your editor.
Jump to Definition
Now that you have an editor that is integrated with your REPL, you
should be able to jump to the definition of a symbol. Find your
editor’s keybinding for this. In emacs with cider, it’s
Typically, you shouldn’t be looking up documentation on an external source. Whenever I need to know what a function does, I just jump to the definition of that function and read the docstring if it has one or the implementation if it doesn’t.
It also makes navigating code far easier.
TIP: You can edit and evaluate functions when you jump to their
definition. For instance, you could jump to clojure.core and change
str works. This is far more useful when you’re working with
3rd party libraries and need to add some logging to figure out
what’s going on.
Keep the REPL State in your Head
Once you start getting used to using a REPL, you also need to learn how to keep some of the REPL state in your head. Keep in mind what you’ve evaluated and what you haven’t.
Not knowing is how you quickly have bugs where you think the code has been evaluated and your function definition updated but has not.
Don’t Type into the REPL Directly
This is more of a soft rule, but I would recommend that you don’t type large chunks of code directly into the REPL when exploring and experimenting.
Instead, I recommend having a comment block at the bottom of the namespace you’re working with that has a bunch of code that you might’ve typed into the REPL.
This lets you save your REPL experiments for multiple sessions and even stored in source control while you work on your branch.
Of course, when exploring how functions work and their results, feel free to use whatever is quickest for you.
I just find that whenever I end up typing a function or redefining an existing function to refactor that it’s far easier to just do it in a comment region and evaluating just what I need.
Run Tests from your REPL
Use your REPL to run your tests. I see beginners with a terminal window running tests that take quite a while to start up due to Clojure’s startup time.
Testing should be integrated with your editor as well. Cider lets me run the entire test suite, a single namespace, a single test, or re-run failed tests.
One thing to keep in mind is you should run the tests outside of a running (in a fresh environment) before pushing code. This goes back to keeping the REPL state in your head. Often times you get your REPL to a state where your code and tests work but from a fresh load it doesn’t. Running tests outside of the currently running REPL instance will help you avoid this.