KEMBAR78
Practical Clojure Programming | PDF
Practical Clojure
Programming



Howard M. Lewis Ship
TWD Consulting
hlship@gmail.com
                       1   © 2010 Howard M. Lewis Ship
Agenda

• Build Tools
• Sharing Your Code
• IDE Support


                      2   © 2010 Howard M. Lewis Ship
Build Tools




              3   © 2010 Howard M. Lewis Ship
Leiningen




                                                                               “A build tool for
                                                                               Clojure designed
                                                                               to not set your
                                                                               hair on fire”

                                                                  4                  © 2010 Howard M. Lewis Ship




“Leiningen Versus the Ants” is a short story from 1938 about a plantation owner fighting a battle against 20 square miles of Army Ants.
http://en.wikipedia.org/wiki/Leiningen_Versus_the_Ants
$ lein compile




                 lein
             (shell script)



             leiningen.jar
                                project.clj
               (Clojure)



                              Maven Ant
Ant tasks      Clojure
                                Tasks

Copying,        AOT           Dependency
packaging     Compilation     Resolution
                   5                       © 2010 Howard M. Lewis Ship
6                  © 2010 Howard M. Lewis Ship




lein is a Unix shell script; self-install downloads Clojure and the Leiningen JARs from http://github.com/downloads/technomancy/
leiningen

I had previously added ~/bin to my Unix $PATH

Note: Most of this presentation was done with an alpha version of Leiningen 1.2 (I may need to update the movie to reflect this
properly)
common lein
      commands
• new — create empty project
• deps — download dependencies to lib
• compile
• test
• jar
• clean
                    7              © 2010 Howard M. Lewis Ship
8                  © 2010 Howard M. Lewis Ship




lein uses some Maven infrastructure; downloaded dependencies live in ~/.m2/repository (the download is needed just once)
.
|--   README
|--   lib
|     |-- clojure-1.1.0.jar
|     `-- clojure-contrib-1.1.0.jar
|--   project.clj
|--   src
|     `-- com
|          `-- howardlewisship
|              `-- example
|                  `-- core.clj
`--   test
      `-- com
           `-- howardlewisship
               `-- example
                   `-- core_test.clj




                  9                © 2010 Howard M. Lewis Ship
project.clj
(defproject com.howardlewisship/example "1.0.0-SNAPSHOT"
  :description "FIXME: write"
  :dependencies [[org.clojure/clojure "1.1.0"]
                 [org.clojure/clojure-contrib "1.1.0"]])




                             10                 © 2010 Howard M. Lewis Ship
Cascade
                                    .
                                    |--   lib
                                    |     `-- dev
                                    |--   project.clj
                                    |--   src
                                    |     |-- main
                                    |     |   |-- clojure
                                    |     |   `-- resources
                                    |     `-- test
                                    |         |-- clojure
                                    |         |-- resources
                                    |         `-- webapp
                                    `--   target
                                          `-- classes



                                                              11   © 2010 Howard M. Lewis Ship




http://hlship.github.com/cascade/
(defproject com.howardlewisship.cascade/cascade-core "1.0.0-SNAPSHOT"
  :description "Simple, fast, easy web applications in idiomatic Clojure"
  :url "http://github.com/hlship/cascade/"
  :dependencies
    [[org.clojure/clojure "1.1.0"]
     [org.clojure/clojure-contrib "1.1.0"]
     [org.slf4j/slf4j-api "1.5.2"]
     [org.slf4j/slf4j-log4j12 "1.5.2"]
     [log4j/log4j "1.2.14"]]
  :dev-dependencies
    [[org.eclipse.jetty/jetty-server "7.0.0.RC4"]
     [org.eclipse.jetty/jetty-servlet "7.0.0.RC4"]
     [org.easymock/easymock "2.5.1"]
     [org.seleniumhq.selenium.server/selenium-server "1.0.3"
      :classifier "standalone"]]
  :aot [cascade.filter]
  :warn-on-reflection true
  :main cascade.version
  :source-path "src/main/clojure"
  :test-path "src/test/clojure"
  :resources-path "src/main/resources"
  :test-resources-path "src/test/resources"
  :compile-path "target/classes"
  :jar-dir "target")




                                         12                      © 2010 Howard M. Lewis Ship
