Don’t Believe the HypePosted: October 3, 2008
I should begin this with a disclaimer: while I normally try to make these posts well thought-out and to stick to subjects I know a lot about, this time around I’ll be getting a little less neutral and talking a little more about things I have limited experience with. I’m not a functional programming guy, and I’ve never programmed extensively in any sort of functional language. I’ve also never actually tried to write anything serious in Erlang or Haskell or Scala, and the only time I wrote in any kind of Lisp was for one class back in college. I am, in other words, probably not qualified to have the kinds of opinions I have. And of course, as someone pushing a new, as-yet-unreleased language with a more traditional imperative programming model and syntax, my opinions are naturally biased.
But well-founded or not, I do have strong opinions, and the seeming constant parade of blog posts over the last year or two about the rise of functional languages and the coming multi-core apocalypse really kind of annoys me. I think they do a lot more harm than good by focusing too much time and energy on problems that seem “cool” to solve but are largely irrelevant for most developers, and I think they’re generally symptomatic of the fact that a lot of engineers like trying out new toys and enjoy thinking about clever, cool solutions to hypothetical problems sometimes more than they like actually solving real-world ones. To that end, here are the developer hype bubbles I’d most like to see burst.
Multiple Cores And Cloud Computing Will Not Fundamentally Change Programming Languages
This seems to be the primary driver behind a few other misconceptions that I’ll get to next, but the bottom line to me is that programming languages themselves are not going to be heavily affected by the increasing number of desktop cores or the increasing move toward cloud computing. There are several reasons for that. First of all, most web applications already parallelize pretty obviously at the request level. Whatever language you’re writing in, you can spawn a thread or a process per user request (or pool them), and continue on your merry way worrying about threading only when you need to access something like a shared cache. That level of concurrency is already taken for granted by everyone, and generally lets web applications scale up to make use of N processors/cores where N is the number of active users at any one time (ignoring blocking IO and memory constraints, etc.). But after that, it’s generally difficult to parallelize: if your request looks like “add a record to the User table, then read the list of current users and render them to the UI” it’s just not easy to figure out how to parallelize. Could you read data while you’re updating? Maybe, if you have to read some bits of data that you know won’t be updated, or if you can later merge in the results of what you updated. Could you render different parts of the template in parallel? Sure, provided that you knew those parts didn’t interact and had some good way to stitch them back together later, and assuming you wanted to buffer the page in-memory instead of writing straight to the response stream in sequence. At most you could, with a lot of effort, find a way to use an extra core or two here or there. But you’re not suddenly going to make your request->action->response loop use N threads for a single user.
Likewise, desktop applications aren’t going to get all that much more parallel. Game developers already have a tough time using more than a few cores; look at how hard fully utilizing the PS3 is for people. Likewise, iTunes and Windows Media probably aren’t going to start using 16 cores any time soon, and neither is Word or Quicken. Could certain tasks occasionally be split up and parallelized? Sure. But the vast majority of the application code will remain relatively sequential.
In other words, the inability of most programs to take advantage of an arbitrary number of cores is inherent to the problem space, not the result of a lack of proper tools or languages. You could have the best language support for concurrency in the world and it wouldn’t make parallelizing page rendering any easier because you’d still need to do the hard work of figuring out which parts were independent.
The primary ways in which the new multi-core processors will be used will be to 1) offload desktop apps into the cloud, where per-user parallelism is an obvious win by allowing one server to handle work for multiple users, and 2) frameworks that allow for easy parallelism for certain parts of applications, the way web-servers make it easy to parallelize requests per user. But those frameworks really won’t depend too much on underlying language support, at least not to the level that will restrict them only to certain languages (certain languages might do it better, of course, but the bar will really be “good enough” not “optimal”).
There are some problems that lend themselves to parallelism, and those will benefit from more cores and from languages specifically suited to that situation. But for the majority of programmers writing the majority of programs, there’s just not going to be any fundamental shift in how programs are written, regardless of what the hardware guys keep saying. There will be a shift in the frameworks and, more importantly, in where the programs are deployed and run, but not so much in how they’re written.
You’re Not Going To Have To Scale That Much
The Ruby guys have been saying this for a while, every time someone complains that Rails isn’t fast enough: most people just don’t have to scale that much, and those people that do can just add a few more processors or servers. Cloud computing and multi-core processors make that even easier, meaning you have to worry less about some performance issues. Google and Facebook and eBay might have to deal with volumes of data and user requests that make your eyes bug out, but again, they’re an incredibly small subset of the programming population. Scaling to those levels requires some serious black magic and some major architectural changes, but working with those constraints makes everything far more difficult, so you naturally don’t want to impose them on yourself if you don’t have to. Most smaller web-applications can get away with a database server or two and horizontal scaling of servers as they add more users; again, per-use parallelism makes that fairly easy. Scaling at that level still isn’t trivial (you have to load test, know how to performance tune, index properly, optimize queries, and do a ton of caching), but it doesn’t require you to fundamentally build everything with scaling up to 100 million users in mind. Step 1: Build something that works. Step 2: Make it fast enough for your users. Step 3: Worry about scaling to 100 million users when it becomes apparent that you might actually have 100 million users instead of just 100.
Erlang Is Not Going Mainstream
So those two general observations bring me to the point that Erlang isn’t going anywhere. It’s rightly getting attention as a great language to write programs that are massively parallelizable and fault-tolerant (in the sense that individual processes can die and be restarted). But otherwise, the syntax is fairly primitive and restrictive compared to any modern programming language, the tools and libraries are as well, and no one is going to start writing their web application in Erlang instead of using Rails or Django or even ASP.NET, unless they’re doing it just to show off that, “Hey, look, I wrote something in Erlang!” The benefits of the language are negligible for most standard applications. If you need to scale up to 100 million users, would the concurrency advantages potentially outweigh the language disadvantages? Sure. If you’re writing a back-end transaction processing system for a bank, or an instant messaging server that’ll need to handle hundreds of thousands of users, should you consider Erlang? Definitely. Will more than about 1% of software projects benefit from using Erlang? Nope.
Functional Programming Is Not Going Mainstream
Which brings me to a related point, which is that functional programming in general is not going mainstream either. Will languages like Ruby and Python that have some functional ideas in them get more popular? Probably. Will Java potentially add some better functional support? Hopefully. Will “mainstream” developers start writing in Lisp or Haskell or Erlang any other the other functional languages out there? Not a chance. Why not? My theory is that most people just don’t think that way. The real world is imperative and largely sequential; people can really only do one thing at a time, and then do them in order. So if you’re going to make a pb&j sandwich you think in terms of imperative steps: take out ingredients, apply peanut butter to bottom slice, add jelly on top of peanut butter, put on top slice, slice sandwich, eat sandwich. In other words, you’d program it as:
var ingredients = fridge.removeIngredients() var sandwich = new Sandwich() applyPeanutButter(sandwich, ingredients) applyJelly(sandwich, ingredients) addTopSlice(sandwich, ingredients) sliceSandwich(sandwich) eatSandwich(sandwich)
You don’t think of it as:
It doesn’t matter whether you think the first version is too verbose, or that side effects are evil, or that the second version parallelizes more easily. People just don’t think that way. They can learn to think that way, sure, but it’s my firm belief that the first version is just how most people’s brains are wired. So people will naturally always be put off by functional programming, regardless of whether or not it’s technically superior. Furthermore, languages like Haskell (and even Scala) have so many complicated concepts baked into the language that most people will just fall back to something easier to use and learn. Sure, monads might be great and powerful and necessary, but anything that takes dozens of wiki pages to explain and multiple tries for most experienced developers is imposing a pretty high barrier to entry. If you’re programming a project just for yourself that you’ll work on for 10 years, and if libraries or platform support weren’t an issue, Lisp (or maybe Haskell) would probably be the right language to write it in. The expressive power and flexibility would let you get more done over time. But if you have to have other people understand your code? Or you need to bring new people onto your team? Wrong answer. The barrier to entry is just too high. It doesn’t matter if something is the best tool if it’s too hard to learn to use, unless you’re the only one that will ever need to use it. And because of that, the libraries and community support just won’t really ever come, which provides a further barrier to entry.
To me, it’s really just a fundamental problem: (most) people naturally think imperatively and will always have an easier time learning imperative languages and reading imperative code, and thus imperative programming is always going to be far and away dominant, regardless of whether or not it’s truly superior in a technical sense.