Clojure Desktop Applications with Swing

h1. Starting a Clojure Desktop Application

We’re starting up our first desktop application in Clojure. We’re a heavy vim and ruby shop. We’ve done several desktop applications in “JRuby”:https:/rolling-a-jruby-desktop-application/. This is the first time we’ve tackled swing UIs and GUI testing in Clojure. It’s still early in the process, but here’s what we’ve found so far.

h2. Swing

For Swing, we’re using “seesaw”:https://github.com/daveray/seesaw. It provides Clojure bindings to standard Swing widgets and MigLayout, which was all I set out looking for. What really impressed me, however, was its CSS “selector”:http://daveray.github.com/seesaw/seesaw.core-api.html#seesaw.core/select engine, allowing you to query a frame for particular widgets for event subscription or manipulation. It also offers an impressive “data binding”:http://daveray.github.com/seesaw/seesaw.bind-api.html mechanism similar to UNIX pipes, complete with transformations and @tee@.

h2. Testing

We’re using Brian Marick’s “Midje”:https://github.com/marick/Midje for unit testing and “fest”:http://code.google.com/p/fest/ to automate system tests.

h2. Packaging

“Leiningen”:https://github.com/technomancy/leiningen manages our dependencies and packages our jars. We’ve found it helpful to “set up a local maven repository”:http://www.pgrs.net/2011/10/30/using-local-jars-with-leiningen/ in our vendor directory for a couple of cases where we needed a jar that was neither in the main maven repository nor clojars.

h2. Editing

We’re heavy “Vim users”:https:/atomic-vim-config/ here at AO, but as fantastic as “VimClojure”:https://bitbucket.org/kotarak/vimclojure/overview is, paredit.vim from “slimv”:http://www.vim.org/scripts/script.php?script_id=2531 just doesn’t compare to “Emacs’ glorious mode”:http://www.emacswiki.org/emacs/ParEdit. I’m pretty incompetent in Emacs, but the “Emacs starter kit”:https://github.com/technomancy/Emacs-starter-kit and a weekend of practice with Emacs and ParEdit has taken the shine off my beloved vim for lisp editing. (It’s actually been a while since I last used Emacs, so I’m sticking with vim in the short term while I ramp back up with Emacs).

h2. State mediation between model and view

So far things are going well with Clojure, but rethinking our approach to structuring GUI applications is definitely a challenge. We normally use “MVP/Presenter First”:https://atomicobject.com/resources/presenter-first when building web applications, but the pattern doesn’t map as easily to Clojure as it does to new object oriented languages. Decoupling domain model and UI with a stateless definition defining communication between the two still seems like a winning combination. We’re using Clojure reference types (refs, atoms, actors) to represent entities in our application domain and using event handlers and data binding with selector-identified Swing widgets. This seems like a workable approach but there are still questions to answer. More to come.

Conversation
  • Lucian says:

    I’ve been using Emacs with Evil mode, and it’s very good. I’ve been using it for almost a month. I get the extensibility of emacs and the nice bindings of vim.

    • Hi Lucian,

      I was just looking at Evil mode last night but hadn’t installed it yet. Last I’d tried vim-in-emacs it was with viper mode and I was a little hesitant to go down that approach again. Your suggestion spurred me to take the plunge – Evil-mode is absolutely fantastic. Thanks for the recommendation.

      Drew

  • Chris says:

    I’m also hearing good things about Evil mode in Emacs

  • Daniel says:

    I’m using Emacs with vimpulse, I really dislike the editing/movement keys in emacs and find Vim’s more intuitive.

    However I also really dislike Vim as an editor and I love the richness of features found in Emacs, so I find using the vim keybindings in Emacs a suitable compromise

    • Lucian says:

      I’ve found Evil to work much better than vimpulse, especially when it comes to buffer management.

      • Daniel says:

        Just tried out Evil mode and it’s much better than Vimpulse, I’m glad I came to this post now because I’d have carried on unaware that an alternative existed!

  • Tamas says:

    Hi Drew,

    I’m the author of slimv (and paredit.vim). Could you please give me some examples what you missed or didn’t like in paredit.vim? I’d like to have some user feedback on how to improve it.
    Thanks.

    Tamas

    • Hi Tamas,

      I appreciate all the work you’ve done on slimv. Some of the problems I had may have been because I didn’t RTFM, but I never found TFM. :-) I mainly used the else clause of the g:paredit_shortmaps branch in paredit.vim as a reference. The issues I ran into were

      * No slurp/barf left (that I saw)
      * Paredit.vim didn’t seem to have fallbacks for cases where extra parens/brackets made it into the file (merge conflict), and I couldn’t figure out how to actually delete the extracharacter
      * Not as many shortcuts as paredit.el for inserting parens/brackets how I want them. I use M-( a lot in emacs to wrap a funcall in parens so I can do something with its result.

      There were also a lot of cases where things didn’t work quite how I expected. I can’t really enumerate these – I wasn’t paying close enough attention. Basically it came down to it felt like a lot more effort was required from me to use paredit.vim than I felt with paredit.el.

      In any case, valiant effort on paredit.vim. Despite my complaints, I was really impressed that someone took up the challenge. It’s starting to feel like it’ll be a race between the evil-mode developers and you to see who lures vim users in long-term for clojure (and other lisp) development.

      Drew

      • Tamas says:

        Thanks, Drew. Here are some notes that may be useful:

        * Paredit TFM (after doing :helptags):
        :help paredit

        * Not exactly slurp/barf but something quite similar for moving the parens around (assume is , ):
        ,

        * Paredit mode should be automatically disabled while the current form is unbalanced. Or you can manually toggle paredit mode via ,( at any time.

        * Wrap is ,W which wraps the current symbol or form (if cursor is on a paren) or the visual selection. Opposite is ,S (splice).

        • Tamas says:

          Sorry, some characters were swallowed:
          Moving the parens around: ,< and ,> (,[less than] and ,[greater than])

  • Grant Austin says:

    I’m curious about the reasons that prompted you to choose Midje over speclj. Could you elaborate?

    • Hi Grant,

      We didn’t make a decision to not use speclj – we just never really found it. AO has some history with Brian Marick and I’d seen retweets about Midje come through the twitterverse. Finding that Midje provides mocks, has a clean syntax, and has great documentation was all I really needed to take the plunge.

      Looking at speclj now (for the first time), I don’t see support for mocks, the documentation looks pretty sparse compared to Midje, and seems (on the surface) to be a little less complete. Also, I think I prefer (foo :bar) => :result to (should= (foo :bar) :result).

      Do you prefer speclj? If so, why?

      Drew

      • Grant says:

        I’m brand spanking new to Clojure. I was just using speclj (an 8th Light craftsman’s project) because that was what was suggested to me by my 8th Light mentor.

        The (foo :bar) => :result form seems more Clojurey to me. I’ll definitely be giving it a try.

        Thanks for the response.

  • Dave Ray says:

    Drew,

    Thanks for the kind words about Seesaw. I’m glad you’re finding it useful. Please let me know if you have any pain points. I add features based on my own random interests. If I could direct that work towards making someone else’s experience more pleasant, that’d be great.

    Cheers,

    Dave

  • Comments are closed.