Skip to content

Instantly share code, notes, and snippets.

@colinbankier
Last active August 29, 2015 14:15
Show Gist options
  • Save colinbankier/147e101aa39687010b3e to your computer and use it in GitHub Desktop.
Save colinbankier/147e101aa39687010b3e to your computer and use it in GitHub Desktop.

#The Winds of Change

Here at Everyday Hero we’re a Ruby shop. We love Ruby. Ruby is great. We are however, starting to experiment with introducing other programming languages and technologies for our backend services into our repertoire. One of our new micro-services has been started in Elixir. In this post I’ll discuss our reasons for looking beyond Ruby at another programming language and technology.

Being a Ruby shop, nearly all our applications are written in Ruby - our oldest apps were started way back on Ruby 1.8 and Rails 1.0, and we now have a fleet of apps that keep up with the latest Ruby and Rails versions, as well as smaller services that use other frameworks like Sinatra or Napa. We have a long history (in Ruby terms) with this technology set. ###Why Ruby is Great I still remember the excitement I felt when I discovered Ruby (and Rails) in about 2006, and I’m pretty sure the reason Ruby gained such popularity is because so many developers felt the same thing. Ruby brought the joy back into programming. For developers worn down by the verbose and cumbersome syntax of languages like Java, Ruby made us remember why we used to enjoy programming. The expressiveness, the simplicity, the flexibility, the ability to focus on the problem at hand, rather than being weighed down by a draconian type system and oppressive syntax. It was a beautiful thing. Rails attempted to bring these same ideals to building web applications, it was driven by an open-source community pushing the boundaries in “agile” development practices and encouraged “best practices” right out of the box. Stop having to fight things you don’t care about, and get on with building the system you were trying to build. Love or hate Rails, it’s uptake and longevity are testament to it achieving this goal. keep calm and code in ruby ##So, Why Change? There are changes afoot in the software engineering industry. Sure, things are always changing - this is the nature of technology in general, but every now and there is something more like a tectonic shift. The shift currently underway is driven by an increasing need to build applications that are distributed and concurrent. Ruby’s strength has been in creating developer happiness, not runtime performance and scalability. We need both. ###Multiple Cores A historical trend, commonly known as “Moore’s Law”, has seen the CPU power available for a given cost roughly double every year. Due to the pesky laws of quantum physics and powers I’ll only pretend to understand, it has become inefficient to build more and more powerful individual CPUs. Instead the architectures of our machines have changed radically to include multiple CPUs, Hyper-threading and additional processors on GPUs, for example. It’s common for a standard laptop now to have between four and twelve cores, and for high-end servers, it can be many more. Even if massive break-throughs occur and we can produce very fast and tiny CPUs on a single machine, we are increasingly needing to build applications that span multiple hosts. ###Web Scale It is becoming increasingly insufficient for the applications we build to run on a single machine. It is common, if not standard practice, to deploy a single application across many physical or virtual hosts. Take a typical production Rails application for example - it would be deployed across multiple hosts serving web traffic, but it would also commonly require some background job processing, using something like Delayed Job, Resque or SideKiq, probably running on another set of hosts. Maybe also another process consuming a message queue of some description if there is one in your ecosystem. The app would then have some combination of a relational database, a key/value store like Redis, caching mechanisms like Memcache or Varnish providing the stateful parts of the application, each running on their own hosts. That’s a lot of hosts, and that’s for a pretty stock-standard Rails app. As we build applications that need to serve 1000s of users from across the globe, it is becoming common to deploy applications not only across multiple hosts, but across datacentres and even continents. ###So what does this mean for programming languages? Most popular programming languages today suck at taking advantage of multiple cores. Languages like Ruby and Python have a Global Interpreter Lock (GIL), which inherently prevent them from executing code simultaneously across multiple CPUs. The JVM and .NET runtimes do not have this limitation, nor does something like C++ - there is another big problem - concurrent programming in most languages is hard. It becomes complex very quickly and even for highly experienced programmers, it is often error prone. Most common languages provide constructs such as semaphores, mutexes and locks to coordinate executing code across multiple cores and concurrent access to data residing in memory. Systems can become non-determinate, weird race conditions become your daily toil, and bugs can become very hard to track down or to reproduce.

