
The Haskell / Snap ecosystem is as productive (or more) than Ruby/Rails. - T_S_
http://blog.dbpatterson.com/post/21885034168
======
cageface
_Having a compiler that will tell you all the places that you need to change
things is an amazing productivity booster._

Agree with this 100%. I think dynamically typed languages are a transitional
technology we'll mostly leave behind as the kinks get worked out of modern
type systems.

~~~
grey-area
It would have been interesting (and perhaps a little more convincing) to see
some examples of the Haskell type system boosting productivity in such a
dramatic way.

I can count on one hand the number of type issues which have caused trouble
for me in Ruby over > 5 years of producing complex systems with it. I haven't
used Haskell though so would be interested to see some examples of this. If
his audience is Ruby users, it is not very informative to just say it is
better in a general way. The main point of comparison in the article point 1
seems to be with unit tests, however there are no concrete examples given of a
failing test from a real program where types would have helped. A strong type
system adds friction and verbosity, so it would need to come with a lot of
advantages for me to prefer it to Ruby, which will not allow something like 2
+ "2" but does try to get out of your way as much as possible.

It's quite hard to compare type systems as they vary so much but at least here
is he comparing just two systems Ruby/Haskell, so comparisons can be
straightforward examples of situations where types have caused him trouble
with direct comparisons. I'd be interested to see an example of something like
a telephone number (from untrusted user input) where the Haskell type system
is superior to having some checks on formatting, and an explanation for those
less familiar with Haskell of what advantages the type system gives.

~~~
chc
The thing is, it's not that straightforward. It's not about avoiding type
errors that would have cropped up in Ruby, but about getting the type system
to encode as much of your program's semantics as possible. For example, in
Ruby, you use strings and symbols for a lot of disparate things. In Haskell,
you'd introduce a type for each purpose to encode your intent in a way the
compiler understands†. In Haskell, you're actually going out of your way to
create more potential type errors, because that's more stuff the compiler can
check for you.

† _Concrete example off the top of my head: In Ruby, we do
`foo.instance_variable_get(:@bar)`. If we accidentally write
`foo.instance_variable_get(:bar)`, that's a hard error, but it isn't a type
error. Haskellers would generally express a constraint like that with the type
system, so the compiler would let them know when they made such a mistake._

(Also, don't forget that every unintended nil is a type error! If you've been
doing heavy Ruby work for years and gotten fewer than six NoMethodErrors, I
will hang my head in shame.)

~~~
mtrimpe
I agree very much.

As far as I'm concerned Java's biggest failure, orders of magnitude worse than
all others, is to make java.lang.String a final class.

~~~
masklinn
I don't know:

1\. having nullable references by default strikes me as a bigger issue

2\. I don't see any reason I'd want to _subclass_ String, actually (though I
could see wanting to create an alternate implementation e.g. ropes-based). So
String being a final class makes perfect sense as far as I'm concerned (unless
it were an interface or some sort of "proxy" class as is often done in Cocoa).
On the other hand, I'd give a phalange to easily create an _unrelated_ type
(typesystem-wise) with the same implementation. What `newtype` provides in
Haskell.

~~~
riffraff
how would a nominally different string type be better than wrapping the string
?

I mean I understand why having a Name, ZipCode or UUID stringish class helps
ensure program correctness, I do not understand (out of ignorance) how it
would improve your code vs a wrapper.

~~~
masklinn
> how would a nominally different string type be better than wrapping the
> string ?

* It is significantly less verbose, therefore simpler and more likely to be used at all. And less error-prone

* It can provide string APIs working on itself (either by default or through the aliasing declaration) precluding the need to manually re-implement things like comparisons or printing

------
danneu
I've been learning Haskell on the side for a while and was hoping for
something more after reading the title, but the post pretty much just points
out a few preferences that OP has.

I spend very little time in Rails hung up on any of the issues expressed.

With some experience with frameworks like Express/Noir/Sinatra, I find that
Rails is productive for me because of (A) convention and (B) getting common
things done with terse code like `belongs_to :forum, counter_cache: true,
touch: true`, and (C) not having to write glue code for basic things.

This quote...