Group Id                     Artifact Id               Version


(defproject com.howardlewisship.cascade/cascade-core "1.0.0-SNAPSHOT"
  :description "Simple, fast, easy web applications in idiomatic Clojure"
  :url "http://github.com/hlship/cascade/"




                                   13                      © 2010 Howard M. Lewis Ship
:dependencies — Runtime Dependencies
                                             :dev-dependencies — Build/Test Dependencies

                                                  Group Id

                                                    [org.clojure/clojure-contrib "1.1.0"]


                                                              Artifact Id        Version


                                   [org.seleniumhq.selenium.server/selenium-server
                                   "1.0.3" :classifier "standalone"]


                                                   [log4j "1.2.15" :exclusions
                                                                     [javax.mail/mail
                                                                      javax.jms/jms]]



                                                                  14                 © 2010 Howard M. Lewis Ship




:dependencies will become transitive dependencies of other projects that depend on this one (unless excluded)
:dev-dependencies are just used for testing, or as a source of lein plugins
Maven Repositories

• central — http://repo1.maven.org/maven2
• clojure — http://build.clojure.org/releases
• clojure-snapshots — http://
  build.clojure.org/snapshots
• clojars — http://clojars.org/repo/

                     15                © 2010 Howard M. Lewis Ship
:omit-default-repositories true
:repositories {
  "jboss" "https://repository.jboss.org/nexus/
content/repositories/releases/"
}




    Additional repositories: id and URL



                               16         © 2010 Howard M. Lewis Ship
Compile all source files
                                                                            in :source-path directory


                                         :aot — vector of namespaces to AOT compile, or :all

                                         :namespaces — deprecated alternative to :aot

                                         :warn-on-reflection — Compiler warning when Java
                                         method invocation requires reflection

                                         :main — Namespace containing a main function,
                                         becomes Main-Class Manifest entry




                                                                   17                   © 2010 Howard M. Lewis Ship




Reflection is needed when invoking Java methods on objects without type hints (on the receiving object, and for the method
parameters). Clojure just knows its an object, but hasn't enough type information to determine at build time what the particular method
to invoke will be. This is a big performance hit.
cascade/version.clj
                                        (ns ^{:doc "Main function to display the version number of the framework"}
                                          cascade.version
                                          (:use [cascade config])
                                          (:gen-class))              Command line args
                                        (defn -main [& args]
                                          (println (format "Cascade version %s" (read-config :cascade-version))))




                                        $ lein uberjar
                                        ...
                                        Created target/cascade-core-1.0.0-SNAPSHOT-standalone.jar
                                        ~/clojure-workspace/cascade
                                        $ java -jar target/cascade-core-1.0.0-SNAPSHOT-standalone.jar
                                        Cascade version 1.0.0-SNAPSHOT
                                        ~/clojure-workspace/cascade
                                        $


                                                                            18                      © 2010 Howard M. Lewis Ship




At time of writing, uberjar would not work except with the default :jar-dir of . (I slightly doctored the text to show what it will look like
once fixed).
:compile-path "target/classes"
:source-path "src/main/clojure"
:test-path "src/test/clojure"
:resources-path "src/main/resources"
:test-resources-path "src/test/resources"
:compile-path "target/classes"
:jar-dir "target"

                                  Where to put
Where to create                compiled namespaces
constructed JARs


   :compile-path        classes
   :source-path         src
   :test-path           test
   :library-path        lib
   :resources-path      resources
   :test-resources-path test-resources
   :jar-dir             .

                      19                       © 2010 Howard M. Lewis Ship
Lein Issues

• Horrible, confusing name
• Targets Maven more than Ant
• Only one command at a time
• Little bit slow to start
• Documentation is terrible

                   20           © 2010 Howard M. Lewis Ship
Maven




                                                  21    © 2010 Howard M. Lewis Ship




http://maven.apache.org

http://github.com/talios/clojure-maven-plugin
Cold clean compile:
                                                                          4m 32s
                                                                          12 MB (392 files)

                                                                          Clean compile:
                                                                          40s




                                                                22                  © 2010 Howard M. Lewis Ship




pom.xml available at http://github.com/hlship/cascade/blob/maven-build/pom.xml
Maven Issues

• Confusing & distressing to use
• Huge, ugly XML build file
• Lots of weird downloads on first use
• Slower than Lein
• Wouldn't compile cascade.filter Why?

                   23              © 2010 Howard M. Lewis Ship
Gradle
                                              24     © 2010 Howard M. Lewis Ship




http://gradle.org/

http://bitbucket.org/kotarak/clojuresque/
Cold clean compile:
                                                                               3m 30s
                                                                               27 MB (129 files)

                                                                               Clean compile:
                                                                               40s




                                                                    25                   © 2010 Howard M. Lewis Ship




build.gradle available at http://github.com/hlship/cascade/blob/gradle-build/build.gradle
Gradle Summary
                                         • Very slick in many areas
                                         • Need to learn some Groovy syntax
                                         • Not as focused/succinct as Lein
                                         • Clojuresque plugin very immature
                                         • Better documentation, still occasionally
                                            patchy
                                         • No real docs for Clojuresque
                                                                 26                © 2010 Howard M. Lewis Ship




CLI has many useful features such as clean quick way to display dependencies; it's also cleaner about reporting downloads from
remote repositories. It's a more fully featured build system, but it's also a lot to take in.
Build Summary

                                        • Try Lein, hope for the best
                                        • Keep tabs on Gradle & Clojuresque
                                        • Avoid Maven
                                        • AOT Compilation of libraries a problem

                                                               27                 © 2010 Howard M. Lewis Ship




A irritation now is that AOT compilation (which can be necessary in many cases) can cause unwanted compilation of namespaces
from libraries. See http://www.assembla.com/spaces/clojure/tickets/322
Sharing Your Code




        28    © 2010 Howard M. Lewis Ship
29   © 2010 Howard M. Lewis Ship
30   © 2010 Howard M. Lewis Ship
31                 © 2010 Howard M. Lewis Ship




Why not "lein push"? the necessary Lein plugin is compiled against Clojure 1.1 and Cascade is tracking against 1.2. Fall down, go
boom. This is usually a problem with code that requires AOT, which it the case for cascade.filter. Still, it's very unfortunate.

I use SSHKeyChain.app to help manage my SSH sessions; otherwise I'd be prompted for my secret key when I execute the scp
command.
32   © 2010 Howard M. Lewis Ship
IDE Support
          33   © 2010 Howard M. Lewis Ship
Eclipse


• Counterclockwise 0.0.95.RC2
• http://code.google.com/p/counterclockwise/


                    34               © 2010 Howard M. Lewis Ship
35   © 2010 Howard M. Lewis Ship
IntelliJ IDEA




                                          • La Clojure 0.2.267
                                          • Built-in to community edition
                                                               36           © 2010 Howard M. Lewis Ship




La Clojure was one of the first IDE plugins available
37   © 2010 Howard M. Lewis Ship
NetBeans


                                                               • NetBeans 6.9
                                                               • Enclojure 1.2.1


                                                                38                © 2010 Howard M. Lewis Ship




Installation details at http://www.assembla.com/wiki/show/clojure/Getting_Started_with_Netbeans_and_Enclojure
39   © 2010 Howard M. Lewis Ship
Emacs




  40    © 2010 Howard M. Lewis Ship
IDE Support


• Frustrating
• NetBeans feels most advanced
• AOT support limited in all


                    41           © 2010 Howard M. Lewis Ship
Wrap Up


• Explosive growth in Clojure interest
• Tools just catching up
• Like Java in 2001?


                     42                  © 2010 Howard M. Lewis Ship
Slides

• Will be available on SlideShare
  http://www.slideshare.net/hlship


• … and rate me at SpeakerRate:
  http://speakerrate.com/speakers/3749-
  howard-m-lewis-ship

                     43              © 2010 Howard M. Lewis Ship
© 2009 fdecomite
http://www.flickr.com/photos/fdecomite/3185386870/
                                                          © 2008 Hallvard E
                           http://www.flickr.com/photos/eldholm/2354982554/
© 2005 Steve Jurvetson
http://www.flickr.com/photos/jurvetson/70704300/
                                                       © 2006 Chris Walton
                          http://www.flickr.com/photos/philocrites/245011706/
© 2007 Howard Gees
http://www.flickr.com/photos/cyberslayer/952153409/
                                                        © 2007 pickinjim2006
                     http://www.flickr.com/photos/81838529@N00/525129498/
© 2005 Jean-Philippe Daigle
http://www.flickr.com/photos/jpdaigle/59942231/
                                                               © 2007 QQ Li
                              http://www.flickr.com/photos/ozyman/443545349/
© 2008 MadAboutCows
http://www.flickr.com/photos/madaboutcows/2933510443/
                                                         © 2008 Martin Junius
                               http://www.flickr.com/photos/m-j-s/2724756177/
    
                                     44                            © 2010 Howard M. Lewis Ship

Practical Clojure Programming

  • 1.
    Practical Clojure Programming Howard M.Lewis Ship TWD Consulting hlship@gmail.com 1 © 2010 Howard M. Lewis Ship
  • 2.
    Agenda • Build Tools •Sharing Your Code • IDE Support 2 © 2010 Howard M. Lewis Ship
  • 3.
    Build Tools 3 © 2010 Howard M. Lewis Ship
  • 4.
    Leiningen “A build tool for Clojure designed to not set your hair on fire” 4 © 2010 Howard M. Lewis Ship “Leiningen Versus the Ants” is a short story from 1938 about a plantation owner fighting a battle against 20 square miles of Army Ants. http://en.wikipedia.org/wiki/Leiningen_Versus_the_Ants
  • 5.
    $ lein compile lein (shell script) leiningen.jar project.clj (Clojure) Maven Ant Ant tasks Clojure Tasks Copying, AOT Dependency packaging Compilation Resolution 5 © 2010 Howard M. Lewis Ship
  • 6.
    6 © 2010 Howard M. Lewis Ship lein is a Unix shell script; self-install downloads Clojure and the Leiningen JARs from http://github.com/downloads/technomancy/ leiningen I had previously added ~/bin to my Unix $PATH Note: Most of this presentation was done with an alpha version of Leiningen 1.2 (I may need to update the movie to reflect this properly)
  • 7.
    common lein commands • new — create empty project • deps — download dependencies to lib • compile • test • jar • clean 7 © 2010 Howard M. Lewis Ship
  • 8.
    8 © 2010 Howard M. Lewis Ship lein uses some Maven infrastructure; downloaded dependencies live in ~/.m2/repository (the download is needed just once)
  • 9.
    . |-- README |-- lib | |-- clojure-1.1.0.jar | `-- clojure-contrib-1.1.0.jar |-- project.clj |-- src | `-- com | `-- howardlewisship | `-- example | `-- core.clj `-- test `-- com `-- howardlewisship `-- example `-- core_test.clj 9 © 2010 Howard M. Lewis Ship
  • 10.
    project.clj (defproject com.howardlewisship/example "1.0.0-SNAPSHOT" :description "FIXME: write" :dependencies [[org.clojure/clojure "1.1.0"] [org.clojure/clojure-contrib "1.1.0"]]) 10 © 2010 Howard M. Lewis Ship
  • 11.
    Cascade . |-- lib | `-- dev |-- project.clj |-- src | |-- main | | |-- clojure | | `-- resources | `-- test | |-- clojure | |-- resources | `-- webapp `-- target `-- classes 11 © 2010 Howard M. Lewis Ship http://hlship.github.com/cascade/
  • 12.
    (defproject com.howardlewisship.cascade/cascade-core "1.0.0-SNAPSHOT" :description "Simple, fast, easy web applications in idiomatic Clojure" :url "http://github.com/hlship/cascade/" :dependencies [[org.clojure/clojure "1.1.0"] [org.clojure/clojure-contrib "1.1.0"] [org.slf4j/slf4j-api "1.5.2"] [org.slf4j/slf4j-log4j12 "1.5.2"] [log4j/log4j "1.2.14"]] :dev-dependencies [[org.eclipse.jetty/jetty-server "7.0.0.RC4"] [org.eclipse.jetty/jetty-servlet "7.0.0.RC4"] [org.easymock/easymock "2.5.1"] [org.seleniumhq.selenium.server/selenium-server "1.0.3" :classifier "standalone"]] :aot [cascade.filter] :warn-on-reflection true :main cascade.version :source-path "src/main/clojure" :test-path "src/test/clojure" :resources-path "src/main/resources" :test-resources-path "src/test/resources" :compile-path "target/classes" :jar-dir "target") 12 © 2010 Howard M. Lewis Ship
  • 13.
    Group Id Artifact Id Version (defproject com.howardlewisship.cascade/cascade-core "1.0.0-SNAPSHOT" :description "Simple, fast, easy web applications in idiomatic Clojure" :url "http://github.com/hlship/cascade/" 13 © 2010 Howard M. Lewis Ship
  • 14.
    :dependencies — RuntimeDependencies :dev-dependencies — Build/Test Dependencies Group Id [org.clojure/clojure-contrib "1.1.0"] Artifact Id Version [org.seleniumhq.selenium.server/selenium-server "1.0.3" :classifier "standalone"] [log4j "1.2.15" :exclusions [javax.mail/mail javax.jms/jms]] 14 © 2010 Howard M. Lewis Ship :dependencies will become transitive dependencies of other projects that depend on this one (unless excluded) :dev-dependencies are just used for testing, or as a source of lein plugins
  • 15.
    Maven Repositories • central— http://repo1.maven.org/maven2 • clojure — http://build.clojure.org/releases • clojure-snapshots — http:// build.clojure.org/snapshots • clojars — http://clojars.org/repo/ 15 © 2010 Howard M. Lewis Ship
  • 16.
    :omit-default-repositories true :repositories { "jboss" "https://repository.jboss.org/nexus/ content/repositories/releases/" } Additional repositories: id and URL 16 © 2010 Howard M. Lewis Ship
  • 17.
    Compile all sourcefiles in :source-path directory :aot — vector of namespaces to AOT compile, or :all :namespaces — deprecated alternative to :aot :warn-on-reflection — Compiler warning when Java method invocation requires reflection :main — Namespace containing a main function, becomes Main-Class Manifest entry 17 © 2010 Howard M. Lewis Ship Reflection is needed when invoking Java methods on objects without type hints (on the receiving object, and for the method parameters). Clojure just knows its an object, but hasn't enough type information to determine at build time what the particular method to invoke will be. This is a big performance hit.
  • 18.
    cascade/version.clj (ns ^{:doc "Main function to display the version number of the framework"} cascade.version (:use [cascade config]) (:gen-class)) Command line args (defn -main [& args] (println (format "Cascade version %s" (read-config :cascade-version)))) $ lein uberjar ... Created target/cascade-core-1.0.0-SNAPSHOT-standalone.jar ~/clojure-workspace/cascade $ java -jar target/cascade-core-1.0.0-SNAPSHOT-standalone.jar Cascade version 1.0.0-SNAPSHOT ~/clojure-workspace/cascade $ 18 © 2010 Howard M. Lewis Ship At time of writing, uberjar would not work except with the default :jar-dir of . (I slightly doctored the text to show what it will look like once fixed).
  • 19.
    :compile-path "target/classes" :source-path "src/main/clojure" :test-path"src/test/clojure" :resources-path "src/main/resources" :test-resources-path "src/test/resources" :compile-path "target/classes" :jar-dir "target" Where to put Where to create compiled namespaces constructed JARs :compile-path classes :source-path src :test-path test :library-path lib :resources-path resources :test-resources-path test-resources :jar-dir . 19 © 2010 Howard M. Lewis Ship
  • 20.
    Lein Issues • Horrible,confusing name • Targets Maven more than Ant • Only one command at a time • Little bit slow to start • Documentation is terrible 20 © 2010 Howard M. Lewis Ship
  • 21.
    Maven 21 © 2010 Howard M. Lewis Ship http://maven.apache.org http://github.com/talios/clojure-maven-plugin
  • 22.
    Cold clean compile: 4m 32s 12 MB (392 files) Clean compile: 40s 22 © 2010 Howard M. Lewis Ship pom.xml available at http://github.com/hlship/cascade/blob/maven-build/pom.xml
  • 23.
    Maven Issues • Confusing& distressing to use • Huge, ugly XML build file • Lots of weird downloads on first use • Slower than Lein • Wouldn't compile cascade.filter Why? 23 © 2010 Howard M. Lewis Ship
  • 24.
    Gradle 24 © 2010 Howard M. Lewis Ship http://gradle.org/ http://bitbucket.org/kotarak/clojuresque/
  • 25.
    Cold clean compile: 3m 30s 27 MB (129 files) Clean compile: 40s 25 © 2010 Howard M. Lewis Ship build.gradle available at http://github.com/hlship/cascade/blob/gradle-build/build.gradle
  • 26.
    Gradle Summary • Very slick in many areas • Need to learn some Groovy syntax • Not as focused/succinct as Lein • Clojuresque plugin very immature • Better documentation, still occasionally patchy • No real docs for Clojuresque 26 © 2010 Howard M. Lewis Ship CLI has many useful features such as clean quick way to display dependencies; it's also cleaner about reporting downloads from remote repositories. It's a more fully featured build system, but it's also a lot to take in.
  • 27.
    Build Summary • Try Lein, hope for the best • Keep tabs on Gradle & Clojuresque • Avoid Maven • AOT Compilation of libraries a problem 27 © 2010 Howard M. Lewis Ship A irritation now is that AOT compilation (which can be necessary in many cases) can cause unwanted compilation of namespaces from libraries. See http://www.assembla.com/spaces/clojure/tickets/322
  • 28.
    Sharing Your Code 28 © 2010 Howard M. Lewis Ship
  • 29.
    29 © 2010 Howard M. Lewis Ship
  • 30.
    30 © 2010 Howard M. Lewis Ship
  • 31.
    31 © 2010 Howard M. Lewis Ship Why not "lein push"? the necessary Lein plugin is compiled against Clojure 1.1 and Cascade is tracking against 1.2. Fall down, go boom. This is usually a problem with code that requires AOT, which it the case for cascade.filter. Still, it's very unfortunate. I use SSHKeyChain.app to help manage my SSH sessions; otherwise I'd be prompted for my secret key when I execute the scp command.
  • 32.
    32 © 2010 Howard M. Lewis Ship
  • 33.
    IDE Support 33 © 2010 Howard M. Lewis Ship
  • 34.
    Eclipse • Counterclockwise 0.0.95.RC2 •http://code.google.com/p/counterclockwise/ 34 © 2010 Howard M. Lewis Ship
  • 35.
    35 © 2010 Howard M. Lewis Ship
  • 36.
    IntelliJ IDEA • La Clojure 0.2.267 • Built-in to community edition 36 © 2010 Howard M. Lewis Ship La Clojure was one of the first IDE plugins available
  • 37.
    37 © 2010 Howard M. Lewis Ship
  • 38.
    NetBeans • NetBeans 6.9 • Enclojure 1.2.1 38 © 2010 Howard M. Lewis Ship Installation details at http://www.assembla.com/wiki/show/clojure/Getting_Started_with_Netbeans_and_Enclojure
  • 39.
    39 © 2010 Howard M. Lewis Ship
  • 40.
    Emacs 40 © 2010 Howard M. Lewis Ship
  • 41.
    IDE Support • Frustrating •NetBeans feels most advanced • AOT support limited in all 41 © 2010 Howard M. Lewis Ship
  • 42.
    Wrap Up • Explosivegrowth in Clojure interest • Tools just catching up • Like Java in 2001? 42 © 2010 Howard M. Lewis Ship
  • 43.
    Slides • Will beavailable on SlideShare http://www.slideshare.net/hlship • … and rate me at SpeakerRate: http://speakerrate.com/speakers/3749- howard-m-lewis-ship 43 © 2010 Howard M. Lewis Ship
  • 44.
    © 2009 fdecomite http://www.flickr.com/photos/fdecomite/3185386870/ © 2008 Hallvard E http://www.flickr.com/photos/eldholm/2354982554/ © 2005 Steve Jurvetson http://www.flickr.com/photos/jurvetson/70704300/ © 2006 Chris Walton http://www.flickr.com/photos/philocrites/245011706/ © 2007 Howard Gees http://www.flickr.com/photos/cyberslayer/952153409/ © 2007 pickinjim2006 http://www.flickr.com/photos/81838529@N00/525129498/ © 2005 Jean-Philippe Daigle http://www.flickr.com/photos/jpdaigle/59942231/ © 2007 QQ Li http://www.flickr.com/photos/ozyman/443545349/ © 2008 MadAboutCows http://www.flickr.com/photos/madaboutcows/2933510443/ © 2008 Martin Junius http://www.flickr.com/photos/m-j-s/2724756177/ 44 © 2010 Howard M. Lewis Ship