We're hiring!

We're actively seeking designers and developers for all three of our locations.

Clojure Desktop Applications with Swing

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. 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.

Swing

For Swing, we’re using 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 engine, allowing you to query a frame for particular widgets for event subscription or manipulation. It also offers an impressive data binding mechanism similar to UNIX pipes, complete with transformations and tee.

Testing

We’re using Brian Marick’s Midje for unit testing and fest to automate system tests.

Packaging

Leiningen manages our dependencies and packages our jars. We’ve found it helpful to set up a local maven repository in our vendor directory for a couple of cases where we needed a jar that was neither in the main maven repository nor clojars.

Editing

We’re heavy Vim users here at AO, but as fantastic as VimClojure is, paredit.vim from slimv just doesn’t compare to Emacs’ glorious mode. I’m pretty incompetent in Emacs, but the 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).

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 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.

Drew Colthorp (28 Posts)

This entry was posted in Functional Programming and tagged , . Bookmark the permalink. Both comments and trackbacks are currently closed.

14 Comments

  1. Lucian
    Posted December 14, 2011 at 9:52 am

    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.

    • Posted December 14, 2011 at 11:41 am

      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

  2. Chris
    Posted December 14, 2011 at 11:26 am

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

  3. Daniel
    Posted December 14, 2011 at 11:27 am

    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
      Posted December 14, 2011 at 11:42 am

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

      • Daniel
        Posted December 15, 2011 at 8:40 am

        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!

  4. Posted December 14, 2011 at 12:30 pm

    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

    • Posted December 14, 2011 at 1:29 pm

      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

      • Posted December 14, 2011 at 3:09 pm

        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).

        • Posted December 14, 2011 at 3:12 pm

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

  5. Grant Austin
    Posted December 14, 2011 at 12:54 pm

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

    • Posted December 14, 2011 at 1:44 pm

      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
        Posted December 16, 2011 at 9:35 am

        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.

  6. Posted December 14, 2011 at 5:40 pm

    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

One Trackback

  1. By Some Notes on Clojure Performance | Atomic Spin on March 13, 2012 at 2:03 pm

    [...] We learned two major performance lessons very quickly while working on the hottest part of our recent Clojure application: [...]