These challenges are part of the reason behind the rise of new programming languages like Go, and frameworks like Nodejs which provide mechanisms for dealing with concurrency more easily and a focus on performance critical to handling web scale traffic. It is also a driver behind a resurgence in ancient techniques from the dark depths of history (in software engineering timescales) that have been until recently relegated to the realm of elbow-pad wearing academics. I’m talking about some of the core principles of Functional Programming. ###Object Oriented is Overrated When I was cutting my teeth as a professional developer, OO was everything. At the time Java was king, and Visual Basic and PHP were teased for being lame because they were not OO. (They may indeed be lame, but this is not because of their lack of OO-ness). OO was the only valid paradigm. Those “Gang of Four” (GoF) guys were our sages. Anything else was inferior. A joke. “Ha! PHP isn’t even Object Oriented.” (OO was later introduced into PHP due to peer pressure). When Ruby became big it was a “Pure” OO language, everything was an object, clearly this was the best thing possible.

The core concept in OO programming is to bundle some state with some operations. This certainly can be useful, but it turns out this is very bad for building concurrent systems. Allowing multiple threads to access and modify an object simultaneously leads to all kinds of inconsistencies in your system, hence the techniques mentioned previously such as mutexes and locks. A core principle of Functional Programming is Immutable Data - once you write a piece of data to memory, it cannot change. What kind of horrible affliction is this? Surely no useful program can be written if you can’t change the value of your variables? Instead of updating a value, a new copy of the data is made. The advantage of this is that there is no contention between threads sharing this data - no other thread can update a variable you were referring to at precisely the wrong moment, many threads can happily read the data knowing that it will not change. Surely all this copying of data is inefficient? In some cases it can be so, but data structures designed for immutable data, known as a Persistent data structure use “linking” to make this efficient in most cases - if a list is modified, for example, only the modified elements require new space in memory, while all other elements point to the same memory location as before. This can be done safely only because we can guarantee those memory location will not change underneath us - they are immutable. Such things can be done in other languages, but often require a ton of additional effort and discipline compared to a language that enables and enforces this inherently.

Persistent Data Structure

An example of Persistent Data Structures where nodes are shared between structures.

Breaking away from OO programming into a Functional approach has other benefits. A key goal in functional programming is limiting side-effects - writing functions whose output depends only on their input, and that do not modify any state outside that function. This inherently makes programs easier to reason about because the result of a function depends only on what you give it, not on arbitrary bits of state mingled throughout the program. Rich Hickey, the inventor of Clojure, calls this aspect of OO “the new spaghetti code”. There are a number of patterns in OO programming that assist you in wrangling this spaghetti of state, such as Value Objects. Wrangling these issues is easier if your language inherently supports immutability - Rich Hickey also gave a great talk on Values and State here. Respecting functions as first class citizens in a language is a concept that is becoming popular in many languages, such as the introduction of “Lambdas” in Java 8, but the power and benefits of Functional Programming come when you also have the other core principles of immutable data and limiting side-effects.

The core concepts of functional programming are not new, they are almost as old as programming itself. There is, however, a distinct rise in interest in functional languages for building concurrent systems. A handful of the newest, fastest growing languages today have a strong functional underpinning, for example Scala, Clojure and Elixir. ##Where do we go now? There are a handful of new languages and technologies springing up to enable us developers to tackle this distributed and concurrent future. The choice of a technology is a subjective one. Every developer builds an opinion throughout their career on aspects of technologies or languages that they love or hate based on their own experiences. These convicts run strong, and many an Internet flame war has ensued on this topic. Different technologies also suit different organisations or businesses for a variety of cultural reasons.

For me, Elixir is the one language that has me super excited. It is a language that brings the same developer happiness that Ruby brought us, but is built on the battle-tested Erlang platform, famous for insanely scalable distributed systems. In a future post, I’ll elaborate on Elixir’s main features which make it, in my personal opinion, the perfect culmination of many technologies that have preceeded it, and why I’m putting my money on a big future for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment