When I teach our web services class Ruby on the Server, a question I occasionally get from students is why we spend half of the first day learning about Rack. After all, Rails is the heavyweight of the Ruby ecosystem, and what most people come to learn about.
One of the core themes of the class is to demystify Rails, which has a lot of features that people often describe as “magic.” When people say that, what they usually mean is an interface with a level of abstraction that frees you from needing to know what’s going on under the hood. It gives you that “it just works” sensation. Being free to build your application without worrying about the underlying implementation is wonderful, but sadly, many developers never peel back the layers and attempt to understand how it works.
At Big Nerd Ranch, our approach is to teach the bare bones first. We apply this tactic over and over throughout the week, from rendering an ERB template by hand to defining resourceful HTTP routes and mapping them individually to controller actions. We make you do it the hard way before we teach you the magical incantations. Think of it as watching the Wizard of Oz backwards. Instead of jumping directly into Rails and seeing your web service magically spring to life, we start with Rack.
This is not just some pedagogical theory, though. It has practical value. Sufficiently complex Ruby web services are often split into multiple sub-services. Rack is a specification designed to build modular web services that can be composed. Whether it’s a simple web interface to view your background job queue or a full blown service-oriented architecture, you’ll encounter such services in the wild. They will almost certainly be Rack apps. “Not Rails apps?” you ask. The wonderful thing is that Rails apps are Rack apps, and so are Sinatra, Padrino and Lotus apps. It would be easier to note exceptions than to compile a list. These days, it’s safe to assume that if it’s serving up HTTP responses, and it’s written in Ruby, then it’s a Rack app.
Understanding Rack is essential to deeply understanding how a complex web service written in Ruby works. We’re not training you to be able to complete the cliché blog tutorial. We want you to go home armed with the knowledge needed to contribute to the kind of projects we work on.
With such wide usage, it came as a bit of a shock when the Rack core team announced that Rack is considered complete. Aaron Patterson will step up to maintain point releases going forward, but the team does not expect to release version 2.0 of Rack. I recommend reading the announcement yourself for a fuller picture, but the gist of it is that Rack is showing its age.
There’s a multitude of new protocols on the horizon, like WebSockets, HTTP2, and Server-Sent Events, to name a few. Many implementations of the Ruby language now have usable multi-threading. The world simply isn’t the same place it was when the Rack specification was introduced.
That said, for now, and a long time to come, you will still use Rack. It remains an important part of the Ruby web stack and won’t be going anywhere for a while. Even so, we need to be thinking about the future. Where will Ruby fit into the event-driven, “real-time” future of the web? Does it have a place?
Whatever comes next needs to be designed for a world where resources can exist not only as documents, but as streams. Our Chief Learning Officer Aaron Hillegass talked about this at AltConf earlier this year.
I think that if there’s room for Ruby in the traditional web service space, where Java is king, then there’s room in this new space. Go and Elixir may be extremely well suited for the job, and I expect them to capture a significant portion of the market. However, Ruby has a winning characteristic: its flexibility. The ease with which you can kick off a project, iterate on the design and get a working product out the door is unparallelled.
I share Aaron’s excitement for the future of WebSockets, Server-Sent Events and the like. However, I think there’s reason to keep some stock in stateless protocols like HTTP: the inherent unpredictability of mobile network connectivity. WebSockets are awesome for broadcasting events to multiple devices in near real-time, partly because they hold open a persistent connection. However, when you lack the requisite, stable connection, that characteristic is less exciting. As much as we all want ubiquitous, reliable broadband, unreliable connectivity is, sadly, the state of mobile internet for the foreseeable future. When you get off a plane in an unfamiliar city, being able to send a request for a car from your favorite rideshare app under sketchy network conditions will be of higher value than seeing real-time car locations on a reliable connection.
Event sourcing application state over a streaming protocol will remain unpractical for quite some time. Imagine downloading every change that ever occurred to a Wikipedia page over a WebSocket just to get the end result. Consequently, I believe we’ll see a proliferation of hybridized web services. In between traditional request-response services and event sockets for everything, there’s a whole world of practical applications where resources can exist as documents or streams, like chat transcripts and real-time chat, or Wikipedia pages and real-time, collaborative editing.
The building blocks for event-driven web services have been making their way into the Ruby ecosystem for a few years now. Couple that with battle-tested, traditional web service frameworks like Rails, and Ruby is in an excellent position to continue being the language of choice for web developers.
ActionController::Live with version 4.0, although it feels
bolted on at best. Rails doesn’t have a first-class way of representing
resources as streams. Others have been researching ways to create hybrid
resourceful/eventful web services:
For the foreseeable future, we’re still teaching Rack. It’s a stalwart of Ruby web services, and isn’t going away any time soon. We believe that understanding Rack is paramount for being able to tackle complex Ruby applications today, and for a long time to come.
That said, things are changing. These are exciting times, and we’re making the most of them. Always learning, we’re putting an increasing focus on evented protocols across all our engineering divisions. We’re conducting internal experiments and doing awesome work for clients.
What we learn, you’ll learn. Coming early next year, the Ruby on the Server bootcamp will teach you to build evented web services as a first-class topic. We’re excited about this unchartered territory, and seeing what will be built in it.