Tag Archives: Pedestal

Clojure on Pedestal

Yesterday I gave a two-hour talk at Lambda Lounge Kraków on Pedestal (and some ClojureScript).

I talked only about the client side, and in that mostly about the dataflow engine and how it connects to rendering and services. We also had some unplanned discussion on testing.

Most of the talk was actually a tutorial, developing a basic monitoring application in a few steps. It probably doesn’t add much over the tutorial, but hopefully it was a faster introduction.

If you’re interested in resources:

Now that I’m on the Internet, I guess I have to explain myself. Yes, I am aware that there are better ways than that jQuery, that I could have created a library for time series, and that it would not run after advanced Closure compilation. It’s not even a perfect Pedestal app. But I think it did the job of explaining the concepts behind Pedestal without drowning the audience in details, using basic pieces that everyone was familiar with. Let’s say that I left ironing out the wrinkles as an exercise.

Despite my lack of experience from my point of view it went fairly well. Always an interesting experience. If you’ve been there, feel free to tell me what you think.

Client-Side Routing with Pedestal

It’s fairly common for rich web applications to use some kind of client-side routing: Load the application once, then navigate with special URLs like http://example.com/#/subpage. Browser doesn’t perform a round trip to server for them, but instead the right chunk of JavaScript can rebuild part of the page locally, hide and show elements etc.

JavaScript tools

There is a number of JavaScript tools to do it. I find two examples particularly inspiring.

Flatiron Director lets you do something like:

var author = function () { console.log("author"); };
var books = function () { console.log("books"); };
 var routes = {
  '/author': author,
  '/books': books
};</p>

<p>var router = Router(routes);
router.init();

Then when you visit page ending with #/books, it will call the books function. Very flexible, but then you need to write a lot of code yourself.

Another good example with completely different philosophy is the Angular JS Router. In your page you can bless a special section as the ngView, and configure router with:

$routeProvider
    .when('/author', {templateUrl: '/t_author.html', controller: "authorController"})
    .when('/books', {templateUrl: '/t_books.html', controller: "booksController"})
    .otherwise({redirectTo: '/books'});

When you go to #/author, Angular will replace the contents of ngView with the template and install the selected controller on it. It fits well in the Angular philosophy and has some benefits.

Pedestal

Anyway, how can we use routing with Pedestal? Turns out there is no built-in or even recommended way to do it, but you can plug in whatever you want. After some research I decided to use goog.History from Closure which comes free of charge with ClojureScript.

All code for these examples is in my GitHub repository. Note that there are 3 tags corresponding to each of the solutions.

Attempt 1: Simple, hardcoded

The first thing I did was a rather ugly, hardcoded solution using the entire Pedestal data flow.

First I installed a listener on goog.History that extracts the location token and pushes it to the :route topic in Pedestal input queue:

(defn ^:private set-route [input-queue route]
  (p/put-message input-queue {msg/topic :route msg/type :set-route :value route}))

(defn configure-router 
  ([input-queue] (configure-router input-queue ""))
  ([input-queue default-route]
    (doto (goog.History.)
      (goog.events/listen (goog.object/getValues goog.history/EventType) 
                          (fn [e]
                            (let [token (.-token e)]
                              (if (= "" token)
                                (set-route input-queue default-route)
                                (set-route input-queue token)))))
    (.setEnabled true))))

I plugged in the default transform and emitter that basically push that message up to the application model:

