If you’ve done web programming for any length of time, you might too feel like we are at the start of some new era. For years, we’ve been using frameworks like Django and Rails in languages like Python and Ruby and PHP which use the old request-response cycle (for lack of a better term). Basically, a request comes into the server from a client, the server renders up an HTML web page, and then sends that back to the client. This pattern is not as dominant as it was 10 years ago, due to AJAX, JSON, and numerous frameworks that embrace client-side rendering, like Ember, Angular, Knockout, Backbone, and more recently React, but in many cases we are still using frameworks and languages which are ill-suited to this. We’ve known for years that Ruby and Python are slow, but we were willing to put up with that. However, as we more and more turn servers into REST APIs that are supposed to deliver JSON to numerous clients, for many it is time to find an alternative.
You see a lot of competitors trying to fill this void. Some people are crazy enough to use Rust or Nim or Haskell for this work, and you see some interest in JVM based languages like Scala or Clojure (because the JVM actually handles threading exceptionally well), but by and far the languages you both hear discussed and derided the most are JavaScript via node and Go. The thing about both languages is that neither of them are especially pretty. JavaScript prior to ES6 was complete shit in a lot of ways, but a lot of misguided judgments today are based on former experience and not modern realities about what the language has become. Personally, as I’ve stated before, I think JavaScript is a perfectly acceptable language, especially if you use a super set like Typescript. A few of its advantages are that it is fast (relatively), it is already used in the browser (though this may be changing in a few years with WebAssembly) and its asynchronous nature allows it to handle the modern web (apps not just pages) pretty well.
Here’s the thing, though. JavaScript also has some flaws. Syntactically it is pretty noisy and ugly. Additionally, as much as I appreciate the fact that it is continually evolving in the standardization process, it keeps getting bigger and bigger. Some of those additions were necessary to just make the language usable, but with as many fingers are in the pie that is ES standardization, I’ve seen concern expressed by some that the language will become especially bloated if it hasn’t already. This is something that concerns me as well. The best things usually have a singular driving force behind them, and I’m not sure JS has that and if it does, whether it can maintain it. Having Microsoft, Google, Mozilla, and others all involved in the process is both a blessing and a curse.
Finally, JavaScript handles the modern web well, but it isn’t perfect. If a request does something that is especially CPU-heavy, every single user of your application will be waiting. Thankfully, promises have eliminated callback hell, but we are still fundamentally covering up and working around JS’s core semantics. Will JS ever get proper threading to better handle some of these issues? Web Workers are a form of IPC, but as soon as you’ve delegated concurrency to that model, you aren’t any further along than Python (I am referencing the GIL and I am aware of aysncio).
There are only a handful of languages which are truly doing concurrency these days. One of them is Go with its goroutines and channels, and this is a large part of its appeal. A few other aspects which have made it a popular alternative to existing languages and ecosystems include raw speed, simple yet dynamic feeling typing, the ability to compile down to a binary, and finally, simplicity. In discussions about Go this last part seems to be a dividing line which is often overlooked. Many people who have or are still using more modern languages like Haskell look at Go and are aghast at what the language is lacking feature-wise and can’t understand why you’d possibly limit yourself to that. On the other hand, if you actually listen to a lot of Go users, that is the primary selling point: the language is small, you can understand it in a day, and whatever facilities it lacks you can overcome with brute force and enough code. It is quite boring but it works. I’ve done some programming in more esoteric languages so I’m not the ignorant user of blub that so many Go-users are portrayed as in any of these silly partisan language wars, but after a decade of working in a number of languages, I do just want something very simple and something that fits in my head. It is a compromise I’m willing to make, and I’m sure many users of Go are the same way.
That being said, have you tried writing a web app in Go? You can do it, but it isn’t exactly entertaining. All those nice form-handling libraries you are used to in Python and Ruby? Yeah, they aren’t nearly as good. You can try writing some validation functions for different form inputs, but you’ll probably run into limitations with the type system and find there are certain things you cannot express in the same way you could with the languages you came from. Database handling gets more verbose, models get very ugly with tags for JSON, databases, and whatever else. It isn’t an ideal situation. I’m ready to embrace simplicity, but writing web apps is already pretty menial work, Go only exacerbates that with so many simple tasks.
In some of these language discussions, Go gets mocked a lot because it was initially marketed as a “systems language”. The idea that Go would be used in place of C or C++ was seen as absurd, and perhaps rightly so. The Go devs have since stated that they were surprised to see that a lot of Go converts were from dynamic languages like Python and not C or C++. When the term “systems language” is used in isolation, it doesn’t make much sense, but when seen within the context of the massive servers and processes at Google, it makes perfect sense. And truthfully, Go still makes sense for a lot of apps, foundational stuff like Docker or small command line apps are all within its wheelhouse and are appropriate. Somewhere, however, that has been extrapolated to the idea that Go is a good language for writing web apps. I don’t believe that’s the case. It is just as out of its element there as it is with true “systems” programming.
There is a language, however, that might fit the bill. It’s a language that both snobs and those looking for something simpler can get excited about. Assuming you’ve read the title of this piece, you know I’m talking about Elixir. Elixir is a very light Ruby-ish layer of syntax that compiles down to run on BEAM, the Erlang VM. Erlang was created at Ericsson and has powered systems with incredible up time for decades. You can go elsewhere for a deeper explanation, but what makes this possible is that Erlang processes are very lightweight and hundreds of thousands of them can be spawned at once. This is true and elegant concurrency and it allows situations like WhatsApp to run on a minimum of servers with a minimum of engineers.
Again, I don’t want to get too far into the concurrency thing mainly because others can do it much better. Erlang/Elixir can do it better than any other language is really all you need to know. What I do want to touch on are the qualities of Elixir itself. Do you want a modern language? Elixir is functional, immutable, and supports pattern matching, which is like a case or if statement on steroids, only that explanation doesn’t begin to touch how much it impacts your entire manner of coding. It also supports macros which means that the core language can remain small but users can extend the syntax to support patterns the designer never dreamed of. As I said before, it does this with a Ruby-ish syntax. Syntax shouldn’t matter but it really does. I’ve tried designing an “acceptable lisp” (or rather an acceptable syntax for myself) before with prose (I think it is really cool!), but with its small core and functional nature Elixir strikes me as the unintentional true heir to Scheme’s throne.
And this is what truly intrigues me about Elixir. Despite the fact that it is a very modern language, it is quite small. You can read through the language guide in a few hours and have a pretty good grasp on the core concepts. I love this. I’d much rather spend cognitive cycles on figuring out how to solve a problem instead of figuring out which construct in the language should be used. This also leads to much quicker mastery. Use 10 constructs 100 times each and you’ll get them intuitively much faster than if you use 100 constructs 10 times each.
So what am I getting at? I think we are very much in a polyglot future. If you were able to get away with using a single language before, that is becoming less and less of a reality. Use Elixir for your REST API and you’ll probably still need to call out to a Python script (or some other language) for certain tasks. The key is, however, that Elixir with frameworks like Phoenix and libraries like Ecto seems like a much better fit as a tool for web development than many other options. If the only thing Elixir does well (and it does) is connecting to a Postgres database and turning that into JSON, then that’s the UNIX philosophy at work. If we are at the stage where people are willing to leave behind thousands of libraries in their existing language in search of a better alternative, Elixir seems to be a stronger choice than Go. Both are simple languages, but Elixir brings so many features which will both make you grow as a programmer and will help your programs to grow elegantly in the future.