

Detailed Breakdown of a Clojure Web App - nonrecursive
http://www.flyingmachinestudios.com/programming/dissecting-gratefulplace/

======
weavejester
I have a couple of suggestions.

1\. If you return a handler function from a Compojure route, the handler is
evaluated with the request. So:

    
    
        (GET "/" request (posts/all request))
    

Is the same as:

    
    
        (GET "/" [] posts/all)
    

So there's no need for a separate "route" macro.

However, passing the full request map is discouraged, because the more
information you give a function, the more things can theoretically affect it.
Functions should be limited in what they know and what they can do, and this
is one of the principles Compojure is designed around.

2\. Some of the macros you've written for Korma could be written as functions
instead. For example:

    
    
        (defn paginate [query page per-page]
          (-> query (limit per-page) (offset (dec page))))
    
        (post/all (where conditions) (paginate page per-page))

~~~
nonrecursive
Thank you! And thank you for making such great libraries available.

For #1, I definitely started by not passing the full request map but I ended
up finding it cumbersome. On the other hand, my code doesn't really need the
full request map. I'll have another go at it and see how I can improve things
- thanks for the guidance. It feels like a process of over-contraction, then
over-expansion. Hopefully I'll find a happy medium.

For #2 - thank you! I was trying to work toward something like but couldn't
quite get there, so this is great.

~~~
weavejester
Could you give me an example of a route that was particularly messy if you
didn't pass the full request map? Maybe I can suggest a better option (or at
least admit defeat :)

~~~
nonrecursive
You know, I actually can't think of any. I just ended up writing things the
way I did because I anticipated I would want the full request map, but that
assumption hasn't born out. Passing params might be a good way to go. I need
to go back and change this!

------
codewright
This is a pretty interesting post, but I'm seeing a common thread in most
"experience reports" regarding making a webapp in Clojure.

They're all built with with the presumption that the person doing the frontend
work (HTML, CSS, JS) will also be doing the backend (Clojure, database)
coding.

This is almost never the case in my line of work.

Hiccup violates this principle by embedding the html _in my Clojure_ and
Enlive couples markup with data tightly in ways that horrify me.

The only approach I've seen that could work for more serious projects is using
stencil because then the map of data you pass to the template-side is a
'contract' of sorts, but they can work with the data you pass however it works
for them.

That's somewhat regrettable as I prefer Jinja-style templating to mustache,
but Stencil (mustache) is the only viable alternative I've found.

I cannot possibly be the only person with a keen interest in Clojure who
hasn't abandoned division of labor.

~~~
asmala
Based on my experience, Hiccup is more productive than just about anything
else _if_ the frontend person is the backend person or otherwise comfortable
with Clojure. The ability to easily and cleanly define and combine
abstractions in the presentation layer has been big productivity boost for me
as a solo developer.

As a concrete example, a small hobby project I did resulted in a fairly
comprehensive library of Bootstrap helpers with very little effort:

* <https://github.com/asmala/giddyup>

I don't have much experience with Enlive but I find the approach is
intriguing. On paper it seems perfect for clean separation of markup and
logic, but you're right that careless use of the library leads to tight
coupling due to the selector naming. I wonder if it would be possible to
circumvent this issue using custom HTML attributes or even pseudo-CFML custom
tags to indicate logical units in HTML?

~~~
cgrand-net
Enlive's author here. I prefer to think of templates as a mapping between data
and presentation. When the HTML provided by the designers changes drastically
you only need to update selectors in your templates and be done with it. The
same is true of the data you pass to templates: when the schema change you
have to change the template. A template is both a contract on some properties
of the input HTML provided by the designer and on the input data provided by
the logic layer.

~~~
asmala
Gotcha. How would you handle minor HTML changes, e.g. something like this:

    
    
      <!-- Original -->
      <span class="username">joe</span>
      
      <!-- New -->
      <span class="username"><strong>joe</strong></span>
    

Updating the selector in the template is easy enough but seems a bit tedious
if the design team decides to go for italics next week. Another option would
be adding another CSS class or a data attribute to indicate which element
should wrap username.

How do you usually handle such scenarios?