(def count-app {:transform {:route {:init nil :fn #(:value %2)}}
                :emit {:router {:fn app/default-emitter-fn :input #{:route}}}})

(defn ^:private set-route [input-queue route]
  (p/put-message input-queue {msg/topic :route msg/type :set-route :value route}))

The last step on the pipeline is renderer. This one here is fairly uninteresting, it basically replaces contents of some specific div with different text:

(defn route-changed [_ [_ _ old-value new-value] input-queue]
  (.log js/console "Routing from" old-value "to" new-value)
  (let [container (dom/by-id "view-container")]
    (dom/destroy-children! container)
    (dom/append! container (str "<p>" new-value "</p>"))))

The main function:

(defn ^:export main []
  (let [app (app/build count-app)
        render-fn (push/renderer "content" [[:value [:route] route-changed]])]
    (render/consume-app-model app render-fn)
    (configure-router (:input app) "first")
    (app/begin app)))

This solution is hardly reusable, but it’s also very flexible. At any point we can decide to do something specific when switching the location – change something in data or application model, make a server request, etc.

I wouldn’t recommend it, it’s just the very first attempt at the problem.

Attempt 2: Generic

It’s quite obvious that the above solution can be generalized. One way to do it is to generalize the renderer. We can initialize it with some configuration telling it what action to execute for each path. For instance, something like this:

(defn render-route [msg]
  (let [container (dom/by-id "view-container")]
    (dom/destroy-children! container)
    (dom/append! container (str "<p>" msg "</p>"))))

(defn route-first []
  (render-route "This is the first route"))

(defn route-second []
  (render-route "This is the second route"))

(def router-config
  {:routes {"first" route-first
            "second" route-second}
   :default-route "first"
   :listener (fn [old-value new-value]
               (.log js/console "Routing from" old-value "to" new-value))})

There isn’t too much interesting stuff happening here, but it clearly is more reusable.

The renderer is now initialized with this config like:

(defn route-renderer [cfg]
  (fn [_ [_ _ old-value new-value] input-queue]
    (when-let [listener (:listener cfg)]
      (listener old-value new-value))
    (if-let [dispatcher (get-in cfg [:routes new-value])]
      (dispatcher)
      (.log js/console "Unknown route:" new-value))))

I’ll omit the history listener and main for clarity, but I hope the point is clear. Again, code is at Github under the generic tag.

All this solution does is bind a function call to each path. I could easily extract it to a tiny generic library. I could also make it more powerful – for instance, use higher order “constructor functions” that let each action access state or push to the input queue. I could use templating. And so on.

Attempt 3: Generic – light

As I was wrapping that up, I figured out one more way to do it. Remember, both solutions above use the entire Pedestal stack – the history listener pushes a message to input queue, and we need a transform and emitter to pass it up to renderer. Maybe I don’t need to involve the “lower layers” with navigation and rendering?

I realized I can just plug the rendering in the history listener itself:

(defn route-first [input-queue]
  (render-route "This is the first route"))

(defn route-second [input-queue]
  (render-route "This is the second route"))

(def router-config
  {:routes {"first" route-first
            "second" route-second}
   :default-route "first"
   :listener (fn [new-value]
               (.log js/console "Routing to" new-value))})

(defn route-changed [{:keys [input]} route-config]
  (fn [e]
    (let [token (.-token e)
          token (if (= "" token) (:default-route route-config) token)]
      (when-let [listener (:listener cfg)]
        (listener token))
      (if-let [dispatcher (get-in route-config [:routes token])]
        (dispatcher input)
        (.log js/console "Unknown route:" token)))))

(defn configure-router 
  ([app route-config]
    (doto (goog.History.)
      (goog.events/listen 
        (goog.object/getValues goog.history/EventType) 
        (route-changed app route-config))
      (.setEnabled true))))

(defn ^:export main []
  (let [app (app/build)]
    (configure-router app router-config)
    (app/begin app)))

That’s it. It doesn’t even need Pedestal. The router is a generic little thing based only on Google Closure. However, in this case each action also has access to the input queue and it’s pretty obvious how you could expose any other things from Pedestal. You can still push messages to Pedestal, install renderers etc. – but that’s no longer required for routing itself.

Wrapping Up

In the end, I’m fairly satisfied with the last solution. Well, in a way – it still requires me to do a ton of manual work! Not for the routing itself, but for DOM rendering. It feels a lot like jQuery, with tons and tons of tedious, manual DOM manipulation.

I guess I became a little spoilt by Angular, and I’m already experimenting with marrying the two.

All the time I’m facing friction though – if I let Angular do too much, I don’t really have any use for Pedestal. On the other hand, there is quite some impedance mismatch between the Angular “pull-oriented model” and Pedestal’s differential pushes. If I ever come to any sane conclusions on this front I’ll write that up. But that’s another story.

Getting Started with Pedestal on Client Side

I finally got to spend a longer while with Pedestal. It is a pure Clojure web framework, where by pure I mean that you’ll see Clojure on back- as well as front end. For starters I only focused on the front end and that’s what this post is about.

What Is Pedestal?

The documentation is good, but it only explains the fundamental concepts. I think it lacks practical examples and more exhaustive API docs (like inputs and expected outputs of each function, options for each configuration etc.). Or maybe it lacks a tutorial (if I win some time on a lottery, I might write one). There are two good sample applications in their repository: helloworld and chat. Unfortunately, helloworld is very simplistic, and chat is a little bit too complicated for beginners. It does a great job showing off all of the features, but it was a little bit too much for me.

So, after a good while of reading the documentation and reverse engineering the samples, I think I’m finally starting to understand what Pedestal is all about.

On the client side Pedestal is a purely functional, reactive, message-oriented framework. All the state is defined in two pieces: the data model and application model. On the surface each of those models is just a single Clojure map, effectively a tree.

Most of the time you don’t operate on the state directly. You define functions (transforms) that react to messages on specific topics and get current state of data model as argument. They return the new value of the state, and the framework will make it the new data model. Another essential kind of function is emitter: In response to certain messages it emits commands (deltas) to update the application model (like “enable transform”, “disable transform”, “create node”, “set value of node”). Finally, in the application level, you can define functions that change something in the behavior or in DOM in response to those deltas.

Everything goes through this pipeline. If an event happens in GUI, or anywhere in the application, it appends a message to the queue and kicks off all the transforms that bubble up from data model through application model to DOM.

This is a simplistic view that doesn’t do justice to all the features, but I think it’s a good starting point.

Better Sample App for Beginners

During this exploration I wrote another sample application. It’s yet another reincarnation of the TODO app that has a single text entry and a list of everything that has been entered so far. It’s much simpler than the chat demo, and it has plenty of comments explaining what’s going on. This is the kind of application that would help me tremendously during in the learning process, and I hope it saves someone some trouble. You can find the source at Github.

Verdict

My initial verdict of Pedestal? It’s definitely worth a close look! I haven’t built any real apps with it yet, but it looks very promising. It’s a breath of fresh air – I’ve never seen anything similar, especially on the client side with JavaScript. And it feels very appropriate: composed of clean, small, well-defined and isolated pieces with sane flow of information. It appears to lead to much cleaner codebase than JS frameworks like Knockout or Angular with their shared state and dangling functions and callbacks everywhere.