What’s the Best Clojure IDE?

In this article, I’ll evaluate the Emacs, Cursive, and Spacemacs, and explain why I ended up with Spacemacs for most of the projects I’m currently working on.

It’s been a while since I started coding in Clojure, but the “IDE dilemma” was there from the beginning. Although some people might think that it’s a waste of time and you can just pick any editor you want, I disagree. There’s definitely a big difference in terms of productivity if you can use the best tool for the job.

My Tour Through the Clojure IDEs’ Country

Emacs LIVE

In the beginning, I did a quick research and found out that many people in Clojure community use Emacs.

I had never really used Emacs. However, I found one particular Emacs incarnation, Emacs LIVE, specially crafted for beginners. Of course, there still was a big learning curve for me. I spent countless hours getting used to Emacs editing style, shortcuts, and quirks of Emacs LIVE.

On the one hand, it was packed up with useful plugins. On the other hand, its config was bloated, and it was slow to start.

Eventually, I was not able to distinguish if my problems (such as broken keyboard shortcuts for slurp and barf) were related to the specifics of Emacs LIVE or if they were some general issues with Emacs or my Mac OS X configuration.

Cursive

In the meantime, I also played with Cursive.

As a long-time IntelliJ IDEA user, I happened to be familiar with the environment. I really love the features like Full-text search, Project tree window, Symbol navigation, Refactoring, Git integration, Live Templates, Database Plugin, and more.

However, for smaller projects, Cursive feels too heavy-weight:

  • Its start up time is slower.
  • ClojureScript and Figwheel integrations aren’t very good (yet).
  • Regarding plain old text editing, Vim and Emacs provide a better experience.

I love Cursive’s features and need them to be productive. I do think that Colin Fleming is doing a great job. But I also need something more lightweight which doesn’t consume a lot of resources.

Emacs – From the Scratch

Being unable to fix some issues in Emacs LIVE, I finally stepped back and started with plain Emacs, adding only plugins I needed. Step by step, I added projectile, project-tree-explorer (later replaced by NeoTree since project-tree-explorer was painfully slow for large projects), auto-complete, company-mode, and more.

You can find my old Emacs configuration on GitHub. One interesting piece is the configuration for Figwheel.