~~~
cgrand-net
By doing such a change they violates their contract. Can't you negotiate an
alternative change? Eg the strong around the span or using styles instead of
strong or move the username class to the strong tag?

Anyway if you really want to program defensively against such changes, roll
your own replacement to content fn which would replace the cornets not of the
current node but of all its terminal descendants.

I'd like to know more about your workflow.

~~~
asmala
My example above was possibly too simplistic. I'm not using Enlive at the
moment but am merely trying to gauge what kinds of contracts would allow the
developers and designers work together most efficiently. I can imagine a
fairly big difference between, for example, the following two contracts:

a) "Don't touch the markup without an explicit agreement between the two of
us."

b) "Please make sure you have an element with a data-content-
for='user.username' somewhere in the HTML."

~~~
cgrand-net
More often than not it's a variation of b) not involving custom attrs (a
matter of taste). It's the same kind of contracts you have to set up if you
are also doing some heavy JS anyway.

Sometimes the design is forced upon the team (eg corporate intranet) and then
one has to resort to ugly and brittle selectors but still I prefer that to
slicing and dicing the design to add loops and conditionals – especially when
the intranet's corporate branding change every 9 months :-/

(Thanks for rewording your reply)

------
irahul
I have used Enlive and I still prefer traditional erb style templates. I
actually use Slim(slim > haml) or Haml, but they are just syntactic sugar.

Enlive, on one hand, allows designers to work on html which doesn't need any
data binding, and then process the plain html. On the other hand, it's tightly
coupled with the markup. A designer can't be sure that changing a class name
or restructuring the markup won't break the templates.

Rolling your own validations might be fun, or it isn't something I want to do
when I am working on a project. I might have rolled out validations from last
project which I can re-use, but I still prefer AR or WTForm validation over
rolling my own(takes time, and if I am in a hurry, ends up not being generic
enough to use in another project). Same goes for pagination. Need pagination?
Here,

    
    
        # Add kaminari https://github.com/amatsuda/kaminari
        
        class UsersController
          def index
            @users = User.order(:name).page params[:page]
          end
        end
    
        # index.html.slim
        = paginate @users
    

Done.

Clojure is a pleasant, expressive and innovative language, but as the blog
post pointed out, the ecosystem isn't vibrant enough yet.

~~~
asmala
Coming from Rails, I tend to agree that the Clojure ecosystem is still less
mature, but not by as much as I initially thought.

Missing Rails I18n, SimpleForm, or validations? Clojure has you covered:

* <https://github.com/ptaoussanis/tower>

* <https://github.com/asmala/clj-simple-form>

* <http://clojurevalidations.info/>

Need more specialized libraries? Take a look at ClojureWerkz:

* <http://clojurewerkz.org/>

Having tried hard to understand the rather labyrinthine source of the original
SimpleForm library, I was astonished by how easy Clojure made writing a
similar library, clj-simple-form. The key contributing factors were Clojure's
emphasis on simple data structures and powerful functions as opposed to
classes, and the ability to pass around functions just like any other objects.
For a lot of projects, I find ease of extensibility to be more important than
ready libraries.

~~~
kinleyd
Clojure does make difficult things easy. And it's getting better and better
with the rapid evolution of new libraries and middleware.

Given one of the core differences in approach, composibility for Clojure and
'convention over configuration' for RoR - I don't think there will ever be a
monolithic RoR equivalent in Clojure. Instead the micro-frameworks that are
emerging are finding their niches, and are being designed from the ground up
to work with other micro-frameworks. Working in tandem these compositions of
micro-frameworks are quickly getting mature and I'm sure will be in the same
league as RoR soon enough.

What I like about this is it allows you to handle Clojure a micro-framework or
middleware at a time. It's easier to digest this way, at least for me: Ring ->
Compojure -> Hiccup - Enlive/Comb/Fleet [x] -> Korma -> Friend, followed by
Domina, Enfocus and others on the ClojureScript side.

[x]: marks where I am.

~~~
kinleyd
I forgot to add to [x]: noir, lein-cljsbuild and clojurescript one; and to the
ClojureScript side: jayq, fetch, waltz and crate.