> In addition, there is also very little “convention” with Snap. It enforces
> nothing, which has the consequence (in addition to allowing you to make a
> mess!) of having the whole application conforming to exactly how you think
> it should be organized.

...is precisely the deal breaker for me. If OP thinks it's hard to add/edit
Rails code because it's spread out, then a lack of convention suddenly isn't a
very compelling scenario for productivity. At least you know where to look.

I've been in a Node.js kick recently, consuming a lot of Express-stack repos
on Github of smart people, and the experience is baffling. Deciding where to
put code in my application just isn't a problem I want to solve when I'm
trying to write a non-trivial, non-single-paged application.

~~~
carterschonwald
I'm slightly confused by this. Is it not the case with rails that many of the
.rb files are generated via rails?

I think you're over thinking / pessimizing what happens with haskell code.

1) for any self contained project (library or executable) in haskell, the
directory structure determines the module names. if you're wondering how the
functions imported from the Foo.Bar module are implemented you simply go to
the subdir #root/Foo/Bar.hs

2) Types. when you're writing use case specific code, you are going to define
use case specific types, and they will be declared. More over, it is good
practice to give explicit type ascriptions to haskell code to make sure that
it does in fact have the type you expect. This means that you can jump into a
module and by also recursively looking at its imports (and you know where
those are in the fs), you can figure out exactly whats going on.

3) cabal-install (cabal), and your project specific project.cabal file make
life great. Why? the foo.cabal file will tell you which module has the Main
function if you're making an executable, what other packages (and their
versions) your code might be importing, which language extensions are enabled,
etc.

Point being, there are no need for "framework specific conventions" of the
sort you're concerned about because those problems are solved by Haskell
specific conventions :)

~~~
danneu
I mean to specify higher level design conventions, as in the structuring
decisions you'd have to make in a non-trivial app.

For instance, my experience with Express. The popular Peepcode screencast
makes a Django'esque `apps` directory and modularizes the granular components
of the entire app. Other people make an `app` directory and model the familiar
Rails MVC. Some people contain controller logic in the router. Some people
export routes from smaller files into app.js under a `//routes` comment.
Sometimes the connection to the database is bootstrapped when the server
starts in app.js. Sometimes the database is accessed from each model.
Sometimes the database is accessed from each route. And you're guaranteed to
have to dig into every required file to see how they exposed its API. Did they
module.exports the entire object? Or did they individually export each public
method?

See, I'm not criticizing unopinionated frameworks. They're for people that are
opinionated and want to write the code that glues their opinionated structure
together. Or for apps small enough to get by without deliberated structure.

But in a discussion about productivity, perhaps there's something to be said
when people with experience making non-trivial apps have corroborated
conventions and practices for a community to share.

------
wylie
This article was interesting, having only used frameworks that either do
everything or just the minimum (think Rails vs Sinatra, or Django vs Tornado).
I was beginning to wonder if there was a middle ground in web frameworks. The
idea of a web library, not a framework, really appeals to me. Is there
anything like Snap for Python or Ruby?

~~~
jvdongen
I've noted that split as well - and wondered indeed if there is no middle
ground. Recently it occurred to me that perhaps there is no real need for that
middle ground.

The fact that Django comes with even more batteries included than Python
itself does not mean you have to use each and every battery. And ignoring
stuff you don't need is often easier than extending an even moderately complex
'middle ground framework' in a meaningful way without making a mess of it.

If I compare that to my own experience, that is exactly what I've started to
do over time.

A thing I've become accustomed to is splitting my applications cleanly in
'front-end' (focus on interaction with humans) and 'backend' (focus on
business logic, (persistent) state and interaction with other
applications/machines).

For front-end applications I've no real need for a number of things Django
offers (ORM, authentication/authorization mostly). For building back-end
applications Django has even more bits I do not really need.

This lead to a situation where I asked myself 'what does Django still offer
me? Is it not easier to use a more limited framework for either use case or
gobble together my own frameworks from various bits and pieces?'.

For front-end applications I could've (and have tried to) build a framework-
to-fit from various bits and pieces such as cherrypy, jinja for templating,
babel for i18n, routes for routing, etc. However creating a solid working
framework this way, with all bits working together nicely - and keeping up to
date with the development of its various bits and pieces - is a lot of work.
Just using Django an ignoring the bits I don't need turned out to be far
easier, leaving more time spending on my actual problem.

