Hacker News new | past | comments | ask | show | jobs | submit login
Lisp Web Tales (ppenev.com)
111 points by lispm on Oct 11, 2013 | hide | past | favorite | 31 comments



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

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


Maybe something like this? https://github.com/yogthos/Selmer


You don't have to go all the way to full Common Lisp server-side development. At 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.


Wow. That's a really cool site.


Thank you very much!


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.


I find it a little ironic that no-one's mentioned Arc yet:

http://arclanguage.org/

Personally, I've never quite "gotten started" with lisp (neither cl or scheme) -- and while I don't know if I'd recommend Arc -- the system on which it is built, which has evolved into racket:

http://www.racket-lang.org

Is as far as I can tell, really, really good. Both the implementation, the tooling, the documentation and the community.

For more on racket and web:

http://docs.racket-lang.org/web-server/

See also: http://stackoverflow.com/questions/4285617/how-do-i-install-...

The hype definitely seems to be on the side of clojure, and clojure+leiningen (the build system) gains quite a few advantages from running on top of the jvm. My guess is that you'll find a lot more libraries and code for using clojure for web programming than probably any other lisp -- and code that people are invested in at that (code that people depend on for running their own projects/businesses etc).


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.


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.


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

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

- And here are the tests for it: https://github.com/danneu/clj-forum/blob/9c0d2b8f17acc06da9a...

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.


Ring is like Python's WSGI and Ruby's Rack. There are some Common Lisp libraries like it as well: Clack - https://github.com/fukamachi/clack cl-ring - https://github.com/AndreasKostler/cl-ring


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.


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


> But the bad part is that I'm bringing the average down. I definitely feel it in #clojure.

Me too, my friend, me too.


It's definitely good for prototyping. However, the real question is whether you're going to build it alone or have any plans to build a team around it and such. If the latter is the case, think twice.


Is this feeling just because there is a larger pool of choices that know other options? Or do you feel LISP is actually a bad choice for large teams?


Lisp is a good choice for any team, as long as your team agrees with your choice.

It's all about attitude. With Ruby/Python/PHP people rarely express strong sentiments over the language choice. Typically, you can easily convince the team going this or that way, depending on the task. Everybody understands those are just tools.

However, when it comes to non-mainstream languages such as Lisp, people become more galvanized. Negative sentiments are likely to shift from 'meh, whatever' to 'you must be mad'.

That's why I say think twice. You might alienate some people -- if that's something you care about.


But then the people you do hire are super into it. I can't imagine there are many people using a lisp at work begrudgingly when there are so many people who'd love to get to use it professionally.


I think it's partly to do with the extreme flexibility of the language. When you have a large team programming in Java, you pretty much know that they're all going to be programming in roughly the same style. eg. They'll obviously be object oriented, they'll use the same major libraries, they'll be focusing on the design patterns, etc...

Whereas in the Lisp world, you have so much flexibility that you can end up with all sorts: some people doing pure functional code, some OO, some using tail recursion wherever possible vs. some preferring more explicit representations, some going heavy on the macros, some using LOOP, some preferring recursive mappings of anonymous functions, etc...

Ultimately, this can be fixed by using a decent style guide. Google has a good example since they acquired ITA:

http://google-styleguide.googlecode.com/svn/trunk/lispguide....

In other languages it isn't so much of a problem - eg. I'm thinking of Python as an example where you are strongly encouraged that there is "only one way to do it".

However, if you recognise from the beginning that you need to enforce a decent style guide, then I see no reason why large Lisp teams couldn't work.


I think this demonstrates just how much the growth of real software engineering has been stunted by half-solutions (like Java, and other mainstream languages).

It's exciting! In the case of Lisp, it's not just about enforcing styles, but (as a team) coming up with the appropriate DSL for the task at hand. The classic 'bottom-up' paradigm (http://www.paulgraham.com/progbot.html), but done collaboratively.

The analog has been done to death in object oriented languages, with concepts such as design patterns and frameworks. I'd love to see similar developments in a meta-language like Lisp, and with all the (potential) power that entails...


AFAICT, Clojure has a big following in the big data & web areas.

I'm working on a side project, using Common Lisp for a webapp. So far it's nice. General reports indicate that current open source Lisp systems works reasonably well under smaller load.


Clojure has done a lot in this area on both the server- and client-side.


Suppose one does not want to marry the JVM. Why not Lisp?


If you're interested in Clojure but want to avoid the JVM, then I would think Scheme would be the better choice than Common Lisp since it's functional like Clojure.


Of course, if you want lispyness while retaining the freedom to choose an imperative style or a functional style, Common Lisp is better.


Both Scheme and Common Lisp support imperative and functional programming styles. The Scheme community has historically been perhaps more dogmatic about sticking to functional programming, and so Common Lisp has built up more tools and idioms around imperative (and object-oriented) programming. But as someone who has used both Scheme and Common Lisp a fair bit, this doesn't seem like one of the dominant criteria for choosing between them for practical programming work.


... or ClojureScript and NodeJS

EDIT: Actually the JVM is still involved but just for compilation.


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


Unreadable on the iPhone (iOS 7)


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.


Try reloading the page with the phone in landscape orientation.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: