DAVID:
Back before I turned into an urban legend.
CHUCK:
[Laughs]
CORALINE:
An urban legend in your own mind.
[This episode is sponsored by Hired.com. Every week on Hired, they run an auction where over a thousand tech companies in San Francisco, New York, and L.A. bid on Ruby developers, providing them with salary and equity upfront. The average Ruby developer gets an average of 5 to 15 introductory offers and an average salary offer of $130,000 a year. Users can either accept an offer and go right into interviewing with the company or deny them without any continuing obligations. It’s totally free for users. And when you’re hired, they also give you a $2,000 signing bonus as a thank you for using them. But if you use the Ruby Rogues link, you’ll get a $4,000 bonus instead. Finally, if you’re not looking for a job and know someone who is, you can refer them to Hired and get a $1,337 bonus if they accept a job. Go sign up at Hired.com/RubyRogues.]
[This episode is sponsored by Codeship.com. Don’t you wish you could simply deploy your code every time your tests pass? Wouldn’t it be nice if it were tied into a nice continuous integration system? That’s Codeship. They run your code. If all your tests pass, they deploy your code automatically. For fuss-free continuous delivery, check them out at Codeship.com, continuous delivery made simple.]
[Snap is a hosted CI and continuous delivery that is simple and intuitive. Snap’s deployment pipelines deliver fast feedback and can push healthy builds to multiple environments automatically or on demand. Snap integrates deeply with GitHub and has great support for different languages, data stores, and testing frameworks. Snap deploys your application to cloud services like Heroku, Digital Ocean, AWS, and many more. Try Snap for free. Sign up at SnapCI.com/RubyRogues.]
[This episode is sponsored by DigitalOcean. DigitalOcean is the provider I use to host all of my creations. All the shows are hosted there along with any other projects I come up with. Their user interface is simple and easy to use. Their support is excellent and their VPS’s are backed on Solid State Drives and are fast and responsive. Check them out at DigitalOcean.com. If you use the code RubyRogues you’ll get a $10 credit.]
CHUCK:
Hey everybody and welcome to episode 210 of the Ruby Rogues podcast. This week on our panel we have Saron Yitbarek.
SARON:
Hey everybody.
CHUCK:
Avdi Grimm.
AVDI:
Hello.
CHUCK:
Coraline Ada Ehmke.
CORALINE:
Hi.
CHUCK:
Sorry about that hesitation. I got confused because I saw David Brady’s picture on the call. [Inaudible]
DAVID:
This is Dave Brady. I’m away from the podcast right now but if you leave your name, IP address and [Podcatcher] version…
SARON:
[Laughs]
DAVID:
I’ll get back to you later in the show.
CHUCK:
I’m Charles Max Wood from DevChat.tv. Quick reminder, we are now inside of a month away from Ruby Remote Conf. So, if you want to go to a conference where you don’t actually have to go to the conference, you can just watch it your computer or whatever, then go to RubyRemoteConf.com and sign up.
This week we have a special guest and that is Jeremy Evans.
JEREMY:
Hello, everybody.
CHUCK:
Do you want to introduce yourself really quickly?
JEREMY:
Well, I’m probably [known] best nowadays as the maintainer of Sequel, the Ruby database library. And I was recently awarded the Ruby Hero Award at RailsConf about a month ago.
SARON:
Awesome.
CHUCK:
Yeah, they give you a nice trophy for that, don’t they?
JEREMY:
It is a very nice trophy. I must say, it’s very nice.
CHUCK:
Do you have it on your desk at work where people can come in and go, “What’s that”?
JEREMY:
It’s actually right next to my diploma at work. So, it looks down on everyone that comes into my cubicle.
CHUCK:
[Chuckles] Nice.
SARON:
If I had a trophy related to programming, I think I’d put it on a necklace and wear it everywhere. [Laughter]
JEREMY:
Seriously, you would look like the, what’s his name? The guy with the big clock?
SARON:
Yeah. [Laughs]
AVDI:
Flavor Flav?
JEREMY:
That’s how big the trophy is. It is gigantic.
SARON:
Flavor Flav
[Laughter]
CORALINE:
It looks a little sharp, too. I think it might be dangerous.
CHUCK:
[Chuckles]
JEREMY:
Yeah. I would not recommend that.
SARON:
If I’m a programmer with an award, I think I’m dangerous. So, it just fits.
CHUCK:
I think I’m going to build a 3D printer and print my own trophy.
SARON:
There you go. And sell them, new revenue stream.
CHUCK:
There we go. You want to be a Ruby Hero, too? Here you go. [Laughter]
CHUCK:
Alright. So, we brought you on today to talk about Roda and routing trees. Jeremy, you want to give us an overview of what those two topics are and how they relate?
JEREMY:
Sure. Roda basically is a routing tree web framework. So in other words, it’s a toolkit for building web frameworks that route web requests using a tree. So, Roda’s core is basically just the router. But Roda uses a plugin system that is similar to Sequel’s plugin system where all the additional features are contained as separate plugin modules. So, when you are building your app using Roda you basically pick only the plugins that you need and you don’t load the other plugins. And by choosing which plugins you specifically need, you’re basically creating a web framework custom tailored to your application.
So, Roda’s history can be traced back to Rum which was a request router written by Christian Neukirchen, the author of Rack, back in 2009. And the fundamental difference between Rum and other approaches to routing was that Rum handles routing at an instance level. So, instead of passing a request to a router and having the router just point you to the request handler, in Rum the router is integrated with the request handler. And as you are routing a request you can also be handling a request.
And the main advantage to integrating routing with request handling is that in most applications the URL structure somewhat reflects the application structure. So, as soon as certain branches in the routing tree are taken, you can immediately start handling the request before you’ve even finished routing your request. And this allows you to easily share behavior for all routes under a given branch from a tree. It provides a natural way to DRY up your code without [littering] it with before filters. And it reduces the amount of indirection when you’re routing, which in addition to being faster also makes the resulting code easier to read and understand.
CORALINE:
So basically, you can scope instance variables and have their logic there for an entire branch of the tree, of the routing tree?
JEREMY:
Yes, that’s one of the advantages to it.
DAVID:
I love that it’s a toolkit for a framework. How did you write this thing without just quoting Xzibit the entire time? [Laughter]
DAVID:
Yo, dawg. I heard you like frameworks. So, we got you a framework for your framework so that you can rap while you route.
JEREMY:
Well, originally it wasn’t designed to be a toolkit. It was basically just its own framework. Some of the history, it originally came back from Rum. But in between there was what this one framework called Cuba, which I think you guys had the author of Cuba Michel Martens on earlier…
CHUCK:
Yup, we did.
JEREMY:
I think back in November. And Roda basically was forked from Cuba basically due to philosophical differences between his approach to writing a web framework and the way I wanted to go. I basically was proposing patches to Cuba that he did not want to take. So, I just basically did it the open source way. If you don’t like it, you fork. And that’s what I did. So, after I’ve worked, originally it was just going to be a web framework. And I thought, “Well, depending on what plugins you load with this, it’s really going to result in a very different framework.” You can have a framework look significantly different depending on with plugins you load. So, that’s why I call the framework toolkit. So basically, depending which plugins you load you’re basically building your own custom framework.
CORALINE:
What are some of those plugins you’re talking about?
JEREMY:
For example, if you want a Sinatra-like API where you basically just define routes sort of like in a list, you can do that. There’s a plugin, ClassLevelRouting, where you can have a list of the top-level routes and inside those, then you can also branch. So, you can make it so it acts just like a nested Sinatra.
And there are plain plugins that change how routing occurs, like how you treat ending slashes. So, do you want to have routes that are always canonical? So, if your route ends in a slash it’s treated differently than a route that does not end in a slash? The default in Roda is that they’re treated differently. So, all routes are canonical. But if you want to treat those two routes the same, there’s a plugin like empty path or something like that, that allows you to have that specific behavior.
There’s also plugins for rendering. By default, Roda is just a router. There is no plugin for rendering templates. Plenty of people use Roda as an API. So, they don’t need routing of templates, I mean rendering of templates. They just need to have quick JSON API requests. So, there’s also a JSON API plugin that makes writing JSON APIs very simple. It basically can just return either a hash or an array from your route and it will be automatically converted to JSON implicitly for you, which makes writing JSON APIs really nice.
There’s also plugins for asset handling and there’s plugins for template streaming, like ActionController Live if you use that in Rails. There’s a plugin that basically does the same thing in Roda. And there’s a lot of plugins for things that you would expect in other frameworks. Because Roda is so small, the core is so small, a lot of things that other frameworks provide are added as plugins, so that if you need them, you can load them. But if you don’t need them, you don’t load them and you don’t pay the cost in memory and performance for using them.
AVDI:
So, we’ve had some folks on in the past to talk about Sinatra and also Padrino which is a collection of basically plugins to plug into Sinatra. How would you contrast your approach with that, with the Sinatra/Padrino ecosystem?
JEREMY:
Well, Padrino and Sinatra are separate projects. Honestly, I’ve never worked directly on Padrino. I’ve read some of Padrino’s documentation. I looked at [maybe] a little bit of the code. But I don’t have really much experience with it. But Padrino is sort of, it had sort of… I don’t want to say, not like a Rails lite there, but adds controllers to Sinatra which aren’t really Sinatra-like.
Roda is actually I think more similar to Sinatra’s routing in a nested level than Padrino is, especially you’re defining classes. You have separate routers. With Roda basically you’re just defining the routes directly like you can in Sinatra, except that you can also define routes in a nested fashion, which Sinatra doesn’t allow. So, I really… and I’ve used Sinatra for many years, like seven years before I started working on Roda. And really, what it is, is basically aimed at being a nice, nested Sinatra without a lot of the backwards compatibility issues that Sinatra has.
AVDI:
Can you give an example of where nested routing is useful?
JEREMY:
Well for example, let’s say you have an albums database. So, your paths start with, your paths relate to an album. It might be like `album/some-id-for-the-album/track-list` or /update for updating it, or whatever it is. So, as soon as you take this album, as soon as you get the ID for the album, before you’ve finished routing the rest of the path, you can retrieve the album from the database. And then all routes underneath that branch of the tree can share that code, which is like a before filter in other web applications. But it’s sort of built in.
It’s implicit. There’s no indirection. It’s basically right there in your routing tree. So, it makes it much easier to read the code and understand what it’s doing versus before filters where you’re looking all over your app, where is this defined? Especially if you use Rails with controllers that inherit from each other, it’s often confusing where things are happening. This makes it much more direct and you can exactly see. You can basically read the routing tree from top to bottom and see exactly where code is getting executed. There is no indirection in that case.
AVDI:
That makes a lot of sense. The flipside of that I could see is that these routing trees could get really long. Do you have any features for snipping some of it out into a module or something?
JEREMY:
Well, there’s actually… because you can basically have a block that breaks across multiple files in Ruby, there’s a plugin called MultiRoute which basically takes your routing tree and you can by plugins, or sorry, by prefixes of the path you can basically say, “Okay, all routes that start with albums, use this separate branch.” So, you’d basically, when you’re defining your routing tree, you do route and you give it a prefix. And then in your main app you can just do ‘r.multi_route’ and that will dispatch all of your routes, basically your separate route prefixes, using a single regular expression to catch the route and then dispatches right to that.
So, in addition to being fast it also allows you a way to break up your code into separate files. And you can use this in a nested fashion. So, if you have a very large routing tree, you can have the top-level files. So, you have the ‘r.multi_route’ in the main app dispatch to all the main top-level prefixes. And those prefixes can then dispatch to sub-prefixes. So, this allows for building apps of arbitrary complexity while still retaining the same model of basically using this routing tree.
CHUCK:
I could see this being used for something similar to what we see engines used for these days. So, you could have a blog app or set of routes that behave in a particular way. And then you just load it in, so to speak. And so, you could actually pass that around between different apps. And then you just pass in the views and make sure that your data structures exist.
JEREMY:
Yeah, so basically you can do it that way. Also, if your blog is a separate Rack application you can also just dispatch directly to that. Rum was originally designed more as a URL router than as a framework itself. It was originally designed for taking prefixes and dispatching them to Rack applications. And you can use Roda the same way. So, if you have a bunch of Rack applications and you just want to structure them and do handling, like access control, before you pass off to another different Rack application, you can easily do that if you have separate Rack applications.
You can also build it all in the same application if you want to. It’s very flexible that way.
CHUCK:
So, how do you dispatch from one Rack app to another?
JEREMY:
The API calls just run. So, you would do… everything in Roda is based off the request. So, the request instance in Roda has methods that operate as routing methods. One of these methods is run. So, you can, with ‘r.albums’ and lets [inaudible] that prefix handled by another Rack application. You go like ‘r.on_albums’ and then inside that you do ‘r.run’ and give it your Rack app.
And then it will dispatch everything under the albums branch to your Rack app.
CHUCK:
Oh, nice.
CORALINE:
Does that mean you can use it in front of something like Rails?
JEREMY:
Yeah, you can basically put this in front of Rails. There’s actually a couple of ways to integrate this into Rails. One, you could have this in front of Rails and then dispatch into Rails. There’s also a middleware plugin for Roda which operates as middleware. You can load it as middleware into your Rails app. And any route that your Roda app does not handle will then be dispatched to your Rails app. So, this allows you to, let’s say you want to speed up your Rails app, you can add this middleware to, Roda as middleware, to your Rails app. And then everything that’s performance sensitive you can do in Roda. And you can pass the rest of the requests onto Rails so that Rails is still being used for the less performance sensitive code.
CORALINE:
So, you’re saying that the routing tree really has a positive impact on performance?
JEREMY:
Yeah. Roda is actually one of the fastest web frameworks for Ruby. And there’s two parts to this. One is the request overhead is kept extremely low compared to most other web frameworks. And internally the way routing is handled is also very fast. So, the benchmarking I’ve done, I have not found, for any significant application of significant complexity, the case where other approaches to routing are faster.
CHUCK:
So, you’ve benchmarked this against Rails?
JEREMY:
Well, yeah. And Rails is hard, because Rails has so much overhead for every request that even though the Rails router is actually very good, tenderlove wrote it, it’s extremely fast and good at what it does. But there’s a ton of overhead in Rails. If you want the Rails router to use a lighter web framework there’s actually a web framework called NYNY that takes Rails’ router and uses it in that. So, more like a Sinatra-like application, and that’s also, that’s actually the second fastest web framework that I benchmarked. But it still has I think more overhead than Roda has.
CHUCK:
Is there a place where people can actually go see the benchmarks?
JEREMY:
Yeah, actually I have a project on GitHub called r10k. And it’s like a takeoff on the c10k problem where you have 10,000 connections. The r10k problem is you have 10,000 nested routes in one application and you benchmark it. So, I have this. It actually benchmarks it with Cuba, with Sinatra, with NYNY, with Rails, and then with Roda with the different plugins loaded to see how they perform differently. And in this Roda ends up being fastest. If you go on the Roda website and you look at some of the presentations I’ve given at RubyConf and MountainWest RubyConf there are some slides that show the output of r10k, the benchmark graphs which show that Roda is the fastest with, it doesn’t matter if you’re doing 10, 100, 1,000 or 10,000 routes. Roda ends up being the fastest.
CHUCK:
Even faster than Cuba? Because I know you modified Cuba to make Roda.
JEREMY:
Yeah. So Cuba, there’s actually another benchmark called bench-micro which is written by Luis Lavena. And it basically benchmarks all these micro-frameworks with a single route. In the single route case, Cuba’s actually slightly faster than Roda. But it’s actually significantly slower anytime you’re doing any routing actually, because Cuba is not really optimized internally. One of the things it does, it’s creating separate regular expressions for every branch of the tree while Roda caches those regular expressions. And regular expression generation in Ruby is actually quite slow. So, this actually makes performance in Cuba, even though Cuba is much faster than Sinatra, it’s still significantly slower than Roda.
SARON:
You mentioned that you can integrate this into Rails. And I’m wondering. Does that happen very often? Is that a common use case? Or do people just use it on its own.
JEREMY:
I’d say in most cases, people are using it on its own. I don’t know anyone that is actually doing this in Rails. If anyone is, please contact me and let me know.
AVDI:
One of the limitations that Rails has hit up against is the fact that Rack was never really designed with streaming in mind. And so, it turns out to be very difficult to do any kind of streaming. Rack really wants you to basically come up with your whole response and then feed that out. Is that an issue that Roda addresses at all? Or is that beyond the scope of what you’re trying to do?
JEREMY:
No, certainly Roda tries to address that in certain ways. One case is the template streaming. So, in the Rack spec basically you can return as the body of the application anything that responds to ‘each’. So, in a lot of cases in frameworks, this is just like an array with one string inside of it. And that’s basically the entire body. But you can have an enumerable, like any enumerable really. As long as it yields strings when called with ‘each’ it basically operates efficiently.
So, there’s two ways that Roda does this. One is it has a template streaming plugin. So, you can stream templates using Transfer-Encoding chunked so you don’t have to prepare the entire response before yielding to the user. This allows you to basically flesh your head part of your request before your entire request is finished generating so that the user can load the assets necessary to display the page before the page is even finished rendering. And you can be retrieving objects from the database while the client is loading the assets related to the page, which makes actual performance for the user in the browser significantly faster.
The other part is streaming. There’s two parts to streaming. One is using things like event source. So, there’s a streaming plugin in Roda now that you can stream things like doing event source type stuff. One thing that Roda doesn’t have support for yet is WebSockets. And I’m currently working on adding support for that using the Faye WebSocket stuff. Also, I’m trying to get Reel. I don’t know if you’ve heard of Reel but it’s the Celluloid web framework. I’m trying to get it to support that through Reel’s WebSocket support. That’s not currently worked in yet.
SARON:
I’m curious to hear how you make decisions like that. Like when you say, “We’re working on supporting WebSocket,” how do you decide what to support? Or do you just wait to hear people complain and then you respond to it. Or, how do you decide your roadmap?
JEREMY:
I’d say currently the roadmap is kind of empty. [Chuckles] But WebSockets are something I want to support. The other thing I have sort of on the to-do list is adding support for Opal. And a lot of the cases, the stuff I’m working on in Roda is not so much in Roda itself but it’s in the surrounding ecosystem.
So, Roda’s asset plugin is based on Tilt. So, Tilt renders the templates for things like if you’re using CoffeeScript with Tilt or if you’re using CSS in Tilt. The asset plugin basically relies on Tilt to handle the template rendering for the assets. I wanted to add support for Opal, which is a JavaScript… So, it basically ports Ruby to JavaScript. So, you can write Ruby code and it’s transpiled to JavaScript. And that JavaScript executes on the user’s browser. When I first started using Opal, it didn’t support that with Tilt. It sort of only supported Sprockets. So, I basically added support to Opal so that you could use Tilt to render Opal, basically your Ruby code to JavaScript. And that way in the future, it will be usable by Roda to basically use Ruby both through your frontend and through your backend. So basically, you don’t have to use JavaScript on the frontend and Ruby on the backend. You can use Ruby for both. And I think that’s sort of where I want Ruby to go.
I talked about this fairly recently on the changelog. But I think one of the problems with all these JavaScript frameworks coming out where if you have to write your frontend in JavaScript, the idea is, “Well, it’s why I [have a] backend in JavaScript so that it’s the same language.” But if you consider JavaScript just at runtime, you can write the frontend and the backend in the same language, in this case Ruby. But if you’re using [I think something] like Clojure, you can use Clojure and ClojureScript for the frontend. And there’s a whole bunch of languages now that they have a JavaScript… they compile to JavaScript as well as compiling natively. And I sort of want to support that with Roda so that you can use basically Roda in the frontend and Roda in the backend.
AVDI:
I love that you’re addressing some of your needs by improving some of these other projects.
JEREMY:
Yeah. And actually, I mentioned Opal. But I’m working on Rack, on Tilt, on MIME types for the Mailer plugin. There’s actually a whole bunch of the ecosystem I’m applying, pushing out pull requests to the other projects and hopefully get them accepted. So, that way I can make Roda better by integrating better with these other external projects.
AVDI:
That’s fantastic. You’ve talked about how most of Roda is about its plugins. So, I’ll bet you have some insights into how to make a good plugin API. Have you learned anything in that department?
JEREMY:
Yeah. Roda’s plugin system is based almost exactly on Sequel’s plugin system. And the Sequel plugin system, I didn’t actually write it. It was actually available in Sequel before I took Sequel over back in 2008. And I think it’s an extremely well-designed plugin ecosystem where a plugin is basically just a module. And inside the module it has a module called ClassMethods if you want to add class methods, and a module called InstanceMethods if you want to add instance methods. And then for Sequel there’s a module called dataset methods. So, you can add methods just [for] the dataset class.
In Roda, that doesn’t make sense. So, the options for modules inside the plugin are ClassMethods and InstanceMethods. But also, RequestClassMethods and RequestInstanceMethods, and response class methods and response instance methods. So, your plugins can basically, each Roda class that you have creates a custom subclass of the request class and response class specific to your Roda app class. So, when you subclass Roda app it also subclasses the request and response classes, and that way when you apply plugins they apply the plugins only to that request class or that response class. And that way you can custom… you basically modify any part of your request, your response, or your current scope, add methods, and you can always call super to get the default behavior.
AVDI:
I guess part of what makes that approach work is that you have a pretty… you’ve limited the number of objects that might need to be extended by a plugin. Is that a fair statement?
JEREMY:
Yeah, that’s certainly the case. I think that’s my approach in general. I don’t tend to have a whole bunch of different objects. I generally tend to stick mostly to the primitives and then only have objects for things that really need to be objects. So, in Sequel there’s the database. There’s the dataset. There’s the model. Those are the three main objects that you deal with in Sequel. In Roda it’s going to be the scope, which is actually the instance of the Roda class that you’re using. And there’s the request and the response. And there are other classes used, but there’s not that many of them. In most cases you’re using just those objects and the primitives.
AVDI:
That’s actually kind of an interesting design [inaudible] where a lot of times we shun having objects that have many, many methods, a few objects with many, many methods. But it does seem like it’s true that when you’re trying to do a plugin architecture, as soon as you have lots of different objects, now you have to find a way to adjust or modify or subclass or something lots of different classes in order to let the plugin advise any part of the system, right?
JEREMY:
Yeah. And some people would say this violates the Single Responsibility Principle. And in some cases it does. But it makes the code much easier to understand. It’s much easier to understand three objects than it is to understand a hundred different types of objects.
So, and especially if you… one of my approaches is using primitives for a lot of things which people also say that might be an anti-pattern. In my experience I found it actually works very well. It keeps the code very simple because basically all Ruby programmers know how strings work. They know how arrays work. They know how hashes work. If you have separate objects for each type of thing where you could just use a more primitive type, it makes the code I think harder for newcomers to understand. I think it is much easier to understand code that basically has a few object types that you need to understand. But the rest of it is primitives that you can just use.
And if you find later that your primitives don’t do what you need, you can always in Ruby subclass the primitives and add methods to them. So, in Sequel originally the association reflections were just hashes. And eventually it became subclasses of hashes with basically added methods to them. So, if you make objects for all those things before you really need them, I think you end up making your application or your library significantly more complex.
AVDI:
It almost feels like maybe there are different forces at work for library code or framework code than there are for say domain code where you might want more objects.
JEREMY:
I think I agree with that. I try to keep especially libraries, should be kept as simple as possible. Because you don’t know exactly how a library is going to be used all over the place. So, applications I think should be treated differently than libraries are treated, both in testing and in design.
CORALINE:
How would people go about writing and taking advantage of the plugin architecture in Roda? Do you have third-party groups or individuals who are contributing plugins as well?
JEREMY:
There’s certainly a lot more of the internal plugins that I have linked as external plugins. And then there are probably quite a few people that work in external plugins. And every time someone works an external plugin, I try to get them to send me the link so I can include it in Roda’s documentation so that people know about not just the internal plugins but the external plugins as well. And in both Roda’s and Sequel’s plugin architecture, it’s designed so that it doesn’t matter to the user if a plugin is internal or external. It’s treated and loaded exactly the same way.
CHUCK:
Yeah. I just want to point out. When he says internal versus external, I’ll put a link in the show notes to this. But if you go to the repository and you look in ‘lib/roda/plugins’ there are a whole bunch of plugins that you can pull in that are just included with the library.
JEREMY:
Yeah. And one of the reasons I did that, sort of like I do with Sequel, is that it’s great to have a bunch of plugins that are inside your repository. Because then they’re tested alongside the main lib code so that you can be sure that no part of any modifications you’re doing to the library are going to break the plugin code. You have the internal plugins that are tested again alongside. Every time you test Roda you’re testing not just the internal, the core of Roda. You’re testing all the plugins that Roda uses as well.
And this makes it so you can change things and make sure… you don’t want to change things that’ll break external plugins. But certainly you don’t want to change anything where you’re breaking internal plugins. That way, all the plugins you’re writing are testing alongside. And you can see if you make a change to the core, if it breaks in the internal plugins, it might break in external plugins. And maybe you want to do something different that’s more backwards compatible.
CHUCK:
Now, speaking of plugins, one thing that I want to ask is I’ve been playing with Roda for a little while. And it doesn’t seem like there are any plugins that are turned on by default.
JEREMY:
correct.
CHUCK:
You have to go and turn them on by default or turn them on yourself.
JEREMY:
Yes.
CHUCK:
The thing that I’m wondering though is that Rails turns on a whole bunch of features for security. And this is something that Noah Gibbs actually brought up when we talked to him. So, I’m wondering. Is there some sort of security methodology that you should follow with Roda?
JEREMY:
Actually, I talk about this in the readme. If you’re designing a customer or a user-facing browserbased app, there are some headers you want to have. And I actually have that in the readme for Roda about… you can use what’s called the DefaultHeaders plugin. You can add some default headers. And every application is different. But those are, the ones I list are basically the common ones that most applications are going to want.
However if you’re using it for designing a JSON API you don’t want any of those. Those are for browser-based apps. If you’re designing a JSON API you’re probably doing authentication via a token system or something else. And then maybe not handling sessions, so session security is not important to you. And Roda, the core of it doesn’t depend on you doing it a certain way. It’s basically designed to be flexible for any use. And then you load the plugins you want for specific use cases. So, I want the core to remain very, very generic.
SARON:
So, in being generic and trying to be flexible and take care of whatever needs the developer has, do you feel like you’re sacrificing anything?
JEREMY:
I don’t feel that I’m sacrificing anything that way. I’d say it might be a little bit more difficult for a new user that wasn’t used to web security to use Roda. If you don’t know about web security and you use Rails, it handles things for you in a decent manner, if you don’t about it and you don’t read Roda’s documentation you could end up with a web application that’s not secure, which is certainly possible. But if you’re not reading documentation, especially Roda’s documentation is not hugely large because Roda itself is fairly small. I say you at least want to read the readme to make sure that you understand all the different parts. I go over certain… there’s a lot of things related to security, cross-site scripting, cross-site request forgery. And Roda has basically the ability to handle all of those. But you need to read the documentation. And usually, it’s just loading this one plugin or doing this one line of configuration to handle it.
CHUCK:
So, one other thing that I want to talk about briefly is what apps in your opinion are good matches for Roda versus something like Rails or Sinatra or some of the other frameworks out there?
JEREMY:
I’d say if you have a Sinatra app, Roda unless you’re using some sort of external Sinatra code that depends on Sinatra, Roda is a good fit for pretty much anything that Sinatra does. It’s sort of the design principle behind it. It’s basically a faster, nested version of Sinatra. So, if you’re using Sinatra or something I’d say it’s a good thing you could use Roda for. It could be faster and hopefully it could be easier to maintain. For Rails, I [think] the main advantage Rails has is the network effect. Tons of developers know Rails, tons of software works with Rails. So, from a network perspective, Rails has a lot of advantages there that Roda does not have.
So, it really depends on how much external code that you would be using that would depend on the external framework. So, if you’re planning on using things like Devise and OmniAuth and all the other things that might integrate better into Rails, Rails might be a better choice for that. It really depends on how much external code you’re using that already depends on another library. I think from a technical… if you’re designing from scratch and you’re not planning on using external libraries, I’d say Roda would be a better choice for most applications, in my biased opinion.
CHUCK:
I have to say that the thing that I’ve been playing with it the most for… I’ve used it as far as having it load views and doing it a traditional web app. But I’ve also been playing with it for APIs. And well, APIs both for say mobile apps as well as APIs for things like Angular and a more involved frontend. And I have to say that it’s been really nice to be able to… because with APIs a lot of it really does boil down to then where is the endpoint and what kind of request are you making to it? So, it gets a lot of the extra stuff that Rails gives you out of the way because all you really care about is returning the information in the correct format and doing that in a way that makes sense. And then solving the authentication problem, which may or may not be more automatic than what you get out of Rails. And so, I’ve really been enjoying it for that. And it works really nicely with both the frontend frameworks as well as with the other types of applications that are going to be using your APIs
JEREMY:
Yeah. I’ve heard that a lot of people that are using Roda are using it for APIs, probably because it’s easy, but also because it’s one of the fastest Ruby web frameworks. So, I don’t actually do a lot of API stuff. Most of my stuff is browser-based apps. But most of the people I’ve heard that are using Roda are often using it for API type stuff.
CHUCK:
Yeah. For me it was the way that it puts together the routing. Performance, I usually don’t worry too much about until I have a problem. But yeah, it just really appealed to me because I can see exactly what the endpoints are, what kinds of requests needed to come in, and how it’s going to handle it, because it’s all right there.
JEREMY:
Great.
CORALINE:
One of the things you talked about in the documentation for Roda is application freezing. Can you talk about that a little bit?
JEREMY:
Yeah. So, Roda actually, one of the… there’s four main goals with Roda. One of them is reliability. The other ones are simplicity, extensibility, and performance. But the reliability part comes in part from freezing the app. So, the idea is in production you have a frozen application. And this freezes all of the internal data structures except for the thread-safe caches. So, that makes it basically eliminate all possible thread safety issues when using the framework, even when you’re running on Ruby implementations that lack a global VM lock, like JRuby and Rubinius. A lot of other Ruby web applications that are thread-safe are thread-safe on MRI because they rely on things like accessing a hash from multiple threads being thread-safe due to the global VM lock. On JRuby and Rubinius, they’re not thread-safe.
You can actually see this on a few, recently about Oga which is an XML parser for Ruby. And it’s basically designed to replace Nokogiri because on Rubinius Nokogiri doesn’t work correctly, because it relies on the global VM lock for handling thread safety issues. So, if you’re doing multiple thread work using Nokogiri on Rubinius, it crashes because it doesn’t synchronize correctly. In Oga, they use a Ruby way that works correctly.
So, in any case, Roda is designed so that thread safety is critical so that you can run this in JRuby and it’ll be extremely fast. And one of the reasons it has to run, it has to be completely thread-safe is JRuby is concurrent. So, you can’t rely on the global VM lock to handle your thread synchronization. So, it basically handles that for you. And it does this by freezing the internal data structures so that if you attempted to use them in a thread-unsafe manner, like let’s say you try to write to them, you’ll basically get an instant exception because they’re all frozen. So, that’s basically the approach to thread safety. So, in testing and production you run it frozen. And then in development you can run with the reloader so it’s not frozen. You can still update things.
AVDI:
To make this more concrete for listeners, can you give an example of the kind of thing that somebody might try to access and then find that it’s frozen?
JEREMY:
Yeah. One of the things you often see if you’re on Stack Overflow looking at things like Sinatra is that people will try to do something that should be run globally like before. For example, Sequel database setup, people will do that for every request that comes in and figure out, “Why am I leaking connections?” You try to do something like that. Let’s say you’re loading a plugin for example but you’re trying to load a plugin inside a request. It’ll fail because when you freeze the application you basically can’t load any more plugins into it because it’s frozen. That sort of thing where if you do it, you’ll get an instant exception, and that way you’ll know that what you’re doing is a bad idea. And you can basically fix it.
AVDI:
That makes a lot of sense.
JEREMY:
I agree.
AVDI:
Hey, I’m curious. You said that you mostly do browser-facing applications. Would you mind telling us a little bit about your preferred stack? Obviously, Roda, but what sort of templating plugins and stuff like that are you using?
JEREMY:
My typical stack will be Roda for the web framework, Unicorn usually for the web server unless I’m doing something streaming related, in which case I’d be using Rainbows! which is a Unicorn variant that supports threaded applications, because Unicorn is single-threaded basically. For the template type stuff, usually I’m just using Erubis and I usually use SCSS or Sass as SCSS for the CSS type stuff.
Currently right now I’m writing… I don’t do very much JavaScript work. But usually when I do, it’s just plain JavaScript. I’m looking at if I do more JavaScript work, trying to push it onto Opal. That’s one of the reasons I’m trying to get Opal fully supported so that you can use Opal in Roda. And that way I can instead of writing JavaScript which I don’t really like [chuckles] basically write what I would be writing in JavaScript in Ruby to make it nicer and simpler. But yeah, that’s pretty much the main parts of what I use, are basically Roda, Sequel, Unicorn, Erubis, Sass. There are probably some other plugins as well, but those are the main gems that I’d be using in my default stack.
AVDI:
Thanks.
CORALINE:
So, you talked about some of the areas where Roda is a good fit, especially in terms of APIs and the work that you do. What are some areas that you’d want to avoid using Roda for?
JEREMY:
Currently right now, it doesn’t have good support for WebSockets. You can do WebSocket type stuff in it, like for example using [inaudible] WebSocket. But there’s nothing integrated. And that’s one of the things I’m working on next, is that I want to be able [to say] you can use WebSockets nicely in Roda, because a lot of things these days are using WebSockets. Things where again Roda is not a good fit, mostly it just depends on the external gems you’re using. If you’re trying to use a lot of external gems that rely on other web frameworks, you might have to recreate those wheels in Roda or wait until there’s Roda support for them.
So, for cases where you do want to reuse a lot of the external stuff like Devise for example, currently there’s nothing like that for Roda. I do have long term plans. I had an account management type plugin. But there’s a lot of complexity there. And I want to get more experience in that area before I start working on that. I don’t want to bring out something that’s really halfbaked before I think it’s ready.
CORALINE:
How long have you been working on Roda?
JEREMY:
I started working on Roda in July of last year. So, I’ve been working on Roda for probably about nine or ten months now.
CORALINE:
Besides WebSockets, are there other things on your roadmap that you’re really excited about?
JEREMY:
Mostly getting WebSockets working and then getting Opal working. And then possibly taking Roda’s routing tree approach and importing that via Opal to JavaScript. So that way, in your browser when you’re making a request your request can return things. And you can use a routing tree in your browser to determine what to do on the particular page. So basically, Roda in the frontend and Roda in the backend. It basically makes it simpler when you’re designing your application. You can use a similar structure for both types of work, both the frontend work in the application and the backend work, the handling there.
CORALINE:
That sounds pretty interesting. What are typical JavaScript frameworks you’re using for that sort of routing today?
JEREMY:
I actually don’t know all that much. I don’t really do that much JavaScript-heavy work. I really try to avoid JavaScript [chuckles] if at all possible. And it’s not unfortunately too much possible these days, which is one of the reasons I’m looking at this. But I actually don’t know. I would assume that, hopefully maybe Charles would have a lot more experience in that area than I would.
CORALINE:
That’s fair.
DAVID:
We can be friends, by the way.
JEREMY:
Good.
DAVID:
Yeah.
JEREMY:
[Laughs]
DAVID:
Not a fan of JavaScript. [Laughs]
CORALINE:
[Chuckles]
AVDI:
Can I switch gears a little bit and ask you a little bit about just how you balance your work?
JEREMY:
Sure.
AVDI:
So, you’re lead developer on the Sequel project, on the Roda project. You’re also an OpenBSD developer, right?
JEREMY:
That’s correct. I actually handle pretty much the entire Ruby ecosystem on OpenBSD. So, this includes JRuby, all the versions of MRI. We support everything from 1.8.7 on to 2.2.2. It also currently works, Rubinius currently works in OpenBSD but it’s an older version. I’m actually going to an [OpenBSD] hackathon in a couple months and I’m going to try to get Rubinius, the updated version, running on OpenBSD because it’s… the last time I tried it, it was quite a hard process to get working.
AVDI:
So, you’ve got that going on. We’ve already talked about how you’re also pushing a lot of pull requests to other Ruby projects. And I can speak from personal experience about how responsive you are when somebody pipes up on IRC about something with Sequel. So, how do you manage your time? How do you keep up with all this stuff?
JEREMY:
Mostly it’s just focusing on them. In most cases, like questions [inaudible] Sequel are usually something… if you just take some time right then to do it, it doesn’t take much time. So, if you focus on the little things and you do them right away, you actually end up long term having more time to do things. So, I work for the government right now. And actually, it’s a great place to work where I work. I do end up having a significant amount of free time. So, in the free time I have where I work, I basically can work on open source stuff, because everything I work on and all my open source projects basically feed into the work I do at my job. So, any time I’m improving the open source code that I use, or the open source code I have, I’m improving what I do on the job.
So, it’s not like there’s fighting between the open source work I do and my job. It’s basically sort of the same thing. So, anything I can do to improve the open source projects long term will help the work I’m doing at my job. So, it’s very easy to spend time helping improve, helping people use Sequel and Roda, because from dealing with people I can see problems in Sequel and Roda. And I can fix them and I can make the entire project better. And if you don’t deal with people directly on a regular basis, you often don’t have a good idea about what is good and what is bad and how to fix that.
SARON:
So, you deal with the little problems as they come up?
JEREMY:
Yeah. So basically, as soon as an issue is put on one of the projects that I work on or a pull request is issued or people have a question online like IRC, I try to address it as soon as possible. And there are a couple of reasons for that, mostly because I think addressing it soon is good in terms of seeing what’s the problem right away. Also, it makes it very nice for contributors, because a lot of projects are not that responsive. Some of them are which is great. But a lot of Ruby projects are not that responsive in terms of you might do a pull request and if you’re lucky it might be a couple of days, a couple of weeks, if you get a response at all.
So, I try to be the change I want to see. And if I post an issue on some other project, I really do want to get feedback very soon. Is this good, is this the way to go, is this bad? And so, since that’s the response that I want, I try to be the same way for people that use my projects and that when they have an issue, I try to respond as soon as I can.
SARON:
But don’t you worry about getting distracted and bogged down by little things that you don’t get to focus on the bigger stuff?
JEREMY:
Currently, at least in the time I’ve been doing it, and this has been seven or eight years, that has not been a problem yet. I would say that if it got significantly more popular and I had requests coming in all the time and the volume got so high that I couldn’t handle it, I would probably need to change my approach. But so far, and I’ve been doing this for quite a while, seven or eight years, it has not been a problem yet.
CORALINE:
In one of my open source talks I tell people that it’s great if you can figure out a way to get paid to do open source by basically using your open source work at work. What advice do you have for other people who would like to be in a similar situation where they’re using their own tools in their work environment and getting paid to maintain them?
JEREMY:
Well, it’s a great job if you can get it.
[Chuckles]
JEREMY:
It’s hard. The place where I started, they didn’t have a programmer on staff when I started. I actually started as an auditor. And I didn’t really like auditing. And a position opened up doing help desk work in the IT shop. And the IT shop is very small. It’s like three people. So, I started doing that. And then I’d taken programming in school and actually worked at a programming lab while I was in college. And they asked me at one point to take over the development of the website which was at the time just a pure HTML site. So, I started doing that and I started doing PHP. Then I
started doing Python. And then I started doing Ruby.
And after I started doing Ruby I started using tons of open source tools and started working on my own open source tools. And basically from there it just snowballed, because since there wasn’t any existing programming infrastructure when I started, I basically had to write everything myself. So that’s why everything I use is something I wrote, because when I started using it there wasn’t anything else there. So, that’s why I get to work on all these libraries that I use at work, is because when I started there was nothing. So, everything I used ended up [inaudible] was already open source or I had to build it myself.
AVDI:
I want to ask you how you pick a project. because if you are in that mode, if you are into creating tools or improving tools, there is a literally infinite array of things where you could be using a tool and you’re like, “Oh, I could do this better.” And you’ve clearly done that with Roda. But you got to draw the line somewhere. How do you decide, “I definitely want to devote some time to making this better,” versus, “You know what? Somebody else can make this better.”
JEREMY:
I honestly try to avoid creating new projects if I can. Roda is actually the only time I actually just forked an open source project basically to take it in a different direction. With Sequel basically I was [attributed] patches to Sequel. And the maintainer of Sequel decided he did not want to do programming at all anymore. So, he asked the people that had submitted patches to Sequel, “Hey, do you want to take it over?” And I was the person that ended up saying, “Yes, I want to take it over.” So, that was basically just me taking over from him. It wasn’t really a fork. It was me taking over Sequel. Roda’s the first time I’ve actually decided to fork another project to take it in a different direction. I actually do try to not fork other people’s projects. I try not to create projects if I don’t have to. I don’t want to write my own web server. I actually didn’t really want to write my own web framework.
It’s just that I was using Sinatra for many years, probably seven or eight years, probably about seven years. I was using Sinatra. And it was great. I had a lot of fun using Sinatra. And one of the things I found with Sinatra is I ended up with duplicate code in lots of my routes. Because in Sinatra, all of your routes basically are independent of all your other routes. There’s no nesting. So, I always end up with duplicate code in all my routes. Everything that started with artist would do something first. And there are ways to work around that in Sinatra. And there weren’t when I started using Sinatra. But they eventually did add the ability to do that in Sinatra. But it started not built-in.
When I started using or started learning about Cuba and saw its approach to routing, it’s like that approach to using a routing tree just would make what I’m doing at work so much easier. So, I
started using Cuba. And I’m like, “This looks really good and I want to switch to it.” But there are all these things in Sinatra that I like better. So originally, the working name for Roda was Sinuba. So, it was half Sinatra and half Cuba.
CHUCK:
[Chuckles]
JEREMY:
And that was my working name for it. Actually if you look back in Roda’s history, the commit history, there’s a part where it’s actually named Sinuba for quite a while before I decided on the name Roda. And the name Roda actually comes from a tree in a video game. Actually, I’ll be able to talk about that when I do picks. But yeah, in general I try to avoid creating new projects if I don’t have to. Usually, if I’m creating a new project it’s because I ran into something, I didn’t see an existing way to do it, and there might be one I just don’t know about. But usually it’s because I didn’t see an existing way to do that, so I had to write it myself.
CHUCK:
So, this segues back. One thing that I’m wondering about is since every route is explicit in Roda, I’m wondering how you feel about the magical routes that you see in Rails like resource and that kind of stuff where it essentially creates a series of routes that then delegate to a controller that matches a certain API.
JEREMY:
Yeah, I don’t really like that approach in Rails. I actually used Rails. I started using Rails back in 2004, late 2004. And I used Rails all the way up until 2014. So, I actually have Rails applications that started in 0.10 or 11 or something and were upgraded all the way to 4.1. But they’re basically always Rails [one style] applications. They never used the resource type stuff that was in Rails. When I did, I never found an advantage to use that. So, you can certainly build things like that in Roda. There’s actually external plugins for Roda that give you things like that. But I don’t use them because in the code I write, I don’t see the advantage to doing it that way.
CHUCK:
Cool.
SARON:
You talked about how you used, there are things about Sinatra that you like but you didn’t like the way that it did routing. How do you decide whether to talk to the Sinatra people and say, “Do you want to reconsider how you do routing to do it this way?” versus just saying, “I’m going to do my own thing”?
JEREMY:
Like I said, I originally talked to the Cuba developers and said, “Hey, there are these things about Cuba I’d like to change. And even if you don’t change the… you don’t have to change Cuba itself. There’s just, I want to do this in Cuba. And Cuba has a plugin system. But I can’t use the plugin system to do it the way I want to do it. And I’d like to make these changes to the plugin system to do it the way I want to do it.” And they basically said, “No, we don’t want you to do that. We don’t think that you should be able to change the default in Cuba. You shouldn’t be able to override methods that Cuba defines to do something different.”
Where in Sequel’s plugin system it’s not like that. You can go in the Sequel model, the class itself, and define the method and call super to get the default implementation, because the default implementation is in a module that Sequel model includes. So, everything’s built on module inclusion. But there’s no ClassMethods itself. All the methods are in modules. So, you can always call super to get the default application.
And that’s I think one of the biggest reasons I forked, is that I could not do what I wanted to do in Cuba. I suppose I could have gone to Sinatra and say, “Hey, you could change your entire way you do routing to do it differently.” And I’m actually hoping in Sinatra 2 maybe they do take a routing tree like approach. But I didn’t think it was right for someone to come in and say, “Hey, let’s do it completely differently.” It would be a huge change to how Sinatra does things that you really… you could possibly do it in Sinatra 2 if you want to break compatibility with Sinatra 1. Like I said, it just didn’t feel right saying, “Okay, we should make these huge changes.”
DAVID:
Yeah, because that would end up breaking the way you declare routes in Sinatra, right?
JEREMY:
Well, yes, because let’s say you change it so the default in Sinatra was not to do it, was to allow nested routes. At all points, you have to find, okay, is this route terminal or is it not terminal? Actually, one of the issues I have with Cuba is that Cuba, there’s no built-in way to define terminal routes. And by default in Sinatra, because every route is independent, all routes are terminal. So, in Roda there’s ways you can say this route is terminal, this route is not terminal. And that’s what you’d have to introduce into Sinatra if Sinatra was to take a routing tree like approach. And I don’t know. I guess it just takes more gumption than I had to tell them, “Hey, we should do it this completely different way.”
DAVID:
Mmhmm.
SARON:
So, in that sense, do you feel like that, feeling like that wasn’t right to do, is that because you feel like the way you did it isn’t necessarily the right or the better way? It’s just a different way? Like if you felt like the way you were doing it was fundamentally, [inaudible] or anything, but [chuckles] fundamentally the better way to do it and would just make Sinatra so much better, would you feel more inclined to make that a conversation?
JEREMY:
Maybe. I do think that, is this the best way to do everything? No. There’s no one… there’s no silver bullet. There’s no one best way to do everything. I think for a lot of things, especially the types of programs or applications that I work on, I think the routing tree approach is great. It makes things simple. It makes it very fast. It’s very easy to extend and work with. But there are certainly applications that it might not be a good fit for. And a lot of those applications, I might not even know it’s a bad fit for those applications because I have not worked on those type of applications.
So, I can’t say this is the best way to do everything. Especially if you have a Sinatra app with two routes. There’s no real reason to use a routing tree. Roda might be faster but that’d be the main advantage. It wouldn’t be better. It would just be faster.
DAVID:
Right. And it’s faster meaning it’s two milliseconds instead of six, right?
JEREMY:
Yeah. And that’s basically, if you actually do benchmarking it actually ends up being close to that in terms of... Roda’s about, for a ‘hello world’ style application, Roda’s about three times faster than Sinatra, or two and a half times faster.
DAVID:
Mmhmm, yeah.
CHUCK:
Not six milliseconds.
DAVID:
Yeah. Well, and that was kind of my point, is it’s like your app is going to spend 150 milliseconds setting everything up. Well, not for a ‘hello world’ app. But yeah, if you’ve got a very small application, then I think it was Donald Knuth that said that anybody that spends any amount of time measuring, getting actual metrics on their optimization learns very quickly that their intuitive guess on where their application is slow is wrong. And to be fair, this is me making an intuitive guess so I’m probably wrong. But I would assume that a very tight, small application with just two or three routes on it, routing’s not going to be your bottleneck, right? It’s going to be somewhere in your app code.
JEREMY:
Yeah. And actually, routing is not a big bottleneck in most applications. One of the main advantages, I said the main advantage to Roda is speed, is not in the fast routing. It’s in the very low per request overhead. If you look at Sinatra’s overhead for each request, it’s a lot higher. It’s not the routing.
DAVID:
Mmhmm.
JEREMY:
In Sinatra, lots of routes are slow because basically Sinatra iterates through all the routes.
DAVID:
Yeah.
JEREMY:
So, it’s basically O(n) for the number of routes you have whereas Roda would be O(log n) because it uses a tree.
DAVID:
Right.
JEREMY:
Sort of. It’s not exact. But that’s sort of the ballpark.
CHUCK:
I’m going to stop you for a second, just for the folks that don’t know what he’s talking about with O(n) and O(log n). Do a quick search for ‘big O notation’ and we’ll put a link in the show notes.
DAVID:
Yeah.
CHUCK:
Go ahead, keep going.
JEREMY:
Okay. So, in general, Roda is fast more for the low overhead, low per request overhead, not for the faster routing. It is faster routing. And if you have a very large application, the routing is fast. But I don’t think the routing is much faster than Rails router. Rails router has some advantages. Let’s say you had 10,000 routes all with a different prefix. If you just did that by default in Roda, it would be quite slow, because Roda basically executes your routing tree directly. So basically, you take the block you have and it’s executing your route directly. And it’s working your way down imperatively through the route code. So, if you have 10,000 routes in one branch it’s going to iterate all through that in Ruby code.
But one of the huge advantages of using Roda is that your routing is basically Ruby. So, let’s say you had something like that, you could do a case statement and then let’s say branch off the first two letters of the route. And then instantly you switch, you eliminate or you reduce the search space you’re using by two orders of magnitude for example.
DAVID:
Oh no, that’s interesting. Okay, so you just described a case where you use a case statement to branch off the first couple of characters. Can you abuse Roda to the point where you could actually have… because you were talking about implementing a tree in Ruby code now to build up a single level of the tree, could you actually use Roda to basically say this is a six-character license plate? And it’s a random… it’s all over the map. So, I don’t want to build out 256, well probably more like 56 characters raised to the sixth power. So, I want to bin these out like in 256 by 256 by 256. Could you tell Roda to do that with a three-node tree inside one level of the route?
JEREMY:
Oh, yeah. Basically Roda is instance-level routing. So basically, when a request comes in, Roda just yields to your route block. At that point, you can use anything you can do in Ruby to route. You can look up a database and then depending on what the database returns route completely differently based on what the database response is. It’s basically instance-level routing. Anything you can do in Ruby, you can do and that affects how you route code. So, you have complete control. That’s not done all that much. But you have the capability to do that whenever you want, which is why it is so different than all these other approaches for routing where basically you’re handing your request to a router and then the router just gives you, “Okay, call this method on this object to do what you want.”
DAVID:
Mmhmm.
JEREMY:
With Roda, you basically have complete control and you can do anything you want to do in Ruby to change how routing is done. Not just how requests are handled but how even to route the requests.
DAVID:
Mmhmm.
JEREMY:
You have complete control over it because it’s just Ruby code.
DAVID:
That’s cool. So, there was a question you got asked at MountainWest RubyConf. And I wanted to give you a chance to revisit it, either for our listeners or to see if your answer has enhanced a little bit. I remember you showing a chart of 10,000 or 100,000 routes and showing the log n degradation version Sinatra’s linear degradation. And somebody raised their hand and said, “What kind of application would have 10,000 different routes?” And as I recall, you kind of shrugged and said, “Eh, they exist.” I kind of want to ask that question again and press you for a little more detail. What would be an example? It can be a dumb example. It doesn’t have to be an obvious thing. But are there categories of apps that are going to have this breadth of routes on them?
JEREMY:
I’d say no. It really, the r10k project with 10,000 routes is unrealistic in terms of I’d say very unlikely that applications will get that large. I do think they exist. Trust me.
DAVID:
Mmhmm.
JEREMY:
In the government, any bad idea you have, it probably exists somewhere. [Chuckles]
DAVID:
[Laughs] Okay, fair enough, fair enough.
JEREMY:
So, but yeah…
DAVID:
We can say that these exist and we’re optimizing for a stupid use case. But it’s a stupid legacy use case which means we’re getting paid to work on it.
JEREMY:
And we’re not necessarily optimizing for that use case. It just says that yes, this would work for that use case. That’s not really… our goal is not to make the 10,000-route case fast.
DAVID:
Yeah.
JEREMY:
Our goal is really to make the 10 and 100-route, the typical app, that’s the goal to make it fast. But the approach scales whereas a lot of other approaches do not scale in the same way.
DAVID:
Yeah. But as soon as you said government projects, it reminded me of a lot of the Rails rescue work that I’ve done in the past where you get brought in to help somebody fix a really stupid mistake. And I actually now totally can visualize getting paid to speed up an app with 10,000 routes. I can totally visualize it. [Laughter]
DAVID:
Because when you bring in a consultant to fix your project, the last thing you want to hear is that you need to redo your entire architecture. Or if they do tell you and you know they’re going to tell you your entire architecture is wrong, and you’re going to say, “Yeah, okay. But we’re making $100,000 a week on an iPhone app that we can’t change. It needs to know about these 10,000 routes.” And so, you do find yourself in the position of, “Yup. I’ve got to optimize for this use case.” I’ve learned never to say that you’re never going to see that, because I got burned by it. [Chuckles]
DAVID:
I just finished reading Bjarne Stroustrup’s C++ annotated guide. And he demonstrates his C++ style by writing a string class. And I held forth long and loud that nobody ever is going to write a string class. And the very next job… [Chuckles]
DAVID:
I worked on was a tiny, we had to stay under 28k for the downloadable which means we could not require the standard library, which means we did not have a string class. And my very next job I had to write a string class. So yeah, I never say never. [Chuckles]
JEREMY:
Definitely.
CHUCK:
Alright. Should we go ahead and do some picks?
DAVID:
Sure.
JEREMY:
Sure.
CHUCK:
Alright. Avdi, do you want to start us off with picks?
AVDI:
Yeah, sure. I’ve got a couple of videos that I found pretty interesting. The first one… the videos are both about the Self language which was a language developed I think at Sun Microsystems, influenced a lot of languages that followed it. But it’s one of those things where if you look back at it, you realize that a whole lot of the stuff, the really innovative stuff that it did, fell by the wayside. And only little bits of it were picked up. One of the movies is ‘Self: The Movie’ which is a short introduction to Self and some of the things that make it neat, by Randy Smith. And it’s back, from back in 1995.
Self:
Whys and Wherefores’ which is a talk at Stanford by David Ungar who worked on Self and was one of the creators of Self. And both of them very interesting, both of them show a lot of fascinating research that has influenced the stuff that has followed and some other stuff that maybe ought to influence us but hasn’t yet. And I think that’s it for me.
CHUCK:
Alright. Saron, what are your picks?
SARON:
Okay, have you guys seen the video ‘April Fools Video Prank in Math Class’?
CHUCK:
No?
DAVID:
Ooh, no.
SARON:
Wonderful. It’s amazing. It has 13 million views. It is a great combination of math, nerdiness, and funny. It’s fun for the whole family. So, that’s my pick. You should definitely check it out. It’s a riot.
CHUCK:
Awesome. Coraline, do you have some picks for us?
CORALINE:
Sure, I have a couple. One is programming related and one is not. The first one is called ‘A pattern language for microservices’. This is a project that’s attempting to create a full-on pattern language for microservice architectures and dives into such patterns as Service per Container, Service per VM, Multiple services per host, and monolithic architectures, and so on. And it’s really a clean site and with good information and provides a good overview of things you need to know and metaphors and paradigms you need to know as you go in to build a microservice architecture.
The second one is a comic book. I found that I use my iPad most often for reading. And often I’m reading comics. One of my favorite most recent titles is called Wytches created by Scott Snyder and drawn by a guy named Jock. It’s a horror comic book series published by Image that started in October of last year. The series follows the Rook family, in particular their daughter Sailor. The family ends up moving to a new town to start over after an incident between Sailor and a particularly nasty bully from her school. But the place that they moved to has secret supernatural traditions that play into their lives, into their story. I want to make sure that you know it’s not a book for kids. And it can be a little violent. So, be warned. And it’s available on comiXology. So, you can read it on all of your mobile devices. And I’ll provide a link to that in the show notes.
CHUCK:
Cool. David, do you have some picks for us?
DAVID:
I do. I’ve been away for a while and you think I would have a whole bunch. But I just have two. I am working on a hot sauce pick. But I don’t have that ready yet. So, I have two picks. One is crazy awesome and one is stupid awesome. But by crazy awesome I mean very, extremely awesome and by stupid awesome I mean awesome and funny and really, really stupid.
So, we’ll start with the crazy awesome one. I have a Garmin Vivosmart. I broke my Fitbit Zip about two months ago and got a Garmin Vivosmart. And now I genuinely cannot understand why Fitbit is even in business anymore. Garmin has been in the prosumer market for wearables and for health technology, like heartrate monitors, biking monitors, cameras and that sort of thing. And now they’re moving down into consumer market. And so, they are producing items that are at the same price points as a lot of the Fitbit wearables. But they’re just so much better. The quality is nicer. They’re more ergonomic. They feel better. And they just do a lot more. The Vivosmart is about the same, it’s about $150. It’s the same price point basically as the Fitbit Charge.
So, it’s a watch that you wear on your wrist. And it’s got an OLED display under a rubber surface. So, it looks like a black rubber bracelet until you tip it towards your face and then it turns on and lights up. And it’s got the same thing as the Fitbit Charge. It’s got a clock, steps, how many calories, your distance, et cetera. But it will also pick up text messages from your phone and display them on your wrist and you can scroll through them on this teeny, teeny, tiny screen, which is amazing. But the two things that I would buy the Garmin Vivosmart just for either one of these two features.
The first one is the auto-goal feature. And what this is, is it just checks in on you. And if you don’t make your goal, it lowers your goal for the next day. And if you just crushed your goal, it raises your goal the next day. My Fitbit Zip, it just said 10,000 steps or go home. And I had it for three years. Now, I’m going to reveal a little bit about my health. It’s maybe a little vulnerable and a little embarrassing. But I’m not a healthy person. I am very overweight. And I am very, very sedentary. And so, I had a Fitbit Zip for about three years. And I think I got 10,000 steps maybe once in those three years. I’m very much not a healthy person.
And the auto-goal, the first thing I did was I said, “I am very sedentary.” And it said, “Okay, buddy. 5,000 steps, all you got to do. Come on, 5,000 steps.” And then I went 1,200 steps that day and my Garmin Vivosmart said, “Okay. I’m just going to get used to disappointment.” And [chuckles] and it lowered the goal to, it just took 300 steps and said, “Come on, try for 4600. You can do it.” And I didn’t make it. And the next day it said, 4300. It kept coming down.
And interestingly, I kept going up because I wanted… this thing was willing to meet me halfway so I was willing to try and meet it halfway instead of just… the Fitbit Zip was just clipped to my belt and I just forgot about it. In fact, I stopped checking in on it. And what this thing does is like the wearables it buzzes. And if you use that to do a little party dance when you meet your goal or when you get up and move around and you do what it says when you’re supposed to, you can actually hack your brain, totally Pavlovian. But if you weaponized Pavlovian conditioning on yourself, it’s freaking awesome. And it totally works. And so, auto-goal was the first thing.
The second thing, and again I would buy it just for this feature, is what’s called the move bar. And this is based on the science of some studies that found that if you sit sedentary for two hours your metabolism goes into sleep mode. It just assumes you’re just laying around. You’re sleeping. I’m just going to shut down. And your rest mass intake of calories goes down. And so, what this thing does is it goes, okay two hours is too much. So, every hour it turns out that all you need is two minutes of activity to keep your metabolism from going to sleep.
So, every hour that I’ve been sitting still, my wrist buzzes. And I look down and it says, “MOVE!” in capital letters with an exclamation mark. And I do, because I’m trying to hack my brain. I say, “Okay I’m going to be healthy.” And so, I get up and I walk out the front door and I walk down to the end of the street and I walk back. And halfway down my wrist buzzes. And I go, “Yay, I’m being healthy.” I’m not healthy but I’m being so much more healthy than I was a month ago that my knees are feeling better. I’ve dropped 10 more pounds. I broke through the dieting plateau. It’s absolutely fantastic.
The combination of auto-goal and the move bar combined have me now where I’m consistently getting over 5,000 steps a day which is more than I’ve ever done. And I genuinely noticed in the afternoon that I am more awake and I feel warmer. I can genuinely feel that my metabolism is actually ticking over at a higher rate of speed because I’m not freezing to death all the time. I’m actually generating heat within my own body. So Garmin Vivosmart, I’m absolutely in love with them. They come in two sizes, large and small. Any my wife has the small and I have the large because I’m bigger and she’s smaller. So, that’s my crazy awesome pick.
My stupid awesome pick, just very quickly, Bad Lip Reading on YouTube. They did…
CHUCK:
Oh, no.
DAVID:
[Chuckles] Oh, yes.
CHUCK:
[Laughs]
DAVID:
They did The Avengers. And their take on The Avengers was to do redneck Avengers. And so, it’s cousin dating and you ate that and it made you sick. And if you watch it there, you will know exactly why I find it incredibly funny because you all know my sense of humor. It’s one of Thor’s lines halfway through. And you’ll know it when you hear it. And yeah, I laughed until I just couldn’t see straight. So, if you want to hear The Avengers talking like redneck, Redneck Avengers by Bad Lip Reading. And those are my picks.
CHUCK:
Very cool. I’ve got a couple of picks .The first pick is I’ve been listening to the backlog on my podcasts. And one of the podcasts I picked up was Saron’s podcast, CodeNewbie. And I just listened to the episode that she did with Aimee Knight who incidentally is on JavaScript Jabber. But it was really inspiring. And so, I really want to pick that.
I’ve also been listening to This is Your Life podcast my Michael Hyatt. And I’ve super been enjoying that one, too. So, I’m going to pick both of those.
And then I’m also going to pick cleaning off your desk. I got about 50% of the way done. But it’s just been so nice. I actually cleared off my standing desk and have been using it off and on, the same thing that Dave’s talking about with just getting up and not being sitting sedentary forever during the day. And so yeah, so those are my picks. And yeah, that’s what I’ve got. Jeremy, what are your picks?
JEREMY:
So, the name Roda comes from the Roda trees which appear in the Ys video game series and help the main characters accomplish their goals. So that’s Ys spelled Y-S. The Ys is a fairly niche video game series outside of Japan. It’s sort of an adventure, action, RPG game series known foremost for having really amazing music in addition to being quite fun to play. Anyway, if you’re looking for a new game to play, check it out on Steam. If you have a PlayStation Portable or PlayStation Vita there are also a few Ys games released for those systems as well. So, my first pick is going to be the Ys video game series.
My second pick is a Ruby library I just discovered last Friday, which is Minjs. And Minjs actually just started a few weeks ago. But it’s a pure Ruby JavaScript minimizer. So, the issue with the common JavaScript minimizers like YUI Compressor, Closure Compiler, and Uglifier is that they all require either a Java or JavaScript runtime. And I certainly prefer not to have to depend on those runtimes being available. Now currently Minjs is pretty slow. But the results are fairly good and it works, unlike previous pure Ruby approaches that I’ve seen. So, did have to patch one part of it that wasn’t working, the [inaudible] escapes. But that pull request was just merged over the weekend. So, my second pick is Minjs.
And my third pick is a movie I watched just last night named Camp. And I’m not really a very emotional person, but I found this movie very moving. It’s about a troubled child and has this experience at a summer camp. It’s a very predictable plot but the acting is really good. And it’s based on a bunch of stories from a real-life summer camp. It’s available on Netflix Instant. And that’s my third pick, the movie Camp from 2013. There’s actually a different one from 2003. But I’m talking about the one from 2013.
CHUCK:
Alright. Well, I think that’s all we’ve got. If people want to follow you or see what you’re working on, what are the best ways to do that, Jeremy?
JEREMY:
Alright. So, I’m on GitHub as jeremyevans and I’m on Twitter as @jeremyevans0. That’s basically probably the easiest ways to reach me.
CHUCK:
Alright. Well, we’ll go ahead and wrap up the show and we’ll catch you all next week.
[This episode is sponsored by MadGlory. You’ve been building software for a long time and sometimes it’s get a little overwhelming. Work piles up, hiring sucks, and it’s hard to get projects out the door. Check out MadGlory. They’re a small shop with experience shipping big products. They’re smart, dedicated, will augment your team and work as hard as you do. Find them online at MadGlory.com or on Twitter at MadGlory.]
[Hosting and bandwidth provided by the Blue Box Group. Check them out at Blubox.net.]
[Bandwidth for this segment is provided by CacheFly, the world’s fastest CDN. Deliver your content fast with CacheFly. Visit CacheFly.com to learn more.]
[Would you like to join a conversation with the Rogues and their guests? Want to support the show? We have a forum that allows you to join the conversation and support the show at the same time. You can sign up at RubyRogues.com/Parley.]