Get “Clojure” with Klaus

When we asked our Software Engineer Klaus to describe his typical work day, he said…

“I wake up, eat raisin toast, check my emails, check our internal work blog, write code, write more code, eat lunch, write some more code, check Facebook, write more code and then go home.”

If you eat code for breakfast like Klaus, then listen up – this is the blog entry for you!

That’s Klaus on the far right…

One of my goals this trimester was to visit the YOW! Australian Developer Conference in Melbourne and hold a brown bag session for rest of our IT team afterwards on the things I learnt.

A lot of the presentations at the conference revolved around the topic of functional programming, so I’m going to give you a short introduction on it. (For those of you who don’t know functional programming from your elbow, here is a cheat’s guide from wikipedia).

Java is the language I am most familiar with – and I’m not talking about the coffee blend. The first steps I took as a programmer were with a Lisp dialect called Scheme. If you’re interested in Scheme, there is an excellent book by Abelson and Sussman called “Structure and Interpretation of Computer Programs”. It could almost be called the War and Peace of IT books. Once you’ve read it, you’ll be a better programer.

As RedBalloon is a Java-based company, I decided to use Clojure (pronounced “closure”) instead of Scheme for the introduction, which is also a Common Lisp dialect. Clojure also has the benefit of running on Java Virtual Machine, which has surprisingly rich libraries.

I won’t go into Clojure in great depth (because some of you may fall asleep), but to show what it can be used for, I wrote a simple RESTful API using Comopjure as the web framework, JDBC to access the database, Cheshire for JSON encoding and Ring for the web server. To handle dependencies I used Leiningen.

Are you still with me? If so, here’s the code:

 

project.clj

(defproject api "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.4.0"]
                 [org.clojure/java.jdbc "0.2.3"]
                 [postgresql/postgresql "8.4-702.jdbc4"]
                 [compojure "1.1.5"]
                 [ring/ring-core "1.0.2"]
                 [ring/ring-jetty-adapter "1.0.2"]
                 [cheshire "5.0.2"]])

api.clj

(ns api (:require [cheshire.core :refer :all]
                  [clojure.java.jdbc :as sql])
  (:use [compojure.core]
        [ring.adapter.jetty]))

(def postgresql-db {:subprotocol "postgresql"
                    :subname "//127.0.0.1:5432/ofbiz"
                    :user "ofbiz"
                    :password "ofbiz"})

(defn get-product [id]
  (sql/with-connection postgresql-db
    (sql/with-query-results*
      ["select * from product where product_id = ?" id] doall)))

(defn map-as-json [product-map]
  (map (fn [x] (generate-string
                 (hash-map :id (:product_id x)
                           :name (:product_name x)
                           :code (:internal_name x))))
        product-map))

(defroutes hello
  (GET "/product/:id" [id] (map-as-json (get-product id))))

(run-jetty hello {:port 8080})

 

I’ll be the first to admit that this code isn’t the most elegant – it only implements one GET and it lacks features like security and catching, but that is beside the point – this code works!

Plus it’s under 20 lines of code (not counting project.clj) and it demonstrates the power of Clojure and functional programming in general.

Imagine writing the same API using Java. Would 200 lines even be enough? Not to mention all that xml…

Now this was just an excercise in Clojure, but considering options other than Java to implement parts of RedBalloon’s back end is not a bad idea.

In the end smaller codebase = less bugs, less effort and it is a lot easier to change as our requirements change.

Tags: , , , , Share |

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>