

Lisp Web Tales - lispm
http://lispwebtales.ppenev.com

======
e12e
On the subject of clojure -- is my impression correct in that most (all?) web
framework/templating frameworks for clojure insist on having the templates be
some clojure dsl, rather than "just" "proper" templates (like: eg zope tal)?

All the (admittedly quick, todo-app style) clojure web code I've seen always
seemed fragile in how the template code was interwoven with the rest of the
app (rather than building up a set of values in an environment and compilling
a template with that).

I prefer to have my templates as far separate from the application as makes
sense...

edit: Looks like there's at least laser:
[https://github.com/Raynes/laser](https://github.com/Raynes/laser)

Which seems more like what I want than what I've seen elsewhere.

~~~
cgag
Maybe something like this?
[https://github.com/yogthos/Selmer](https://github.com/yogthos/Selmer)

------
juanre
You don't have to go all the way to full Common Lisp server-side development.
At [http://greaterskies.com](http://greaterskies.com) I wrote in CL the engine
that computes and creates the personalized PDF maps of the sky, then built an
sbcl custom core that's kept listening to a socket. I then manage the httpd
communication with rather simple Python and AJAX, relying in flat files and
static HTML. I am quite happy with the maintainability, and I got to use Lisp
in the part where I could really take advantage of its power and speed.

~~~
pnathan
Wow. That's a really cool site.

~~~
juanre
Thank you very much!

------
taeric
I'm really looking forward to taking a closer look at this. Huge thanks to
whoever posted it!

As an aside, are there any good rundowns of using a LISP for web development?
I don't personally see it recommended/done a lot. Curious if that is just my
exposure, or if it gels with reality.

~~~
danneu
Clojure has been my go-to web dev language for a less than a year.

My Clojure workflow is much better than my Ruby workflow. It's easier to glue
things together. My feedback loops are faster (like being able to eval code in
my source file). The domain is simpler. So are APIs.

You don't hear about people using lisps because the communities are small.
There's a self-fulfilling barrier to entry. And it certainly is a smaller
world. The good part is that the quality/intelligence per capita is high. But
the bad part is that I'm bringing the average down. I definitely feel it in
#clojure.

~~~
147
I tried Clojure out for a while. It's my favorite language.

But I went back to Ruby and Rails for my recent projects and I'm just way
faster at it. It's so much easier to use and the way the gems glue themselves
and integrate with my projects saves so much time.

If there was a way to get something like this in Clojure or Common Lisp (I
haven't tried Common Lisp) then I'd go back to it.

~~~
danneu
Yeah, at first it's much faster to bang out a prototypical CRUD app with
Rails.

`gem install devise`, a few more incantations, and now you've got a full
authentication/forgot-password/email-verification system up and running within
5 minutes. CSRF protection is included with a `protect_from_forgery` link in
the ApplicationController and you don't need to know what CSRF is.

But at a point I find myself at the whim of Devise's Github Wiki to expose the
method I need to override to make a trivial change. And as I diverge from the
base-case of the gems in my Gemfile, I'm spending my time credentializing in
gem source code to do trivial things. I need to make what should be a 5 second
change to an API endpoint, but we used RABL because it was easy and now I'm
back on its Github page hunting down its API doc.

Those chickens had never really come home to roost until I was a full-time
Rails developer working on a monolithic app where my days became squandered to
pay back technical debt by specializing in the intersection of codebases that
were not my own.

That's what brought me to Clojure which I was pretty much sold on after
reading about Ring ([https://github.com/ring-
clojure/ring/wiki/Concepts](https://github.com/ring-
clojure/ring/wiki/Concepts)). A request is just map. Your app is just a series
of functions that transform that map. And a response map comes out the other
side.

In Rails, to reset a session, you call a magical method `reset_session`.

With Ring, you return the response map with its `:session` key set to `nil`.

Implementing features is much more obvious now. The hard part is figuring out
how to structure and fit together the app. Especially since Rails made most of
those decisions for me.

I started building a forum with Clojure and Datomic:
[https://github.com/danneu/clj-forum](https://github.com/danneu/clj-forum)

My goal is to eventually arrive at a webapp structure that I can replicate in
future Clojure webapps.

I don't really know how to use Datomic or how to organize my code or what
abstractions will work, but I have a clay-ball approach to it all where I just
do what's good enough now and refine it later.

But it's coming together.

If you start in the handler ([https://github.com/danneu/clj-
forum/blob/master/src/clj/foru...](https://github.com/danneu/clj-
forum/blob/master/src/clj/forum/handler.clj)), you can get a sense of what's
going on.

\- Here's an attempt at recreating some of the Ruby CanCan authorization lib:
[https://github.com/danneu/clj-
forum/blob/9c0d2b8f17acc06da9a...](https://github.com/danneu/clj-
forum/blob/9c0d2b8f17acc06da9a59db72f6f63d73cc18b26/src/clj/forum/cancan.clj)

\- And here are the tests for it: [https://github.com/danneu/clj-
forum/blob/9c0d2b8f17acc06da9a...](https://github.com/danneu/clj-
forum/blob/9c0d2b8f17acc06da9a59db72f6f63d73cc18b26/test/forum/cancan_test.clj)

Yeah, that was a longer post than I thought I'd write but I've been alone in
my Clojure cave for a while now, complecting.

~~~
joesb
So, in the end, do you get all the feature of Devise back with Clojure (and
its library, of course). Do you have to reimplement CSRF _correctly_ yourself?

What you describe about Rails is a problem with using third party
library/framework in _any_ languages. I don't know how you can avoid that in
Clojure.

~~~
danneu
The difference is that Rails and the popular gems involve some of the highest
abstractions I've ever used. It's like that by design. There's nothing
inherently bad about it.

Here's the typical workflow for adding a gem:

    
    
        1. Add "gem 'some_library'" to Gemfile
        2. `bundle install`
        3. Drop the 'some_library_method!' incantation where you need to.
    

Here are the steps for Devise's base-case (I only use Devise as an example for
a broader point):

    
    
        1. echo 'gem "devise"' >> Gemfile
        2. `rails generate devise:install`
        3. `rails generate devise User`
        4. `rails generate devise:views`
    

Boom. It's awesome.

The trade-off is that now your entire authentication system is hidden behind
line 37 of your Gemfile. And that's Devise's purpose - to be that abstract.
And on many projects that's perfectly fine.

Of course, you can roll your own authentication in Rails. It's easy. It's not
like you have to use Devise or a daisy-chain of opaque libraries.

But I find it nontrivial to understand what Rails does behind the scenes. Or
what `require "activerecord"` in Sinatra does behind the scenes. Or how to
recreate a state of my application. Or how to test things without a testing
abstraction. And I didn't really care until I started to care.

Ring's functional abstraction has helped me remain aware of what my
application is doing. My application state is annotated clearly as `(def
^:dynamic _current-user_ )` which is bound to every request by plucking the
value of the `:session` key out of the request map. My application is now a
function that's applied to a map.

    
    
         (app {:uri "http://localhost", :port 3000, :body ...})
    

Where `app` is just a var that's bound in my source code:

    
    
        (def app 
          (-> my-routes
              middleware1
              middleware2
              middleware3))
    

Each of those just a function that's trivial to understand. Trivial to modify.
Pure or trivial to mock pure if I need to mock its components.

    
    
        > So, in the end, do you get all the feature of Devise back with Clojure (and
        > its library, of course). Do you have to reimplement CSRF correctly yourself?
    

Over the course of a software project, interacting with existing code and
getting existing code to interact with other code dominates more and more of
your day-to-day.

In other words, `devise install full-stack-authentication-system` optimizes
for the only easy part of software: greenfielding it in the first place.

It buffers you from having to understand it. In fact, the mantra is that
you're supposedly stamping out the specter of NIH and deferring the hard stuff
to smarter people. But too often I find that the fear of NIH is bolstered as
some unconditional ostensible virtue used to justify a system that's hard to
tweak because so much of it is hidden away. Or worse yet, it enables you to be
wildly productive without ever having to know what CSRF even is. Or it lets
you assume that authentication, CSRF protection, and password encryption are
all significantly hard problems that you probably wouldn't be able to
underestand.

Yehuda Katz presents a talk at Railsberry 2012 entitled "Why Rails Is Hard."

[http://www.youtube.com/watch?v=2Ex8EEv-
WPs](http://www.youtube.com/watch?v=2Ex8EEv-WPs)

He explains that you don't need to worry about things like CSRF protection
because the entire concern is abstracted into the ApplicationController method
`protect_from_forgery`.

And his key assertion is that an application framework's security shouldn't be
deferred to the end-user (the developer). It shouldn't be opt-in for the few
that run the gauntlet of reading the documentation. People don't dive into
your documentation. I don't. I'm all about that `## Usage` heading in your
Github project's README. Once you give me the incantation to install and
require a library, I bounce.

He says that he doesn't want to worry about the order of anti-forgery
middleware every time he's cranking out an application.

I generally agree with him. I think Rails should provide those abstractions.

However, I went a comically long time without caring what
`protect_from_forgery` was. Or what CSRF was. Or what a password salt was.
They were probably sophisticated things.

And by not caring, I indeed was able to focus on software and getting better
at building applications and learning how to code. CSRF is an acronym I
certainly can defer to a future date or Yehuda Katz when I'm still learning
how to even get a datastore, an authentication system, an authorization
system, a user system, a forum system to all intermingle from the highest
level.

But more importantly, I went a long time without even knowing enough to
implement these things myself.

I didn't know that `GET /logout` was a bad idea. Or that someone could make
their forum avatar into `<img src="/logout">` and log out every single person
that viewed it. Or that CSRF protection doesn't protect that.

Sheepishly, it wasn't until relatively recently that I started to learn these
things. And I'm fortunate that I have a lot of time to learn them. I'm 25 with
no wife or children but with the freetime to begin learning from scratch all
the things I've deferred for so long. Not everyone has that. That's why all of
the above is a personal expression that I should've told from the first
person.

I certainly don't think I'm some sort of transcendental security wizard
because I finally know what the `__anti_forgery_token` is. Or because I could
google "github ring csrf protection" and find a Clojure library and add it to
my dependencies. But I have finally started to understand how my software
works. And I've discovered that things like password encryption and CSRF
protection aren't exactly mystifying. And I can read some simple functional
Clojure source-code that makes is obvious to me because I can replicate it in
the repl.

Yehuda Katz is right in that I probably wont know about the next CSRF edge-
case exploit as it's known. Nor will I notice that my ring.util.wrap-anti-
forgery dependency was updated and I need to bump the version. Nor will you
see an impenetrable fortress if you visit that repo I linked in my last post.
It's far from that and far from complete.

But it's an iterative learning process, and Ring's simple functional
abstraction and the a la carte nature of Clojure libraries and how simple they
are to glue together due to their reluctance to mutate state helped make it
trivial for me to see how things fit together from a slightly less concealing
abstraction.

As I work on my app, I'd like to work towards my own web-stack template that's
robust and transparent for me to understand. And for all I know, I'm probably
not much different than DHH hacking on Ruby pre-Rails or any other person
that's ever cobbled together their own abstraction. Maybe in half a year I'll
have just arrived at Clojure on Clails. I just feel late to the party.

(I didn't mean to focus so much on security, but this applies to the whole
surface area of abstractions that might do too much. Like
[https://github.com/bernat/best_in_place](https://github.com/bernat/best_in_place),
a library that handles inplace-editing and even the Ajax request that saves
it. Of course, your appetite for technical debt varies wildly from project to
project.)

------
georgismilyanov
i would be curious to learn more about you, Pavel. what do you study? are you
from Bulgaria?

------
tambourine_man
Unreadable on the iPhone (iOS 7)

~~~
osivertsson
Unfortunately unreadable on my Android-based Sony PRS-T1 too. Text is aligned
too far to the left, leading to some of it being cropped.

Interesting topic though, I'll revisit it when I have access to my workstation
again. Thank you for posting.