;; Cider figwheel integration
(require 'cider)
;; more elaborate cider-cljs-lein-repl than in official documentation
;; this tries to match the project type
;; copied from https://lambdaisland.com/episodes/figwheel-emacs-cider
(setq cider-cljs-lein-repl
 "(cond
 (and (resolve 'user/run) (resolve 'user/browser-repl)) ;; Chestnut projects
 (eval '(do (user/run)
 (user/browser-repl)))
 (try
 (require 'figwheel-sidecar.repl-api)
 (resolve 'figwheel-sidecar.repl-api/start-figwheel!)
 (catch Throwable _))
 (eval '(do (figwheel-sidecar.repl-api/start-figwheel!)
 (figwheel-sidecar.repl-api/cljs-repl)))
 (try
 (require 'cemerick.piggieback)
 (resolve 'cemerick.piggieback/cljs-repl)
 (catch Throwable _))
 (eval '(cemerick.piggieback/cljs-repl (cljs.repl.rhino/repl-env)))
 :else
 (throw (ex-info \"Failed to initialize CLJS repl. Add com.cemerick/piggieback and optionally figwheel-sidecar to your project.\" {})))")

Previously, I struggled a lot with a proper setup for ClojureScript projects including browser-connected REPL, Figwheel and CIDER integration.
That Lambda Island episode finally got me some setup that worked.

Again, it took me non-trivial amount of time to configure my Emacs and learn new shortcuts. Yet I still had some issues with code formatting and usability. I was never quite happy with using Emacs for large projects, especially for the ones I wasn’t familiar with. Therefore, I ended up using Cursive for every larger code base I encountered.

 

Spacemacs to the Rescue

Recently, I visited The second Brno Clojure meetup and had a great discussion with Karel Miarka about many topics, including Clojure editors. Instead of using plain Emacs, he recommended the Spacemacs distribution.

Getting Started with Spacemacs

I found following resources to be perfect for getting started with Spacemacs:

  1. Spacemacs documentation
    1. Quickstart
    2. Full Documentation
  2. Clojure development with Spacemacs from Practical.li

The Introductory video is fascinating and made me curious. If that’s how the Spacemacs works, maybe I can use Emacs again without frustration even for large real-world projects.

The downside: I had to learn a little bit different workflow and shortcuts once again.
The upside: easy and almost automatic configuration and good pre-configured plugins.

My Spacemacs Configuration

Since Spacemacs configuration is almost automatic, I did a very little custom configuration:

  • I uncommented following dotspacemacs-configuration-layers in .spacemacs file (use shortcut SPC f e d for quick edit of .spacemacs file and SPC f e R for quick reload)
    • helm
    • auto-completion
      • By using this layer, you can automatically expand code snippets like defn via M-/ (yas-expand) to simulate Cursive’s Live Templates
    • better-defaults
      • few enhancements of standard commands like C-a, C-e, C-w, C-y, M-q
    • git
      • magit provides an incredible Git experience inside the editor.
      • Start with magit-status: SPC g s
      • Unlike many developers who use the Git only from command line, I believe there’s value in having strong Git integration within IDE. I used to use IniteliJ “Commit dialog” a lot and now I have a similar (and maybe even better) experience with magit.
  • I activated hybrid-mode instead of default-mode: dotspacemacs-editing-style 'hybrid
    • This means that you can use emacs shortcuts like C-a and C-e when you are in vim editing mode – very useful!
  • I turned on line numbers by default: dotspacemacs-line-numbers t
    • I can always turn them off via SPC t n

CIDER

There’s a nice shortcut , (comma) which serves as a prefix for all Cider commands. For instance , t a will run all unit tests for current namespace. Alternatively, you can use SPC m prefix: SPC m t a

Other than that, Cider integration is just seamless and very similar to the ordinary Emacs.

Layouts

Layouts are one of the more useful features that I didn’t use from the very beginning.

Basically, the layout is a set of related buffers. Something you could call a project in more traditional IDEs. The layout will help you to organize your buffers.

There is always at least one layout called Default. To create a new layout, press SPC l and then 2. Type the name of the new layout and you’re all set up. You can start creating new buffers. When you press SPC l b, you’ll see only buffers assigned to the current layout (except the Default one which contains all buffers).

Final Thoughts

Nowadays, Spacemacs is my tool of choice for all Clojure projects – both small samples and large code bases with thousands lines of code. I think it’s a great development environment with tons of useful features like Cider REPL, Git integration, Neotree explorer, layouts, and more. I found it more approachable for non-expert Emacs users than vanilla Emacs.

If I work on some project with lots of Java/JavaScript code in the future, I will probably switch back to Cursive.

How About the Atom + Proto REPL?

A Few days ago, I watched the Clojure/conj talk Proto REPL, a New Clojure Development and Visualization Tool by Jason Gilman and it completely blew my mind. The debugging and visualization capabilities of Proto REPL are brilliant.

However, when I tried Atom with Proto REPL it just didn’t feel right to me. To be honest, I didn’t spend much time with it (I have other things to do besides testing all possible Clojure editors). For now, I feel more productive and organized with Spacemacs, so I’ll stick with it. I’m pretty sure I’ll revisit Atom + Proto REPL at some point in the future.

Resources

 

My Bookshelf: Create a Project Skeleton for Clojure Web Application

In the last post, I discussed my Clojure learning strategy in general and introduced my new hobby project My Bookshelf.

This is the very first post in the My Bookshelf series in which I’ll describe how to create a skeleton of a simple Clojure web application based on Luminus template.

Getting Started

When I presented My Clojure Learning Strategy, I mentioned the importance of practical experience and learning just enough to get started. This is exactly what Step 7 of 10-step learning process is about.

As a preparation, I read the first chapter in Web Development with Clojure, 2nd ed. This was more than enough to get ready for creating a new project for My Bookshelf.

Tools

To be able to generate the project skeleton with Luminus template you need Java JDK and Leiningen.

I installed Leiningen via brew:

brew install leiningen

You’ll also need to install a database of your choice. I chose PostgreSQL:

# install PostgreSQL
brew install postgresql
# Run PostgreSQL as a service whenever the computer is started.
brew services start postgresql

After that, you’re ready to go.

Generate a Project Skeleton

Luminus is a handy template providing an opinionated selection of high-quality Clojure libraries. It’s really useful for beginners. It’ll save you plenty of time and a terrible headache which you’d get trying to explore all available Clojure web development libraries.

Having that said, it’s trivial to create a new project:

lein new luminus my-bookshelf +postgres

We’ve just generated simple web app using the +postgres switch which instructs Luminus to add PostgreSQL dependencies and generate db.core namespace.

You can, of course, select another database if you want. You’ll find the list of many possible options in Application Profiles documentation.

Set Up a Database

To be able to connect to the database you need to perform an initial setup:

  • create a database user for your application
  • create a database itself

Both these steps are trivial with PostgreSQL. Run following commands in a shell:

# creates a new user 'bookworm' which will be used by our application to connect to the DB
createuser --createdb bookworm

# create 2 databases - one for development, another one for testing
createdb -O bookworm my_bookshelf_dev
createdb -O bookworm my_bookshelf_test

DB config

Database connection info is stored in profiles.clj in project root directory. This file is automatically generated by luminus template and contains database url for dev and test profiles:

{:profiles/dev  {:env {:database-url "jdbc:postgresql://localhost/my_bookshelf_dev?user=bookworm&password=password"}}
 :profiles/test {:env {:database-url "jdbc:postgresql://localhost/my_bookshelf_test?user=bookworm&password=password"}}}

The database url can always be overriden via DATABASE_URL environment variable.

Migrate the Database

Luminus uses Migratus library for handling database migrations.

To migrate the database just run the following command:

lein migratus migrate

Migratus will scan the resources/migrations directory and look for the .sql files which have to follow naming convention ^(\d+)-([^\.]+)\.(up|down)\.sql

In our case, it’ll find the 20170218124009-add-books-table.up.sql file and execute the SQL found there:

CREATE TABLE books
(id VARCHAR(20) PRIMARY KEY,
 title VARCHAR(30),
 author VARCHAR(60),
 issued DATE,
 status VARCHAR(30));

Note: If you leave the password in profiles.clj blank (jdbc:postgresql://localhost/my_bookshelf_dev?user=bookworm&password=password”) you’ll get an obscure error when trying to migrate the database:

2017-03-07 09:37:12,682 [main] ERROR migratus.database - Error creating DB connection for postgresql://localhost/my_bookshelf_dev?user=bookworm&password=
java.lang.IllegalArgumentException: Vector arg to map conj must be a pair
        at clojure.lang.ATransientMap.conj(ATransientMap.java:37) ~[clojure-1.8.0.jar:na]
...
        at clojure.java.jdbc$parse_properties_uri.invokeStatic(jdbc.clj:178) ~[na:na]
...
        at migratus.database.Database.connect(database.clj:338) [na:na]
...
2017-03-07 09:37:12,683 [main] INFO  migratus.core - Ending migrations
Exception in thread "main" java.lang.NullPointerException, compiling:(/private/var/folders/hn/tgwyrdmj1tb5pmmbdkd1g_qc0000gn/T/form-init7084456921097733207.clj:1:125)
...
Caused by: java.lang.NullPointerException
        at migratus.database$connect_STAR_.invokeStatic(database.clj:223)
        at migratus.database$connect_STAR_.invoke(database.clj:217)
        at migratus.database.Database.connect(database.clj:338)
        ...

So make sure that some password is set.

Run the Application

Now we are ready to run our application skeleton. Go to the terminal and execute lein run.

This will compile the application and start an embedded web server listening on port 3000.

Configure a Different Port For a Web Application

Since many Clojure web applications use port 3000 by default, it can be useful to change the port to another one if you want to avoid conflicts.

For instance, I use the port 3003. You can change this setting in config.edn file.

Add a Simple Welcome page

As a first step, we just want to modify the main page to show a title of our shiny new web application.

To make it easy, we’ll use Hiccup to generate HTML on a server:

(defn render-home [books]
  (hiccup.core/html
    [:body [:h1 "My Bookshelf"]]))

Notice, that we ignore the input argument books for now. We just want to show a static text.

Now run the application (if you haven’t run it already) and open the main page in a browser:

Conclusion

That’s it!

We managed to generate a skeleton for a new Clojure web application, set up a PostgreSQL database and display our first primitive HTML page rendered by Hiccup.

In the next post, we’ll add a basic functionality like showing the list of books to the user.

Source code

You can find complete source code for My Bookshelf in master branch. Beware that this is the latest version and it might be confusing to use it while reading this article.

The version corresponding to this post is tagged (git tag) as 01-skeleton and you can find it in Releases tab on GitHub.