And for building my backend-applications I don't need all the stuff listed
above - I simply need a robust and reasonable fast networked server which can
host my business logic. The 'minimalist' frameworks then offer just what I
need without getting in the way too much.

So in conclusion: if you want to build something that is mostly logic with a
machine-machine interface, the minimalist frameworks offer a solid foundation
and you have no real need for all the extras a 'mega framework' or even a
'middle ground framework' offers you. If you want to build something that has
to interact with humans, you actually do need most of what the prevailing
'mega frameworks' offer you and leaving out the bits you don't want is easy.
Hence there is no real need for 'middle ground' frameworks.

------
vitomd
Learning Haskell will improve your overall programming skill, it will change
your mind. The best tutorial to learn Haskell: <http://learnyouahaskell.com/>
.And it is the tutorial that I enjoy the most (including tutorials ruby, php,
backbone, jquery, etc)

------
bfung
Some source code is worth a (three) thousand (fourteen) words ... =P

~~~
batista
And a couple of finished products, well, web-apps or web-sites in this case,
even more.

------
danssig
Not a single line of code to illustrate the point? Not even one?

~~~
mratzloff
I was coming in to write this. Rule #1 for these kinds of blog posts: include
code samples! Sometimes I want to read long, detailed articles. Other times I
just want to look at the "pretty pictures", so to speak.

~~~
romaniv
When discussing structural issues, like routing, code samples will be either
deceiving or extremely verbose, because the ideas like that involve
interaction of multiple components that simply doesn't happen in "hello world"
examples.

~~~
mightybyte
Yep, the same is true of the benefit static typing gives you for refactoring.
Real world examples where the benefit is really significant are too big to put
in a blog post. It should not require too much imagination to make the point
clear to an experienced developer.

------
delinka
OT: The title of this article without the parenthesized would be "...as
productive than Ruby/Rails." Want a more link-baity title? Try "...more
productive than Ruby/Rails?" making it a question. Not so baity, but with Moar
English? "...at least as productive as..."

This goes back to my little rant from last week: Please proof read your blog
posts. In this case, reread the title with and without the parenthesized
modifications and see if the English still holds together.

------
nnethercote
The single sentence that surprised me the most:

"For performance, there is no question that Haskell will win hands down on any
performance comparison".

~~~
tikhonj
Why is that surprising?

Haskell is a compiled language with a _very_ clever optimizing compiler, so it
tends to be pretty fast by any standard. On top of this, it has recently had
some improvements to its IO manager which is particularly important for web
servers.

Ruby, on the other hand, is notoriously slow.

~~~
zoul
Performance isn’t measured just by the language tools, it depends on the whole
stack. It’s quite probable that the Ruby/Rails stack is better suited to high-
performance sites simply because it has more installations and the kinks have
been worked out.

~~~
lincolnq
I agree that the priors would suggest that you are correct, however, let me
give some evidence to update you:

The Warp web server for Haskell is the fastest Web application server _that
exists_. [http://steve.vinoski.net/pdf/IC-
Warp_a_Haskell_Web_Server.pd...](http://steve.vinoski.net/pdf/IC-
Warp_a_Haskell_Web_Server.pdf) [pdf, but easy to read] -- in the comparison on
page 2, php handled 3400 requests per second, and Warp 81000.

~~~
yxhuvud
Uh. This doesn't make any sense whatsoever.

As to why, here is a hint: The three most common webservers in the world are
Apache, nginx and IIS. Yet are any of those even mentioned in that paper? NO.

~~~
lincolnq
Hm, you may be right. The methodology to arrive at these results in the paper
is not given at all (as far as I can tell).

However I suspect that the three you listed would not be benchmarked on their
own, as they are not application servers, just frontends. It would be more
reasonable to benchmark Apache+mod_wsgi or whatever, and it would be nice to
see that on the graph.

------
islon
title: "The Haskell / Snap ecosystem is as productive (or more) than
Ruby/Rails." bio: "...computer programmer and web designer, who is interested
in the intersection of mathematics and computer science..."

Old stereotypes die hard.

