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

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, 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.)