My experience of rewriting this website's engine in Haskell was
surprising and disappointing at the same time. What I initially
expected was the heroic quest filled with fierce battles against the
creepy Monads and ending with the Hero (hehe, me) drinking from the
Holy Grail of Catamorphic Wisdom. How it actually turned out is
described in this essay.
At the moment when I decided to create this "antiblogging" website,
under my belt I had around two years of experience programming websites
wanted to try something different. That is why I picked PL/pgSQL
(that's PostgreSQL's flavour of procedural SQL which I never used
before but wanted to try out sometime anyway) for parts of the business
logic and Java (which I programmed before for few years) for the web
Then I put together the website1
. And then I saw every thing that I had made, and, behold, it was very
Except that it wasn't.
Well, PL/pgSQL part was okay. Actually, I have to admit, I like this
language. It is highly specialized in moving values across the
database and isn't suitable for anything else, and still, despite of
it's limitness and COBOL-ish syntax, it is very good for describing
exactly what I want to happen with the data.
Words "exactly what I want" are important here since with Java code,
it just didn't happen. Because those thirty-some classes I've
produced could perhaps match the definition of "what I can live with"
but were nothing near "exactly what I wanted". So I tried to refactor
them. "1000 lines added / 700 lines removed". Better, but still crap,
try again. "600 lines added / 800 lines removed". Even better, but
still bloated, and spending evening after evening after evening doing
this feels boring. Especially when compared to PL/pgSQL part which
remained not just stable but intact because, well, it already did
exactly what I wanted.
I believe, that's a generic problem with Java. Java is bland and
doesn't have powerful syntactic sugar and semantic chilly pepper to
express simple things in a way other than being very verbose, and then
comes a temptation to introduce some utility patterns to help to
describe those simple things in a concise way, and then your "utility"
code is twice as big as the original one, and you want to refactor it
too, and that's a trap! Unless you're not as maniacally obsessed about
the code's clarity as I am. Or unless you (or me or we together) are in
a work environment where there are more interesting things to do than
obsessively polishing a piece of code. But obviously neither of this
applies to my personal hobby projects.
So, at some point I thought about rewriting it in something else,
and I decided to give Haskell a first shot thinking that even if I
don't succeed, at least I will learn some secret knowledge about all
that fancy-shmancy monadic functional programming.
Next comes the list of things that I have actually learned from this
exercise. Also, just to let you know, webapp that served you this page
is written in Haskell, and I intend to wipe all Java sources from
my git repo as soon as I finish writing this essay.
1. Perhaps the most surprising lesson is: while the popular
opinion says that the main reason to pick Haskell is "to have fun
hacking," in fact it's not so fun to hack in Haskell because there's
not such much hacking to do at the first place. For instance, you don't
need to spend lots of effort tracing and fixing obscure bugs, so if
your definition of "hacking" includes heroic bugfixing, you'd be
refactoring, so if you want to have fun doing it, you'd better pick
Java. And if by "hacking" you mean typing in stockpiles of code,
hardly anything beats C for that purpose.
But if you don't really like programming that much any more and
just want a concise program that just works without
putting too much effort into "having fun hacking it together," then you
definitely should consider Haskell or a similar FP language.
2. However, despite the claims from aficionados that Haskell
is a silver bullet that will magically solve all your problems and fix
all your bugs, that's also not true. Haskell is more like a depleted
uranium bullet; it timely detects most of my bugs, though some
occasionally slip in.
But, probably, the most important
lesson for me was
that Haskell port didn't turn out to be an exact 1-to-1 clone of Java
version's functionality. One such difference was usage of intra-process
caches. In Java with DI container backing, it's harmfully easy
to spawn a bunch of "service" classes that hold some chunks of data
inside. In Haskell it's also possible, but must be done in a more
explicit manner and thus feels somewhat messy. So, I wrote a cacheless
version, then tested the performance, saw that it painlessly holds
100 rps without any tuning2
which is more than enough for a personal homepage. And so I purged
all caching-related logic for good.
Was it possible to make these improvements to Java code? Yes,
definitely. Was it possible to consider these improvements to
Java code? Well, this is a very, very, very good question.
"Lack of ecosystem" is what usually shows up in every "Top 5
reasons I'm not going to use Haskell" list. But, at least for web
development, it's not true nowadays. I guess that "nowadays" is the
important word in the previous sentence as this website is built on top
and all of those projects had begun around 2010-2012. So, probably,
building a website in Haskell in 2008 was a different story, but it
was same for
and who cares now?
Today, Haskell has complete stack of whatever you might need to write
a web backend, so "lack of ecosystem" is not a valid excuse anymore.
Not so much surprising to me, but maybe it is for some of
this text's readers, Haskell is not that hard to program in.
For the record, I don't have dual PhDs in computational semiotics and
in abstract algebra, I'm just a humble enterprise/web developer who
never used Haskell to write anything bigger than a Project Euler type
of programs. Still, I can tell you that once you (a)
appreciate the mostly-stateless code with strictly localized mutable
learn to appreciate the compile-time errors4
wrap your head around monads5
then all that's left to do is to memorize syntax and libraries, and I
assume you've done it multiple times before.
In the advertising materials there's much of emphasis
regarding Haskell being "pure" from side effects and from that you
might get an impression that no True Scotsman will (or even
is able to
!) write code with side effects in Haskell6
. That's not true, it's totally possible to write impure code in
Haskell, but there are some tricky details: in a conventional
programming language having side effects is a kind of opt-out7
and there are typically no special notation for it8
. In Haskell, they're opt-in and you must use
to designate it appropriately.
Strong typing is not just about autodetecting bugs you have
I bought myself a textbook on category theory. Just because
Haskell itself is not especially mind-bending.
Just in case if you enjoy reading the lists of Java components used in
this or that application, I've got one for you. Jetty, Velocity, C3P0,
PicoContainer, Ant, Ivy, JUnit, IDEA.
And no, my site is not simple
. It is lightweight
That naturally comes from experience fixing bugs caused by shreds of
mutable state being concealed in the random places of an application.
Think of incorrectly invalidated caches for one example.
That naturally comes from experience fixing run-time
In extreme haste, of course, 'cause they're already in production
and users are unhappy.
Which don't directly correspond to the concepts found in conventional
programming languages. However, once you shake off all that abstract
algebra notions that you have seen in tutorials written by abstract
algebraists and barely understood anyway, and realize that monad isn't
much more than simply a generalization over an idea of a transactional
container, then it gets smooth.
From that people often infer that since most kinds of programs
can't be written in totally side effect-free manner, Haskell is
likely to be not useful for their kinds of problems and avoid it
I.e. you're not forbidden from writing functions that only depend
on input arguments and constants
I struggle to remember anything except