------
BadCRC
I really hope Haskell/Snap starts getting picked up by everyday web developers
so someone can start exposing ridiculous things like:

    
    
      > 11111111111111111111111111111 - (length [])
      => 1729917383

~~~
getsat
Can someone explain what is happening in this example? I'm learning Haskell
right now and this makes no sense.

~~~
lincolnq

        Prelude> :t 11111111111111111111111
        11111111111111111111111 :: Num a => a
        Prelude> :t (length [])
        (length []) :: Int
        Prelude> 11111111111111111111111111111 - (length [])
        1729917383
        Prelude> 1111111111111111111111111111 - 0
        1111111111111111111111111111
        Prelude> 1111111111111111111111111111 - fromIntegral (length [])
        1111111111111111111111111111
        Prelude> 11111111111111111111111111111 :: Int
        1729917383
    

"Int" is the machine-length integer type. "Integer" is the unbounded, but
slower integer type ("bigint" in other languages). In Prelude, "length" always
returns an Int, assuming that the length of a list will never be bigger than 2
__32.

Haskell interprets numeric literals as the typeclass (Num a => a), meaning any
member of the typeclass Num can be constructed using these literals. Int is
one such type, and causes wraparound when it constructs an instance using the
typeclass.

~~~
zopa
_assuming that the length of a list will never be bigger than 232_

Should be 2^32, of course. Though I think the real upper bound is (2^31)-1:
there's a bit used for negative numbers, and there's zero.

------
VeejayRampay
My language.

It's better than your language.

Ergo, you should use my language.

Rinse and repeat with any choice of languages.

------
vjeux
Where are the benchmarks?

~~~
DanWaterworth
Here [http://shootout.alioth.debian.org/u32/which-programming-
lang...](http://shootout.alioth.debian.org/u32/which-programming-languages-
are-fastest.php?ghc=on&jruby=on&yarv=on&calc=chart)

~~~
tikhonj
I think he wants the server benchmarks in particular rather than general
speed.

I found some on the Snap framework web site[1], but they may be a little out
of date.

[1]: <http://snapframework.com/blog/2010/11/17/snap-0.3-benchmarks>

~~~
DanWaterworth
Let's be clear, the article is comparison between frameworks. The benchmarks
should therefore reflect the comparative speed of the same web application
written using both rails and snap. I'm not aware of any attempt to do this, so
I attempted to approximate it using the speed of the language in general and
you can see that from the results I posted that the slowest Haskell GHC is
faster than the 25% percentile of MRI ruby 1.9. This is a useful observation;
A simple pong benchmark has absolutely no bearing whatsoever.

------
fusiongyro
Let's not downplay the few years you'll need to spend to get productive with
Haskell first.

------
batista
Until it has produced as many sites, I consider any such statements as
anecdotal.

That is, I'd rather measure a system's productivity with actual production in
the wild than with any of the systems "inherent" capabilities.

It might be productive for the author, but I don't see the general web
programming public finding it more productive. People have learned Ruby to use
Rails, but not many have ventured to learn Haskell to use its frameworks.

~~~
Marwy
It's not as popular therefore it's not as good. Your logic is definitely
valid!

~~~
batista
_> It's not as popular therefore it's not as good. Your logic is definitely
valid!_

And your logic is definitely faulty. I've never used the word "good"

What I said is "more productive" (what the author claims) can only be measured
in actual PRODUCTION.

That is, the important thing is not:

(a) "If I were to use X framework/language, how productive would I be over Y
framework/language?",

but:

(b) "In an actual empirical observation, what framework/language is actually
responsible for the largest volume of production?"

The author talks about (a), and advocates Haskell. But that is not an
empirical, scientific, measurable observation, it's just his personal
opinions, feelings and anecdotes. Only (b) gives an actual overall metric of
the productivity of two frameworks/languages combos.

Even having the same person doing the exact same project with both X and Y
framework/languages and comparing the speed with which each was done, would
tell us very little. Maybe someone he was more comfortable with one or the
other, maybe that particular project fitted especially X over Y, maybe it
didn't need to communicate with legacy stuff with neither X nor Y do well,
etc.

The only way to tell what generally was for production for the majority of
people, is to, DUH, see what the majority of people have used for their
productions.

