- Erik Michaels-Ober (twitter github)
- James Edward Gray (twitter github blog)
- Katrina Owen (twitter github blog)
- Avdi Grimm (twitter github blog book)
- Josh Susser (twitter github blog)
- Charles Max Wood (twitter github Teach Me To Code Rails Ramp Up)
01:53 – Erik Michaels-Ober
02:45 – Unofficial Rogue: Emily Stolfo
03:32 – Rogues Golf Contest
09:31 – Twitter Gems
17:21 – Other Open-Source Projects
- Erik’s Github Repositories
- Steve Agalloco
- Tony Arcieri
23:42 – Dependency Management
25:17 – Semantic Versioning
- ~> Twiddle waka
- Going 1.0
32:10- Advice for maintaining a new gem (project)
- Cargo Culting
33:49 – Changelogs
37:15 – Diagnostic Signals
- Code Climate
- 083 RR Decomposing Fat Models with Bryan Helmkamp
- 041 RR Code Metrics with Bryan Helmkamp
- Sarah Mei – “Why Hasn’t Ruby Won?”
43:51 – Maintaining Twitter Gems vs Standard Rails Gems
47:12 – adamantium
54:32 – hashie
01:05:77 – The Null Object Pattern
01:08:27 – Gem Wrappers
- Food Fight Show: Immutable Infrastructure (James)
- B T (James)
- Serious Pony: Presentation Skills Considered Harmful (James)
- Cabeau Memory Foam Evolution Neck and Travel Pillow with Portable Bag (Avdi)
- Parrot Zik Headphones (Avdi)
- The West Wing (Avdi)
- Rubinius 2 (Josh)
- Ruby stdlib gem (Josh)
- Codex Seraphinianus (Josh)
- Nathen Harvey: Learning Chef (Chuck)
- Redmine Backlogs (Chuck)
- spree_digital (Chuck)
- Benchmarking Ruby 2.1 and Rubinius 2.0 (Erik)
- The DOT Language (Erik)
- DuoLingo (Erik)
- Charlie Kaufman: Screenwriting Lecture (Erik)
- Louis CK (Erik)
- @SeinfeldToday (Erik)
Book Club: Confident Ruby with Avdi Grimm
ERIK: So, what are we going to talk about?
JOSH: European breakfast pastries, right? [Chuckles]
JOSH: What else do we talk about with a Berliner?
[Hosting and bandwidth provided by the Blue Box Group. Check them out at BlueBox.net.]
[This podcast is sponsored by New Relic. To track and optimize your application performance, go to RubyRogues.com/NewRelic.]
[This episode is sponsored by Code Climate. Code Climate automated code reviews ensure that your projects stay on track. Fix and find quality and security issues in your Ruby code sooner. Try it free at RubyRogues.com/CodeClimate.]
[This episode is sponsored by SendGrid, the leader in transactional email and email deliverability. SendGrid helps eliminate the cost and complexity of owning and maintaining your own email infrastructure by handling ISP monitoring, DKIM, SPF, feedback loops, whitelabeling, link customization and more. If you’d rather focus on your business than on scaling your email infrastructure, then visit www.SendGrid.com.]
CHUCK: Hey everybody and welcome to episode 127 of the Ruby Rogues podcast. This week on our panel, we have James Edward Gray.
JAMES: Good morning everyone.
CHUCK: Katrina Owen.
KATRINA: Good morning.
CHUCK: Avdi Grimm.
AVDI: Good morning.
CHUCK: Josh Susser.
JOSH: Generic greeting.
CHUCK: I’m Charles Max Wood from DevChat.TV with a quick reminder to go check out my free freelancing video at GoingRogueVideo.com. And we have a special guest this week and that is Erik Michaels-Ober.
ERIK: Guten tag.
JOSH: [Chuckles] Guten tag. Hey, Erik.
ERIK: Hey, how’s it going?
JOSH: Good. Welcome aboard the show.
ERIK: Thanks, great to be here.
CHUCK: Yeah, you sound very German this morning.
JOSH: I’m detecting a German accent in the line noise. What’s going on with that?
JOSH: So, where are you, Erik?
ERIK: I am in Berlin. I recently moved to Berlin from San Francisco about three months ago and it’s great. I’m working at SoundCloud now as a developer evangelist.
CHUCK: Oh, nice.
JOSH: Developer evangelist. So, what does that mean actually? Because that’s the kind of position that seems like that’s different in different places.
ERIK: It is. So SoundCloud, for those who don’t know, is the largest community of musicians and also podcasters on the web. And being a dev evangelist basically means I work on providing a great platform for developers to build any sort of audio-related applications. I do quite a bit of travel to conferences and hackathons showing people how they can use the SoundCloud platform to create new applications and to make their existing applications even better with sound.
CHUCK: That sounds awesome. I’m going to break in real quick because I’m a horrible person. I got reminded three different times and I still forgot. We have another Unofficial Rogue and I just want to again thank him for supporting the show. An Unofficial Rogue is somebody who joins the Parley List and contributes $50 a month to the show. And last week, Emily Stolfo signed up as an Unofficial Rogue.
CHUCK: Thank you.
JOSH: Emily is actually super awesome. She gets to be part of Parley for free because she’s going to be a guest on the show soon and she’s like, “No, I’m paying for it anyway.” So above and beyond, definitely.
AVDI: So, thank you for supporting my bourbon habit, I mean all the great things we do on Ruby Rogues.
JAMES: Yes, thank you for supporting Avdi’s bourbon habit. Oh, no.
JOSH: Yeah, Avdi, your bourbon habit is one of the great things we do on Ruby Rogues.
CHUCK: Anyway, back to your regularly scheduled Erik, what are you doing today?
JAMES: So, the reason we had Erik on the show is back in ancient history, we ran this Ruby Rogues golf contest and we said that we would have the winner on the show. We didn’t say plus or minus three years. But we’re keeping good on our promise. Erik won. We’ll put a link to that treat in the show notes.
ERIK: Didn’t I get bonus points? I was actually in Hawaii when I tweeted that, so I could have been out on the beach sipping a Mai Tai. But instead I was, for some reason, doing code golf for Ruby Rogues. So, I think I get extra credit for that.
JAMES: That’s awesome. I just looked at the tweet and it is actually geocoded in Hawaii, which is cool.
CHUCK: So, you were in Hawaii and your submission wasn’t the shark attack one?
ERIK: Yeah. I guess I should have been more creative there.
JOSH: I think more people travel to Hawaii to play golf than to be eaten by sharks. So, I think it worked out.
ERIK: I did survive. Made it back to the mainland safely.
JAMES: So, tell us what you did in your golf tweet, Erik.
ERIK: So, it’s a little bit hard to read, and if you want to see the expanded version, it’s actually included.
JOSH: [Laughs] I’m sorry.
ERIK: As these things tend to be, I guess.
JOSH: Apologizing for the readability of your golf is like apologizing for your pretzels being salty.
CHUCK: Did you write a minifier first?
ERIK: I didn’t. There’s actually an expanded version of the tweet that’s actually embedded in one of the projects I worked on, which is the twitter gem. So if you go to GitHub.com/sferik/twitter, in the etc directory of that project is basically code that does essentially the same thing but in a way that’s more readable. But basically what it does is it creates a graph in the DOT language, which is a graph language and it’s a graph of the Ruby object system. So, it uses Ruby’s object space Object and iterates over every class and then shows the relationships between those classes, which classes inherit from which other classes and basically draws a map so you can see the whole object system in Ruby.
JOSH: Yeah. Being able to see the whole object hierarchy like that is actually really awesome. And it’s one of the things I always miss in the Ruby documentation, is that you can’t easily see the inheritance relationships in classes. So this is actually useful.
ERIK: Yeah, well you can. It’s just 140 characters of
JAMES: What Josh, there’s that one textural line that says inherits from or
JAMES: Come on.
JOSH: Yeah, sure. And that’s totally sufficient.
JOSH: To graphical user interface.
JAMES: That’s all you need. Come on. [Chuckles] No, this was really cool. Do you remember there was an oddity? There were certain versions of Graphiz that complained about the way it generated the output or something? You had to have the right version or you had to modify it slightly to change the output was I think one of the issues when it came out. Because I remember having to fiddle with it a bit before I got it to work. But once I did get it to work and it popped up the screen of the entire graph and stuff, it was amazing.
ERIK: Yeah, and the version that’s embedded in the twitter gem is, I think I cheated a little bit. So actually, the DOT language requires you to have a trailing bracket at the end, curly bracket, to close your graph. But the version of Graphiz I was using at least worked if you omitted that. And I wasn’t able to squeeze it in to the 140 characters so I left that off. But I guess other newer versions of Graphiz are a bit stricter and maybe wouldn’t parse that graph.
JOSH: Didn’t I figure out a way to make this have enough room for that?
ERIK: Yeah, I think that’s right. We were chatting about it after I submitted it and I’m sure it could better. But yeah, golf is just terrible code anyway. But the version that’s in the twitter gem I would actually recommend. It’s really useful code. So the version in the twitter gem is modified slightly so that it shows not the entire object system, the entire object hierarchy of the Ruby language, but just the object hierarchy of that Twitter:: namespace. So you can just see the object graph for that library. And the code, basically you can just put in whatever namespace you want for any gem and see the object hierarchy for that particular gem or a library.
So I’d invite anyone. It’s MIT-licensed and you’re free to take this and use that little snippet in your library to generate graphical representation of the objects that you use. And to me, I think, when I’m using a new library or looking at a new project, I really like to see that just to quickly at a glance understand the design of the system and get a sense of how complex it is and the different objects and how they relate to each other and work with each other.
JOSH: Okay. So I’m looking at the code in the twitter gem for doing this and it’s 50 lines of code as opposed to 140 characters. [Chuckles]
JOSH: And I actually find the 140-character version more readable.
ERIK: Well it’s interesting. One interesting constraint of doing a longer version of this is that I couldn’t use any objects because if I created an object while generating this graph, it would pollute the graph itself. Because it’s a graph of all the objects.
JAMES: That’s awesome. Good point.
ERIK: So basically, I had to write completely non-object-oriented code to do it. So I agree, the code to do it is a bit ugly but it has to be.
JAMES: That’s a really neat point. I like it. So we’ve been talking a lot about this. But let’s actually get into it. Erik, you maintain, I would argue, two really cool gems for the interface to Twitter in Ruby. Why don’t you tell us how you got into that and why you do that?
ERIK: Yes. I guess it started, I don’t know, maybe back in 2008 or so. And John Nunemaker created this gem called the twitter gem. I was using it at the time I was cofounder and CTO of a company, a little startup in San Francisco that’s still around called 140 Proof. And we were doing a bunch of Twitter analytics, building all these apps using Twitter API. And the gem that John created was missing a few features that I wanted. I contributed a few patches to it and just went down that rabbit hole of switching over the whole way of communicating with HTTP. At the time I think it was using HTTParty. And I switched that over to using Faraday. Then I started contributing to Faraday.
And yeah, I just went down. It was like my entry to open source. I’d done a bit of open source before that but this really just got me working on a bunch of different projects related to JSON parsing, HTTP wrapper APIs, and specifically doing things with twitter gem. And originally, in a very early version of the twitter gem, it had a command line interface built into it. So it was both an API client for doing general things with the Twitter API but also for hacking on the command line with Twitter. And in version 0.5 of the gem before I started working on it, John Nunemaker ripped that out and said this should really be a separate library. But he never actually made that a separate library.
So I ended up doing that a couple of years down the road and that’s called T. It’s basically just a command line interface to Twitter. So you can use Twitter data with pipes. It has an option to export the data as csv. Thank you, James. So yeah, I think basically people use that for archiving tweets or storing personal collections of them because Twitter itself used to not be so good at that. Now I guess it’s a little bit better. But the main thing people use it for is to search through old tweets. Because Twitter’s search functionality, their index only goes back about a week or two. And the way the T gem works is it will get all of the tweets that a user has tweeted or all of the tweets in your timeline using the API and then search through just that set. So it’s a little bit slower but it’s much more comprehensive and it’s actually pretty fast for what it’s doing.
JOSH: I’ve used it for doing management of lists on Twitter.
ERIK: Yeah, it’s great for that. For example, if you want to take everyone who you’re following at a specific point in time and add them to the list, you can of course create a list with the T CLI and then you can say t following which will list out all the people who you’re following, and then you can pipe that to t list add and all of those people who you’re following will be added to a list. You say, t list add <the name of the list> and then the pipe will give as input to that command all of the people who you’re following. So yeah, if you want to make a list, let’s say you’re following 300 people. To do that manually would be quite laborious. And T gives you a quick way to do it.
JAMES: It’s so cool. That’s what’s awesome about the gem I think, is that you can pull data out of there and really easily pipe it into something else.
ERIK: Yeah, it’s designed to basically be like a UNIX utility. So it will work smartly with pipes and redirects and things like that.
CHUCK: Alright, I’m a little curious how you wind up making the transition from, “Oh here are a few patches for things that help me out,” to maintaining the gem. Was there a passing of the torch or something?
ERIK: It was basically just a giant yak shave. I think I just started working on it and then I said, “Oh, I should improve the documentation.” So I wrote all this YARD documentation and then just started refactoring things. So I was the main committer on it and John Nunemaker, he started a lot of great projects and I think he was busy working on something else, like MongoMapper at the time caught his attention. And he wasn’t really maintaining it anymore.
Actually, Wynn Netherland who also works at GitHub now with John, the two of us were maintaining it for a while. Then Wynn stopped maintaining it and started working on some other things so I just became the de facto maintainer of that. It’s had a number of maintainers and contributors across its lifetime. But yeah, it’s a true open source project in that way, I guess. So it’s great. It’s benefitted from the contributions of many people.
JAMES: That’s really cool.
CHUCK: I’m also curious as far as Twitter goes. How often do they change their API and how much work is it for you usually when they do that?
ERIK: That’s a good question. They used to change it a lot more than they do now. The Twitter product and feature set has stabilized a lot over the years. But back in 2006, 2007, 2008, they were adding new features to the product all the time and adding new APIs for that all the time. And one thing that was cool is that Twitter as a company would often release API for things before those features even existed in the product. They don’t really do that anymore and now, unfortunately, there are some features in the product for which there are no APIs, which is a little disappointing.
But it used to be changing all the time. But now it’s pretty stable. Twitter API version 1.1 which was released, I don’t know, maybe 9, 12 months ago, something like that. I don’t want to say that’s the final version of the Twitter API but I think that represents a pretty solid foundation of what the Twitter API is and what Twitter is. And unless Twitter becomes something fundamentally different, I don’t expect the API to be changing too much going forward.
KATRINA: What’s the most challenging aspect of maintaining a big popular project like the twitter gem?
ERIK: I don’t know. To me, I love it. People use it all the time and because it’s a Twitter-related library, they’re always tweeting at me and telling me how much they like it or if there’s a bug, whatever, I’ll normally find out on Twitter. But it’s actually great to get that instantaneous feedback from people on Twitter about the library. And I would say it’s pretty stable now. So there are occasionally bugs, but I would say in general people are pretty happy with it. So one of the biggest challenges I guess is making it work across multiple Ruby implementations. And Travis is something that makes that really easy. And I test the twitter gem across Rubinius and JRuby and would like to test it across on things like Topaz as well.
To me, there’s a lot of really exciting things happening in this alternative Ruby implementation space. To me, that’s something I’m very conscious of. But honestly, I wouldn’t call that a challenge either. Those projects have come a really long way since when I started testing on them. And now generally, if the tests pass on MRI, they’re almost always just automatically pass on JRuby and Rubinius and I don’t really have to do anything. The only thing to look out for is gems that have C extensions and make sure I don’t depend on any of those because they don’t play that well with JRuby in particular.
KATRINA: So do you spend a lot of your time on other open source projects these days?
ERIK: Yeah. I do a lot of open source stuff. Probably the most famous or popular project that I work on is RailsAdmin. I’ve also done quite a bit of work on Thor, which is a toolset for generating command line interfaces.
KATRINA: I love Thor. I’ve used it a ton.
ERIK: Thor, it’s the most popular software in the Ruby community that most people haven’t heard of or really used.
ERIK: Basically like the command line interface for Rails. Like when you say rails new you’re using Thor. That all depends on Thor. When you’re using Bundler, when you say bundle or bundle update or whatever, Bundler is built on Thor. T, the command line interface for Twitter that we were just talking about, that’s built using Thor. So yeah, it began down that rabbit hole. First worked on Twitter and then built this Twitter command line interface on top of Thor and then started maintaining Thor with Yehuda. Yehuda Katz is the main creator and maintainer of that.
JAMES: So the command line interfaces you’re talking about here that Thor excels as is when you have one command with a whole bunch of subcommands, like Git, right? git branch, git commit et cetera. That’s the kind of thing Thor excels at, right?
ERIK: Yeah. It’s particularly good at that. Yeah, you can just use opts parse. Ruby has some things in the standard library to build command line interfaces. But just like you said, they’re not so conducive for doing complicated sub-options and parsing out sub-options and things like that where that’s what Thor is really designed to do, to build systems that are like Git. So in the Twitter CLI, T, one example of that is you can say
and then there are all these sub-options for that. So you can delete a tweet, you can delete a direct message, you can delete a favorite, you can delete a list, you can basically unblock a user, like delete a block. These are all subcommands under the t delete command.
AVDI: That’s an interesting organization. I’m a little surprised that it’s t delete and then a thing versus t the thing and then delete. Not saying one’s worse or better, just surprising.
ERIK: Yeah, to me that was the logical design of the app. Because you’re like, “Okay, I want to delete something,” and you can say t delete
Deleting a direct message, as far as I know, that’s only exposed by the API. There’s no way to do it via the Twitter.com interface. But sometimes, you fire off a direct message to the wrong person or something like that and really want to delete it. And t is a really simple way to do that.
The other example of that is t stream, so there are all these streaming features. So you can t stream a list, you can t stream a particular search. So you can say t stream search and then give it a keyword or a list of keywords and then it’ll show you every tweet in real-time that’s using those keywords or anyone who mentions those keywords on Twitter.
ERIK: And then the other thing. I’ve been pushing toward the version 5 of the twitter gem that currently I have release candidate 1 out and should be shipping RC 2 any day now. Basically, version 5 builds in streaming. Previously, you had to use two separate gems if you wanted to talk to the Twitter REST API and the Twitter Streaming API. But in version 5, that will all be built into the twitter gem. And I think all the previous streaming gems for Twitter depended on EventMachine, which I didn’t want to build in because it just seemed too heavy of a dependency. But I’ve been able to implement Twitter streaming in version 5.0 without depending on EventMachine.
JAMES: How’d you do that, Erik?
ERIK: It was a lot of work, actually. And I can’t take credit for all of it. I actually got a lot of help from a few people. Steve Agalloco wrote the majority of the code. But he wrote it in a standalone gist. So I took the code that he wrote. He’s the one that works on TweetStream which is one of the EventMachine-based Twitter streaming clients. And he’s also done a bunch of work on the twitter gem itself. So he’s familiar with it. TweetStream depends on twitter and uses twitter objects. So when you get an object back from TweetStream, it’s a twitter object from the twitter gem. So you can use those interchangeably. So it really made sense for it all to be in one gem and Steve did most of the work on that. I just merged it into the project.
And I also got a ton of help from Tim Carey-Smith and Tony Arcieri who both work on Celluloid. And originally I wanted to do async streaming you could open up multiple streams at once and I was using Celluloid for that. But at the last minute, I reverted the Celluloid dependency just because it was adding more complexity than I wanted. And I’m planning to add that back in a future version but for the first version of streaming, it’s just going to be blocking synchronous streaming. So you say it starts streaming and then it doesn’t stop until you tell it to stop or kill the process.
But in the future, I’d like to be able to have streams implemented as futures using Celluloid futures so you can just spawn off a stream and then it’ll keep streaming. You can have multiple streams running at once and they’re not blocking. But the interfaces for that were getting a bit complicated and the code was getting a bit much. So maybe that’ll be in the 5.1 release. But 5.0 is going to be without Celluloid.
But anyway, those guys helped a lot on the implementation of it, even independent of Celluloid. And actually as part of that, I contributed a few patches to Tony’s HTTP gem which is also worth looking into. I’m actually using that. So that has a nice HTTP request object that I’m using in the twitter gem. So even though Celluloid is not a dependency, Tony’s HTTP gem is and I’m using the request object there.
JOSH: So Erik, you’ve mentioned a couple of times dealing with dependencies on these open source projects. And dependency management is one of the hardest things to deal with in software engineering. I’m curious. Do you think that enough attention is paid to that when people are doing open source projects or is it always just a big mess?
ERIK: Yeah, it’s often a big mess. It’s a great question. I’m glad you asked that. I do deal with a lot of dependencies. And I didn’t have this as one of my picks but I’ll recommend it now. Yehuda Katz wrote a great blog post called something like the >= operator is considered harmful. Basically, people should really understand the pessimistic version constraint when they’re building gems, gem authors in particular. You should use it for runtime dependencies.
For development dependencies, I actually think using >= is fine because if there’s a new version of a development dependency, let’s say a new version of RSpec that breaks your specs, it’s not going to break anyone’s code. It’s just a development dependency and you actually want to know about that sooner rather than later. But for runtime dependencies, it’s really important to specify an upper limit on your dependency. So you either be using, if you use >= you should always use it with < and otherwise just use the pessimistic version constraint. That’s probably the number one mistake I see in Ruby open source projects, people misusing or not using the pessimistic version constraint in runtime dependencies.
JOSH: Okay. Do you think that there’s still an issue with semantic versioning versus something else?
ERIK: If a project doesn’t use semantic versioning, I usually just go on their issue tracker and start screaming bloody murder. At this point, I just assume everyone’s using it, unless they explicitly state that they’re using a different versioning scheme. Because there’s basically no responsible reason not to do semantic versioning. Yeah, that’s a really important best practice that everyone should follow. And by and large, most people do. Most people, I think, get that right. But that only works, the only benefit of having that, is if people are using the pessimistic version constraint with semantic versioning. So those things go hand in hand.
JAMES: So if they’re not using semantic versioning, I guess the best thing you can do is actually lock to a specific version of the gem and then choose to [one you want to unlock].
ERIK: I actually disagree. I think if they’re not using semantic versioning, you should go on their issue tracker and complain that they’re not using semantic versioning.
ERIK: There’s almost never a good reason for it and the world would be a much better place if they were using it. So it’s a good opportunity to educate people about semantic versioning. And if they have a good reason for not using it, at the very least they should be documenting that. And if some project, for whatever reason, doesn’t want to use semantic versioning and documents that, then sure, lock to a precise version or use a version that makes sense given their versioning scheme. But I haven’t run into, I work with a lot of gems and dependencies, and I’ve never really seen a great excuse for not using semantic versioning.
The closest I’ve seen to a reason for using it is if you have a gem that tracks it versioning to another library. Let’s say you have a gem that wraps some C library, like Git for example. If you wanted your versioning to match the versioning of whatever you’re wrapping, like you’re wrapping Git so you want to have the same version as that, sometimes what they’ll do is they’ll do semantic versioning but shift it down by a few dots so they’ll have more digits of precision and those extra digits of precision represent the semantic part and the first two or three digits of precision are just a clone of what version that library maps to of the main package that it wraps or interacts with. But that’s the only good excuse not to use semantic versioning that I’ve seen. And even that, I think, maybe that’s not such a great reason.
CHUCK: I think you just told us how to gem install lynch-mob or something.
JOSH: What about pre-1.0?
ERIK: Yeah, so semantic versioning actually has a policy on that. So pre-1.0, you’re not making any guarantees about the API. Minor releases can have breaking API changes. So my policy is I try not to depend on things that are pre-1.0 because in general you don’t want to depend on things that are fragile. And by definition, in semantic versioning things that are pre-1.0 are fragile in that way. But sometimes there’s a good reason for doing that. So if you can’t encourage the developer to lock down the API and release a 1.0, I’ll just use the pessimistic version constraint with three digits of precision instead of two. And then for things that are above 1.0, I’ll use the pessimistic version constraint with two digits of precision. And for people who don’t know what the pessimistic version constraint is, it’s a tilde and then a greater than sign. So it looks like a
JOSH: Tadpole is my favorite description for it.
ERIK: Yeah, yeah. There are some other names.
JAMES: It’s sometimes called the twiddle waka.
ERIK: There are some other names for it as well.
JOSH: Right. Yeah, I think we had a whole thread on Parley about naming things like that a couple of months ago.
JAMES: Even Rails who has been very resistant to the semantic versioning, even now in recent versions they’re not yet moved to semantic versioning but they’re starting to get close to it. Is that how you’d describe it?
ERIK: Yeah. And I think a lot of big projects, like Ruby itself, does not really use semantic versioning. They basically release a major version once every 20 years and then break things in minor versions, I think is their policy.
ERIK: And Linux, for example, I don’t know if they still do this but the kernel used to be something where in the second digit, odd numbers were unstable and even numbers were stable.
JOSH: Yeah, Ruby was doing that for a while, too.
ERIK: Yeah, Ruby did something a little bit similar. So anyway, I think unfortunately some of these big projects actually have good reasons to not follow semantic versioning or they came before semantic versioning really existed as a concept. So in that sense, they’re not great role models to follow. But if you’re just building a gem, you’re not building an operating system kernel or a programming language, you should really follow semantic versioning.
JOSH: Okay, so when I asked about the pre-1.0, I think what I was really getting at was talking to gem authors about when to make that transition to 1.0. I know it took Jim Weirich something like 15 years to get Rake to be 10.0.
JOSH: You know, from 0.9 to 10.0. [Chuckles] But semantic versioning lets you off the hook for having to maintain compatibility if you’re pre-1.0. But I don’t think that’s an excuse to never go 1.0, or I don’t think it’s a reason. And I think that there are other good reasons to go 1.0 and to start supporting version and promises about it.
ERIK: Totally. And I’m a bit of a hypocrite on this. Thor, which I do a lot of work on, is not 1.0 yet. And obviously, everyone has it in their Gemfile .lock. It’s used in production all over the place and it really should be 1.0. And we’ve been talking about getting it to 1.0 for a while. It’s currently 0.9. I wish I did a better job of practicing what I preached here. But in general, I think Thor is in that category of big honking projects, like Rake, that you really need to make sure the API, because Rails and Bundler and so many projects depend on it. And if you’re going to make a promise that you’re never going to break the API, you really want to make sure it handles all the use cases you need it to and everything is right. So we just want to be really careful with that on Thor. But most gems don’t have that problem.
CHUCK: So I want to ask a question. I’ve got a couple of ideas for projects that I want to work on. So as I’m starting a new open source piece of software, what kinds of mistakes am I going to make as a new maintainer of a new project?
ERIK: I don’t know. I guess I would say the gem new command, or is that what it is? Bundle new, I mean, where it gives you
KATRINA: Bundle gem.
ERIK: Bundle gem. That’s a pretty good way to get started, if you’re making a new gem. And there’s a bunch of best practices that are built into that. For example, it gives you a Gemfile, which is something that you should use and should have if you’re developing a gem. And it gives you a gemspec and it gives you a readme and a default license and all these things that a lot of first time gem authors don’t think of or forget. I guess you need a gemspec. You couldn’t forget that or you wouldn’t get very far.
ERIK: But it gives you a template for a gemspec and it gives you all these blanks to fill in. So that’s worth doing. But a big mistake I see is people just cargo culting other gems. They’ll just [spine] some random gem in their Gemfile that they use and see how they do it. And a lot of bad practices get distributed out that way. So I would say before you cargo cult another gem, just think about why it is the way it is and maybe if there’s a better way to do it, or just look at two or three different gems to see how they do it instead of just picking one and then take the consensus of the three that you’re looking at, rather than just cargo culting one. Cargo cult three is my advice, I guess.
KATRINA: What about changelogs?
ERIK: Changelogs are great. They’re a real pain to maintain. And I used to not have one for the twitter gem and some of the other projects that I’ve worked on and people really complained. For me, as a maintainer, a changelog is annoying. When you have a release that’s ready to go, you just want to ship it. You just want to be done with it and put it out there. And a changelog is like this laborious step of going through every commit and figuring out which ones are important enough to highlight in a changelog and let people know about and summarize the release. So I was actually pretty resistant to doing that at first but I’ve completely come around on that. I maintain a changelog on almost all my projects and find them really valuable. When a new gem is released that I depend on or use, I always look at the changelog. And if there’s not a changelog there, then I’m always disappointed by that. So I think changelogs are great.
The hardest thing with a changelog is just the right level of granularity. A changelog that just is a list of all the commits, so my argument when people ask for a changelog was basically the GitHub. I tag my releases and GitHub has a compare view. So if you want to see the difference between two versions of a gem, you can just say GitHub.com/maintainer/project-name/compare and then tag1…tag2 and that will show you a really nice summary. It will show you all the commits that changed between those two versions.
But if it’s more than five or ten commits, that’s actually probably more information than the person looking at the changelog wants. And really, they just want a summary of the breaking interface changes and things that matter to them. They don’t really care if you’re refactoring or cleaning up whitespace or all these other noisy commits. So I think having a proper changelog where you go through and say, “Okay, what do my users really care about? Let me highlight those changes,” that’s really a lot more valuable than just saying, “Here’s a list of the 500 commits that changed.”
KATRINA: So would a changelog be important for something that is open source but not a gem?
ERIK: Could you give an example?
KATRINA: I have an app that’s open source, exercism.io. And would people be looking for a changelog in that, for example?
ERIK: I think it’s more important for gems, because people specify gems as dependencies and so they want to know what if an API changed, what changes they need to make. For an app, it’s more for you and your personal record keeping. If you want to know when a change was made, you can summarize that in a changelog just for your own records. But I don’t know. I find I would normally just use git log for that instead of opening up the changelog.
KATRINA: Yeah, that makes sense.
CHUCK: I think one place where it is important for an app is if it’s something like Redmine or some of these other projects where people are building off of them, forking then, deploying them to their own servers. They’re going to want to know what features have changed and what things are different in the new version.
JAMES: Discourse would be another good example.
CHUCK: Yeah. But if you and a handful of other people are the only people using it, then it probably doesn’t matter as much.
JOSH: Yeah. I have a slightly different tack to take here. Erik, I’m curious if you have amassed any diagnostic signals that you use when you’re evaluating open source projects, if there are warning signs that tell you if a project might be good to avoid or if there are some signs that you look for that shows a project is healthy.
ERIK: Yeah, that’s a great question. There are a lot of things I look at. One is actually the version stuff we were talking about earlier. So if it’s not 1.0, I’m much more skeptical of depending on it because it means API will likely break in the future. It means they haven’t made any promises about the API so that means I’ll need to do more work changing my library or my application to whenever they decide to change the API or I’ll just get stuck on some old version, neither of which sounds great.
CHUCK: Can I derail you for a minute? What exactly does 1.0 mean to you?
ERIK: In semantic versioning, it has a very precise meaning, which is the API will not break until version 2.0 is released.
ERIK: But before 1.0, then you’re allowed to break the API in minor releases. So from 0.1 to 0.2, you’re allowed to have breaking changes according to sem ver, but from 1.0 to 1.1 to 1.2, the API needs to stay the same.
ERIK: So when you release 1.0 you’re making a promise about the API as long as you’re following semantic versioning.
JAMES: And aside from just that, I think there’s a kind of unspoken agreement that 1.0 is the line where we say, “Hey, you could use this in production.” That’s why we allow for those breaking changes before 1.0. It’s like, “I’m still figuring this out. It’s a thing I don’t really know exactly what it ends up looking like yet.” But then once I hit 1.0, I’m saying, “Yeah, I’ve got it figured out enough that we can start using this.”
ERIK: Yeah. That’s a really obvious first thing I look for. The second thing I probably look for is tests. Does the project have tests and is it running them on a continuous integration? And specifically, if it’s using Travis or some other CI system, is it testing them against different Ruby versions? Because again, I don’t want to specify a dependency that only works on MRI, that won’t work on Rubinius or JRuby or some of these other alternative Ruby implementations. So that’s something I look for.
I also look at, there’s a great service called Coveralls, which basically takes SimpleCov. In Ruby 1.9 and later, there’s built-in code coverage statistics which is a rough crude measure of how comprehensive the tests execute the code, how much of the code is executed by the tests represented as a percentage. So ideally, it’s 100. And if it’s less than that, that means there is certain code that’s never exercised by tests. Anyway, Coveralls is a service that after the tests are run on Travis, it will do the SimpleCov analysis of the code coverage and then push that to Coveralls which is a web service that reports that back in the form of a little badge that you will sometimes see at the top of a repository. So if you have tests but they’re not that comprehensive, they’re not really covering the code, then that’s a bad sign. If there’s 100% coverage, that’s great.
And then the last thing I probably look at is Code Climate. If a project isn’t on Code Climate, actually anyone can add it. You don’t need to be the author or maintainer of that library to add it. You can just go to Code Climate and paste in the URL for the project. Sometimes I’ll do that just to see. Again, it’s a pretty crude measure, but it does static analysis. I know you guys have talked about it before and had Bryan on the show as a guest. So if people don’t know about Code Climate, they can just go back and listen to that episode. But basically it’s just a crude measure. It gives you a letter score in the American grading system of A through F. So you get a sense, is the code high quality? Is it unnecessarily complex? Is it well-factored? Yeah, that’s something I look at as well.
JOSH: Do you ever look at the number of issues or open issues or pull requests, that sort of thing?
ERIK: Sometimes I do, yeah. That’s also a good indicator, but not always. Sometimes projects that are very popular will have a lot of open issues. Rails, for example. If you said, “I won’t use projects that have a lot of open issues,” you wouldn’t use Rails.
JOSH: Probably a good choice.
ERIK: Maybe it is. But I think you have to divide the number of open issues by the number of people using it and some very unpopular projects might have a lot of issues that just haven’t been reported yet. So it’s an indicator, but it’s not a perfect indicator. But yeah, definitely something I look at. I guess another thing I look at is just does the project seem like it’s being maintained? When was the last commit? And are there open pull requests that look reasonable to me but for whatever reason haven’t been commented on, haven’t been merged in? There’s no discussion going on there. That’s a really bad sign.
KATRINA: I submitted a pull request to a project two years ago and they still haven’t commented on it.
ERIK: Yeah, that’s [inaudible].
JAMES: They’re thinking hard about it.
JAMES: Sarah Mei actually covered this in her talk at GoGaRuCo, the steps that people use to evaluate projects. And she had some interesting things about it. She asked several people this exact question and got them to define their steps and then she put them all up on slides. A lot of people, I would say, did use similar metrics. They definitely used them in different order or gave different weight to things. And it was very interesting to see. And she grouped them into different categories of this is about the code and this is about the people maintaining it, or things like that. She had these different categorizations of them and was trying to dig down into what does all of this mean and what are we trying to figure out? It was very interesting.
ERIK: Yeah. I watched that talk. That was great. I’d recommend it as well.
CHUCK: So I’m curious. Is it different maintaining something like the twitter gem as opposed to something that’s more along the lines of a Rails engine like the RailsAdmin?
ERIK: You know, they’re both gems. There’s a bunch of differences. I actually gave a talk at GoGaRuCo a year ago, not the most recent one, but 2012, about Rails engines where I talk about some of the differences and similarities, I guess, between Rails engines and Rails apps and also between Rails engines and Ruby gems. And a Rails engine is a Ruby gem but you do some things differently. For example, testing it. To test an engine, typically the best practice for doing this, which seems like a little bit of a hack but I don’t know of any other better way to do it, is to basically just have a simple Rails app inside of your test or spec directory and then mount the engine in that test app, the dummy app. And then test against that dummy app, which is a little bit of a hack, to have this Rails app inside of your test directory. But I think that’s the best way to do it.
JOSH: So I’ve done something really similar to that where it was essentially a Rails app template that we embedded in the engine test harness that would, every time you ran tests it would generate a brand new Rails app to hook the engine into to test there. And it turns out that running rails new, if you’re not going through the database initialization, running migrations, all that kind of stuff, takes just a fraction of a second. It’s really fast. It didn’t seem like we had to check in all the files. We could just have a very simple template that customized the stock rails new into an application that worked well for a testing harness.
ERIK: Yeah, that’s nice. I’ve never thought of doing that. I guess I always think of rails new as being kind of slow. But I guess if all the dependencies are there, then the bundle install after should be pretty quick. The thing that is great about that is then when new Rails versions get released, you don’t have to regenerate that test [back] inside your application.
JOSH: Yeah, that’s exactly why we were doing it that way. It simplifies the dependencies a whole lot.
ERIK: Yeah. And also, if you wanted to test against multiple versions of Rails then that also makes it a lot simpler where you don’t have to have five different Rails apps embedded in your test directory.
JOSH: Yeah, we did take a look at trying to extract that and it was just too idiosyncratic a solution to be able to generalize to everybody. But I think somebody probably could.
ERIK: Yeah, totally. Yeah, you should try to do that. That would be really handy. Maybe I’ll put it in RailsAdmin if you do.
JOSH: Okay, worth talking about sometime.
JAMES: It is worth noting that that practice just described of embedding a Rails app in the test is basically what the Rails engines guide recommends.
ERIK: Yeah. I just think it’s ugly, right?
JAMES: Yeah, it’s weird that there’s not a way to just grab a hold of the engine and ask it things. But it’s interesting. Anything else you think we should cover?
JAMES: Yeah, let’s do that.
JOSH: Can I get claws? Or just the skeleton enhancement?
JAMES: Yeah, once you have the skeleton enhancement, who cares?
ERIK: Yeah, so I was actually listening to a Ruby Rogues episode a few weeks ago with Piotr Solnica and he mentioned a bunch of gems that came out of the ROM project, the Ruby Object Mapper. And I tried just using them. I looked them up and they looked really cool and I tried putting them into the twitter gem just to play around with them. And a few of them, I kept in there. Equalizer was one that came up in that conversation which I’m actually using now in the twitter gem. It’ll be in version 5. But another one which I tried,
AVDI: How are you using that?
ERIK: The twitter gem returns objects that have a unique id. For example, every tweet has a unique id or every Twitter user has a unique id. And when you compare, you might fetch two users in two separate requests and compare those two users to see if they’re actually the same user even though they’re different objects. Basically, if they have the same id, you want them to be the same. You want == to return true. So the equalizer gem gives you a really easy way to do that. So I had custom code in the twitter gem that had been doing that for a long time and now I’m just using equalizer, which I look at their code and it’s actually better at doing that than the code I was doing. It covers more edge cases and is better factored. It’s just nicer code. So I’m using that now.
And then Adamantium was the other one that I looked at. That’s the one that freezes all your Ruby objects, basically turns them into immutable objects. And I actually had a version of this working and ended up backing it out because, why did I back it out? Oh, because it was only compatible with Ruby 1.9 and greater. And for a variety of reasons, I’d like to maintain compatibility with Ruby 1.8.7 even though it’s dead. Basically, if there’s not a really good reason to break compatibility, I try to maintain it. And I didn’t think Adamantium freezing all my objects was a good enough reason to break that compatibility for some people. Also, just benchmarking it, freezing all those objects had the effect of slowing things down pretty substantially on MRI. It didn’t affect other Ruby implementations as much, but since so many people use MRI, I just wasn’t sure it was worth the tradeoff of including that.
But there’s one really nice feature of Adamantium, which is a memoize method. So I wanted to use the memoize method, but not the freezing functionality that’s the core functionality in Adamantium. So I’m actually working with Dan Kubb now on a memoizable gem that should be broken out of Adamantium and can be used standalone. So that’s one of the actual final things I need to do, get that gem released, break it out of Adamantium and make sure Adamantium still works and memoization still works there. And then include that separate gem as a twitter gem dependency and just to do simple memoization.
So basically, if you execute a method, the second time you execute it, instead of redoing whatever computation that method does, it’ll just return a cached value, which is important. It’s very relevant to Adamantium because when you’re freezing an object, if you assign an instance variable when you call a method, which is a pretty common thing to do when you call a method, the second time you call that method, you can’t reassign the instance variable if that object is frozen. So memoization and Adamantium are tightly coupled now and working on decoupling those. Because sometimes you want to do memoization without necessarily freezing the object.
AVDI: Are you doing memoization including methods that take arguments?
ERIK: That’s a great question. The current code in Adamantium only memoizes methods with zero arity. But I think one of the benefits, and probably the first release of the memoizable gem will only support zero arity methods, but future versions might. And I think it’s a really good argument actually, for having it as a separate gem, because it has a life of its own and can evolve. And people can add features to it independent of Adamantium.
AVDI: What’s your approach for storing right now?
ERIK: It actually uses Charlie Nutter’s thread-safe hash implementation.
ERIK: It’s used under the hood. So I think he mentioned that a few episodes ago when he was on the podcast. He has this thread_safe gem which I really recommend everyone checking out. He’s trying to get the same data structures built into Ruby 2.1 as primitive data structures in Ruby. But for now you have to use them as a separate gem and they’re really nice. So there’s a thread-safe hash, thread-safe array, and thread-safe cache. They behave just like hash and array but they give you these thread safe guarantees, which if you’re using JRuby and there’s no global interpreter lock, that’s really nice to have. Or Rubinius for that matter. So if you’re doing that sort of caching, a thread-safe hash is a really nice data structure to use.
AVDI: Right. And you’ve got zero arity so you’re just basing it on the name of the method and nothing else as the key?
ERIK: That’s exactly right.
AVDI: So it’s like you get a single hash per object.
ERIK: Yeah, that’s exactly right. And if you try to account for different arity, that makes it quite a bit more complicated.
AVDI: Oh yeah, very much.
ERIK: So for now we’re just doing the simple thing and that solves many use cases. You can cache many of your methods with zero arity. And I think we just need more time to think about what data structures make sense and what we should do, whether it actually makes sense to support methods with greater than zero arity.
AVDI: Right. Well that can explode really fast in complexity because somebody that decides, “Oh, this is really cool. I want to cache this method that takes in some arbitrary argument like the method that gives you information about a Twitter user for instance.” So the argument is the name of the Twitter user and returns information about the Twitter user. Then they throw it into a program that retrieves information about arbitrary Twitter users and suddenly you’re caching an enormous amount of information. So then you have to start thinking about, “Okay, do we want to do these, drop stuff off the cache if it’s old, or something like that.” Yeah, it’s definitely a lot easier to support the zero arg case.
ERIK: Yeah, exactly.
JAMES: Plus there’s the question of how do you compare arguments. Is it a straight equality check?
AVDI: Equality, identity, threequality. [Chuckles]
JAMES: Yeah, basically. Right. In the simplest case, it can be just putting the method name followed by the arguments in an array and using that as a key to a hash. That actually works in Ruby because array can be a key to a hash. But there are lots of edge cases in there that may or may not be acceptable like we just talked about. It’s interesting, Erik. You talk about the twitter gem being your testing ground for these ideas and cases where you were just playing with these. I think I’ve actually learned about gems before by seeing them used in the twitter gem. I just looked and it’s not true today but I think in the past the twitter gem used Hashie. Is that true?
ERIK: Yeah. The original implementation used Hashie.
JAMES: Yeah. So I learned about the Hashie gem because I saw twitter gem returning those objects to me and I’m like, “What the heck is this?” and looked into it a little bit. So it’s interesting to hear you say that you’re using this as this testing ground.
ERIK: Yeah, that’s exactly how I use it. It’s great for that. And I think everyone should have some gem like that. API wrappers, I think, are actually really good testing grounds for this because you have your objects, like a Twitter user object or an object that represents a tweet. Then you have to do some HTTP stuff. So to me, there’s just the right level of complexity where you can play around with lots of new ideas. And if you want to try out memoization or freezing objects or something like that, you just have a little testing ground to do it. And I definitely treat the twitter gem that way.
Speaking specifically to Hashie, that was one of the original dependencies that John Nunemaker had in the gem. And actually, one of the reasons why I got involved in the project was to factor that out. I’m not a big fan of Hashie and didn’t like the type of objects that it generated. [Chuckles] It was in the twitter gem at some point, but it’s not something that I would necessarily, and it’s an interesting gem, but not necessarily something I would endorse using unless you’re just doing very quick API hacks.
AVDI: I want to hear more about that. Because I think that’s the kind of experiential opinion that sounds like hard-won knowledge.
ERIK: Hashie is this gem that basically will take a hash. And it’s like in Rails. You have this concept of hash with indifferent access where you can access the hash using either a string or a symbol and go back and forth between them. You don’t have to worry about it. Hashie takes that one step further and gives you method access, keys in the hash.
AVDI: So it’s similar to OpenObject in the standard library.
AVDI: Yeah, OpenStruct, sorry.
ERIK: Yeah, exactly. So basically if you have a hash and it has a key called foo and a value pointing with the arrow or colon to bar, you can say with the brackets symbol foo to get out bar, string foo to get out bar, or you can say dot foo to get out bar. And I don’t like it specifically because it makes it, these keys are coming in from a third-party API, from external API that you don’t really have control over what the keys are. They’re coming, in this case, from Twitter. So there’s nothing to say that Twitter couldn’t return some keys in that hash that overwrite method names in Ruby, in Ruby’s basic object.
For example, Ruby. Now it’s called object_id but .id used to return the id of the object according to Ruby. And Twitter also has this concept of an id. So that’s an example of a conflict there. And hash is another got example, the .hash method. Every object in Ruby has a .hash method so it can be hashed when it’s put into a hash. And it’s confusing that Ruby calls hashes hashes but, yes.
JOSH: Yeah, see in any real language, they’re called dictionaries.
ERIK: Yeah, or hash maps or maps.
AVDI: So you’re a real Python fan, huh, Josh?
JOSH: Oh, absolutely, yeah.
ERIK: Anyway, so Hashie I just found to be not so good because you didn’t have, and it wasn’t clear what the behavior would be, which method should be overwritten. Should the Twitter id method override the Ruby id method or should the Ruby id method override the Twitter method? Obviously, there are things you can do alias methods and get around these, but to me you should really just define Ruby objects that know what their attributes are and map them based on that, define your own methods that are mapped based on the hash. And this gives you the ability to do nice things.
For example, a Twitter user has a created_at property for when that user signed up for Twitter. And if you’re using Hashie, that will just return the string that Twitter’s JSON returns to you. But by defining your own method, you can actually convert that to a Ruby Time object and I think that’s what most Rubyists would expect created_at to return, to return a Time object.
ERIK: Another example of that is the website method. So every Twitter user has a website that’s associated with their Twitter account. Mine is my GitHub profile. Again, you could just return the string, but I think it’s a little bit more Ruby-like to return actually a URI object, a Ruby URI object when you call user.website. So for me, this is one of the big advantages of defining custom objects instead of using Hashie. And Hashie is great for, like I said, quick hacks. If you’re just building out something for a hackathon weekend or something, fine. Use Hashie. But if you really want an API wrapper that people are going to be using in production applications, it’s worth taking the time to define proper objects for each of the objects in the system.
AVDI: It seems like a good general rule is that if you have an object that is like a bag of attributes, it seems like a good rule that the subscript operator, square brackets, is what you use for raw access. And if you’re going to get an attribute by method, then maybe the method adds some convenience over the raw access or some more semantic meaning or something like that.
ERIK: Yeah. On twitter objects, I expose and attrs method that gives you raw access. So you can always get that string representation of a date or the string representation of the URI if you want it. But most people use just the normal methods to access those.
The other big advantage of defining your own custom Ruby objects is that for example, that object graph, the object hierarchy that we were talking about at the very beginning of the call, you can’t generate that if you’re using Hashie. You don’t have any concept of what the objects are. So if somebody’s looking at a project and they want to see what are all the entities in this gem, if you’re using Hashie those are all hidden. So yet another advantage of defining your own objects.
JAMES: I definitely agree with everything Erik just said and feel like it was an excellent point and we should definitely push that. In defense of Hashie, just so we cover both sides, it is actually a collection of tools, one of which can be used to define these hash-like objects with predefined properties. That one’s called Dash. And you can actually explicitly say which properties it does or does not have. And typically, you do that in your own classes so you still get the object hierarchy and stuff. So that’s one thing.
There’s also a trash, is another thing in there, which works like Dash in that you define these properties but you can specify what they come from in the original info. So if you’ve got some Java-centric API or whatever that’s using the camel case and you want to use it as a more Ruby-esque underscore, then you can give the from camel case name and define the property the underscore one. Again, this is explicit property definition. So it doesn’t have that problem of just random fields and stuff.
So there are some interesting tools in there and I think it’s not totally an unviable tool. But another thing I would argue is I had a few cases. It typically comes up when I’m talking to some kind of payment gateway. Typically every interaction with the payment gateway involves it dumping about 40 billion fields on me, of which I care about three.
JAMES: Did this payment go through or something. So my goal is I pull out the three fields that I actually care about and use those to do whatever logic I want. But because it’s something like a payment gateway and I want this wonderful audit trail, I take that thing they gave me and shove it somewhere for reference purposes. And I think on something like that, Hashie can be fine even in the form we were talking about where you have these random set of fields. Because if they start sending me 4 billion and one fields, then I would be okay with picking up that extra data.
But I definitely agree with what Erik said and the API and defining your own objects. That’s actually why I find the ROM ecosystem tools really interesting, because they lower the barrier to doing that kind of stuff with libraries like equalizer and concord and stuff like that.
ERIK: Totally. I agree with everything there. And actually, I was referring specifically to the Hashie::Mash data structure, which the M in Mash stands for method to give you method access. And then Hashie 1.0, it didn’t have some of those features that you were talking of where you can build up your own hash-like object with whatever properties you want. That was mostly rewritten. The library was largely rewritten for 2.0, which was released earlier this year. And 2.0 is much nicer. But when I was evaluating whether Hashie was a good fit for the twitter gem, I was doing that in the 1.x days or maybe even the 0.x days of the Hashie gem. And back then, it was much less flexible. But it’s a good gem to know about and it’s definitely useful for certain things. So I don’t need to give it a bad rep.
AVDI: One other question about the twitter gem. You mentioned to me recently that you’d started to use the null object pattern. Can you talk a little bit about how you use that?
ERIK: Sure, yeah. It was actually a feature request from one of the users who again, because you’re dealing with this third-party API,
JAMES: The user was Avdi, right?
JAMES: Just checking.
CHUCK: Yeah, it was all for naught.
ERIK: [Chuckles] Basically the Twitter API is web service and it’s unpredictable. And sometimes, for example, when you get a tweet back, that tweet will have an embedded user object in it and people expect that Twitter user object to be there within the tweet. So that way, when you display the tweet, you can also display the name of the user who tweeted it and the profile picture or something like that, depending on your application. But sometimes, for whatever reason, Twitter will return a tweet with no user, with no embedded user. It’s, I think, maybe their internal user service didn’t return the user fast enough and so the tweet just gets returned with no embedded user. I’ve actually never seen this, but a user reported that it was possible. So I took his word for it and basically, instead of having it just return nil there, I had it return a null object. So if you expect there to be a user in your tweet, 99.9% of the time, there’s going to be a user there whose name you can display. But for the .01 or maybe even less percent of the time when there’s not a user, you won’t get a no method error if you’re trying to call methods on that embedded user object. You’ll just get nothing. So that’s another feature that’s new in the 5.0 version of the gem that should be released pretty soon.
AVDI: You’ve got a pattern in this null object code that I’ve never seen before. Or an idiom, I guess I should say. You’re conditionally defining some methods depending on the Ruby version and you’re actually doing it by saying
def respond_to?(blah, blah, blah)
You’ve got the body of the method, then end, so the end of the method. And then after the end of the method, you have
if RUBY_VERSION < “1.9”
ERIK: Yeah. I think I shamelessly cargo culted that from the backports gem, which basically, that’s its business, to do that sort of thing. So yeah, that’s right.
AVDI: You know, that’s funny. It makes perfect sense but it never actually occurred to me that I could put a statement modifier at the end of a def.
JAMES: Now I challenge you to try while.
ERIK: For hot-swapping your Ruby version?
AVDI: Might never load.
ERIK: What’ll happen there? The class will just not compile, right? Until the while returns?
JAMES: Yeah. Well very cool. I loved what you said about having the gem to be your test environment. I agree that that’s a great thing to have that where you can go, “Hey, this is a neat idea. What if I go and convert everything to use that?” And you can do it on a branch. You can see, like you said, if something like Adamantium ends up resulting in a performance hit or whatever, because you’ve got a pretty big enough of things to try. And I think that that playground, that experimentation area, is really important.
ERIK: Definitely. And I’ve built a few other gem wrappers as well. I built one for the Sunlight Congress API which has data about things in the US Congress, votes and things like that, in the house and senate, like which senators and congress people voted which way on which bills. So I did a Ruby wrapper for that. If you say gem install congress that’s that gem.
I did one for Mt. Gox, which is the largest Bitcoin exchange. And I was actually doing some Bitcoin arbitrage between different exchanges back in the day. So I actually wrote a couple of different API wrappers for Bitcoin exchanges. And I even did a gem that wraps the RubyGems.org API. That’s the gems gem. So if you say
gem install gems
you will get the gem for accessing gems basically, getting metadata about RubyGems, which versions have been released and when they were released and who the authors are and things like that.
JOSH: That’s awesome.
CHUCK: I can’t help it, but I have to ask this. If you install the congress gem, will your machine shut down for a week?
ERIK: Hopefully not.
JOSH: No, but it will tell you who you don’t want doing ops work on your machine.
JOSH: Keep these guys away from my machine.
ERIK: Yeah. What was I going to say? There was something else. Oh yeah, I was just going to say I’d encourage anybody who, there’s so many APIs that don’t have Ruby wrapper libraries around them. And even ones that do, it’s a great playground to just experiment with ideas and concepts like null objects and freezing objects and memoization in Ruby. There’s basically no good excuse for not writing one of these Ruby wrapper libraries. And if you want to use Twitter as an example or ask me questions about it, I’m happy to help anyone who wants to get started doing that. So yeah, I would encourage everyone. Just go write a Ruby wrapper for your favorite API.
CHUCK: I have another question for you. With all these gems that you maintain, how do you still have a job and get stuff done?
ERIK: [Chuckles] Well that’s a good question. A lot of them I created while I was a Code for America fellow. Basically my job as a Code for America was to produce open source software. For example, I developed the congress gem while I was doing that. And if you follow some of these best practices, these gems maintain themselves, more or less, unless there are big API changes. The congress almost never changes. It’s this institution that’s been around for a few hundred years and the votes and the basic core concepts of it don’t change very often. So things like that actually don’t require much maintenance.
When they do, I’ve written some scripts to automate that. For example, if there is a new version of Rake or some gem that’s a dependency of almost all my other gems, RSpec is another example, I’ve written scripts to recurse through my directory of gems that I maintain and update those dependencies programmatically. That’s a little bit of scripting and a little bit of just following good practices so that you don’t have to be constantly churning.
JAMES: Automating that workflow.
CHUCK: That’s right. Writing code to write code. Alright, well do you guys have any other questions for Erik? I know this episode’s gone a little bit long but it’s been really good.
AVDI: What you were just talking about actually prompted another question in my mind. if people are writing gems that wrap HTTP services, one thing that can happen is if I use that gem, I’m now bound to whatever HTTP backend you chose to use in that gem, which can have some interesting implications. If let’s say you use Ruby’s built-in HTTP libraries, now if I want to do some asynchronous processing using your gem, I might have to put that in a thread as opposed to using EventMachine::Reactor stuff. I guess this question really boils down to, should everybody who is writing gems that wrap external services be using Faraday?
ERIK: Enthusiastic yes. Yeah, that was one of the things that got me into the twitter gem, was to decouple the twitter gem from Net::HTTP. And Net::HTTP is still the default adapter for the twitter gem, but if you want you can easily switch in a different adapter. You can use EM-HTTP for EventMachine. You can use Typhoeus, you can use Patron, and a variety of other adapters that I’ve never even used or heard of that Faraday supports. For those who don’t know Faraday, it’s basically the opposite of Rack. Rack lets you define response middleware and Faraday is for defining request middleware. And at the end of that middleware is an adapter. But you can also insert things in the middle of that request cycle that you want to happen every time.
For example, in the twitter gem, the response handling, parsing a response into JSON for example, is handled all in middleware. There’s no actual code in the twitter gem for JSON parsing. That’s just Faraday middleware that I put into my middleware stack and everything that comes back from Twitter is automatically parsed as JSON. Then the other example of that is error handling. So if Twitter returns a 200 code then everything’s okay and you parse it as JSON and you go forward. But if it’s not 200, then you can handle that differently based on exception or do something else. All of that’s handled in the middleware.
And the thing that’s really nice is I actually expose that middleware interface, which is maybe a little bit ugly, like exposing too much of the internal implementation. But it’s actually really nice. For example, if you’re in China and you’re behind a firewall and you want to proxy your Twitter request. You don’t want to hit the Twitter server directly. You want to go through a proxy server because the Twitter endpoint is blocked by your firewall. You can just insert proxy middleware at the top of that middleware stack and it will work perfectly.
And another good example of using Faraday is for logging. So if you want to log HTTP requests, like there’s some bug and you’re trying to track it down, you can just insert logging middleware and then everything, as long as you insert that at the top of the stack or you can actually insert it in the middle if you want to, if you know an error is happening only at a certain point in the HTTP request, then you can just log out different information about your HTTP requests. If you’re writing an HTTP wrapper, definitely, I would recommend using Faraday.
JAMES: So to go back to Avdi’s question, what if I suddenly decided to make my requests parallel, it turns out Faraday supports that too.
CHUCK: Alright, well let’s go ahead and wrap up the show. Thanks for coming on the show, Erik. It’s been a lot of fun.
ERIK: Yeah, it’s been fun for me as well. My pleasure.
CHUCK: And we’ve only owed you for a year and a half.
ERIK: Better late than never.
JAMES: We get around to it. We’re just slow.
CHUCK: Yup. Alright, well let’s do the picks. James, why don’t you start us off?
JAMES: Okay. I have for a tech pick, we had the Food Fight Show guys on our podcast a while ago talking about infrastructure and stuff like that. Chefs, I think. Anyway, they run the ops podcast modeled off of Ruby Rogues and a similar format, these roundtable discussions. It’s really good. One of the things that came up on our episode was Chad Fowler’s blog post about immutable infrastructure. And at the time, they told us when they were on the show that they were trying to get Chad on their show to discuss that so they can have a great discussion around it. And they did that shortly after out show, actually. But it took me forever to get around to actually listening to it. And it’s a cool episode. So if you’re at all remotely interested in that kind of stuff, you should go listen to the Food Fight Show, especially that episode, the Immutable Infrastructure, because it’s great.
And then on some less techy picks, I’ve mentioned that Kathy Sierra is back in the world of social media and it’s so great to have her back. I can’t believe how many things I’m getting out of just following her on Twitter. One is I found this new electronic artist that she recommend I listen to named BT. I guess BT is a programmer or something but also an electronic artist. And I’ve really been digging that music, especially to program to. So that was a great find.
Also Kathy just wrote a wonderful blog post about conference presentations. If you give conference presentations, please forget everything you’ve been taught and then go read this blog post and just stop there. That would be excellent for us.
AVDI: I read that, but I had not realized that it was Kathy Sierra.
JAMES: It’s Kathy Sierra. Yes, okay. Those are my picks.
CHUCK: Awesome. Avdi, what are your picks?
AVDI: My picks. So I think I mentioned the last time I did picks that I’ve been iterating on my travel toolkit things that make my travel more comfortable and especially as I’ve been doing a lot more flying internationally. The last few things that I added and tested out on the trip that I just got back from include a new neck pillow. This is a little thing, but I had a neck pillow for a long time for sleeping on airline seats. But I was curious if better ones existed, since I just grabbed the first one I saw at Wal-Mart.
I looked around for a bit and I found the Cabeau Memory Foam Evolution Neck and Travel Pillow, which is pricey as these things go. But it’s memory foam so it’s a bit firmer than the one I had and it folds up. It squishes down to a quarter of its original size into a little bag and then you pull it out and it expands back out to its original shape. It’s much higher. It’s both firmer and higher than most of the neck pillow you see at airports. So it actually really does hold my head up as opposed to trying to. The shape is different. The back of it is actually thin so it doesn’t push the head forward from the seat. But the rest of it is thick. It’s got a fastener in front to make sure it stays closed around your neck instead of just letting your head fall out. It’s just well-designed, I guess. And I tried it out on my trip to Belgium and it worked really, really well. It was much more comfortable than the last neck pillow I used. So if you’re stuck in the cattle car class and don’t have one of those seats that you can lay down on, this seems like a pretty good purchase.
Another thing that I brought with me, I splurged on this one. I’ve been looking at various noise-cancelling headset s and things like that for a while. And I got the most expensive pair of headphones I’ve ever bought and probably ever will buy. They’re $300. But it’s called the Parrot Zik and it’s this pair of noise-cancelling Bluetooth headphones. So they function as headphones. They function as a Bluetooth headset if you want to make calls on them. They’re noise-cancelling. They’ve got pretty solid noise-cancelling, stacks up pretty well to some of the other noise-cancelling headsets out there.
And they’re really, really nicely designed. They look like a piece of art and they’ve got stuff like NFC so with the right Android phone, you can just tap it to pair it. The one side of one of the ear cups is a touch panel, a gesture touch panel. So if you want to control your phone, track forward, track back, or adjust the volume up or down, you can just slide your finger in an up-down gesture or a left-right gesture or tap and it senses the gestures, which actually turns out to work really well. And a lot of little touches like that. You can take them off of your ears and it automatically stops the music playing. So pricey, but you can tell they put a fair amount of effort into it. I’ve been pretty impressed with them. They’re a little less comfortable than I would expect for their price level, at least on the very top of my head. But part of that may just be my head shape.
And I’ll do one more. I have been really enjoying the show, The West Wing. I realize this is not anything new. But once I ran out of House of Cards to watch, I cast about for something to give me my Washington politics television fix and realized that all of The West Wing was on Netflix. So I’ve been plowing my way through all the seasons of The West Wing. It’s just a great, great show. It’s funny how even though it’s a decade old or something at this point, how relevant so many of the episodes are. Just a few weeks ago, I watched the episode about a government shutdown as a result of an impasse between the democrats and the republicans. It explained stuff that now I feel like I understand the current government shutdown better because of that episode. So cool show.
CHUCK: Nice Katrina, what are your picks?
KATRINA: I don’t have any today.
CHUCK: Josh, what are your picks?
JOSH: Okay. So Rubinius 2 has been released. That’s not actually my pick. I think it’s cool and maybe we should do a show on it one of these days. But a part of the Rubinius 2 announcement was that they are now providing the Ruby standard library. Okay, so Rubinius includes an implementation of the standard library written in Ruby itself because that’s how Rubinius works. And they’ve released all that packaged as a bunch of gems. And it’s actually pretty cool. So I think if you want to know more about how the standard library in Ruby works, this is a really good resource. As I’ve said this before, looking at the source code in Ruby is a hell of a lot easier, sorry, a heck of a lot easier than looking at it in C for most of us Rubyists. Okay, so the Ruby standard library as Ruby gems thanks to Rubinius. That’s my pick.
Then there’s this book. I don’t think this has been picked before. There’s this book called the Codex Seraphinianus that came out 30 years ago, something like that, 1980, 81. And it’s sort of an encyclopedia from a parallel universe is the best way to describe it. It’s written in a made-up language and lots of bizarre pictures of non-sensical things. But it’s like Dr. Seuss for grownups. But there’s a new version of it that has just been published. It’s going to be available any week now. And I’m excited. I never managed to get a copy of the book back in the 80’s when I first encountered it. And so I’m going to have to get a copy of this when it comes out. It’s definitely the most interesting coffee table book you can put on your coffee table. I’ll just leave it at that.
JOSH: Okay, that’s it for me this week.
CHUCK: Alright. I’ve got a couple of picks. My first one is related to James’ pick. He was talking about the guys from the Food Fight Show. I think we had Nathan on the show, if I remember right. Anyway, I’ve been playing with Chef and I’ve been watching these videos that were put together by Nathan Harvey who is one of the guys on the Food Fight Show. And their tutorial on how to get started with Chef and they’re really good. So I’ll go ahead and put a link to those in the show notes.
Another pick that I have is I have been playing with Redmine for a while. And I found a plugin for Redmine called the Redmine Backlog plugin. And it is really, really nice. I moved away from Pivotal Tracker mainly because you have to pay to have more than one person on a project. And that set things up so that I wasn’t using that all the time with my clients. Sometimes the clients had their own ticket tracking system or whatever. So I moved over to Redmine for my own stuff so that I can bring people who want to help me out on that on one of those projects. And the backlog basically allows you to setup a workflow for your tasks, tickets, features, bugs, whatever you want to call them. And then as you work through them, you can move them over to in progress or resolved or completed or rejected or whatever. Anyway, it’s really awesome. And I’ve really, really liked it. So I’m going to pick that as well. And like I said, I’ve been playing around with Redmine. If you need help with Redmine, I’m happy to help you. Obviously, that’s part of my consulting business.
And I’ve also been playing with Spree and I’ve playing with the spree_digital plugin for Spree which allows you to sell digital products on your Spree shopping cart. And it looks really cool. I haven’t quite got it implemented yet. But so far it looks exactly what I need for some of the other stuff that I’m doing. So I’m going to pick that as well.
JAMES: And just to clear it up, since two of us have mentioned it, it was Nathan Harvey on the show. Episode 113 where we talked about DevOps.
CHUCK: Awesome. Yeah, Nathan was super helpful. He actually got on and helped me fix some problems that I was having with the cookbook for Apache. So we actually submitted some pull requests for that and fixed a couple of bugs. He’s really helpful. He works for Opscode who are the people that put out Chef. So I can’t say enough good things about him. Erik, what are your picks?
ERIK: I’m really excited for my picks this week. Yeah, I’ve been listening to the show forever and I always think, “If I was on the show, what would I pick?” So now it’s my big chance to get them all out there. There’s a bunch of them.
I guess my first one, to plus one Josh’s pick of Rubinius 2.0, I would also add JRuby 1.75 as well as MRI 2.1.0 preview. So the past three weeks or so has had releases of all of these, I would say the big three Ruby implementations. And obviously the MRI release is just a preview release. But the JRuby and Rubinius releases are really exciting, I think. Both of these Ruby implementations have just in time compilers. They both have parallel generational garbage collection. And they both lack a global interpreter lock.
Miguel Camba actually ran some benchmarks against these three Ruby implementations that just got released this week and also against MRI 2.0 and 1.9.3. And obviously, like all benchmarks, they’re not necessarily representative of your workload if you have a Rails app. But I think they’re interesting and I would say for Rubinius in particular, this is the first release of Rubinius that I think it would be responsible to run in production looking at the performance. Previous versions of Rubinius have been pretty slow in my experience and this one actually looks awesome. So I would say install Rubinius. Check it out.
If you maintain any gems or libraries, you should definitely test them against Rubinius and JRuby so that people can use those gems on these alternate Ruby implementations. Because if you look at these benchmarks, these implementations are surpassing MRI in many cases. So I think a lot of people are going to start switching from MRI to JRuby and Rubinius in production, which is really exciting I think. A pretty exciting time in Ruby. And of course, there’s Topaz and other up and coming Ruby implementations as well. So this I think is great.
My second pick is the DOT language which we talked about a little bit earlier. DOT is basically a graph description language. And one of its design goals is to be both human and computer readable. So much in the way that Ruby is easy to write and easy to read, I think DOT is also this way. And you get to really easily generate these cool graphics, cool diagrams, directed graphs, non-directed graphs if you want. And the DOT command line utility can generate them in any format, pdf, postscript, png, jpeg, you name it. And I would actually say, read the grammar for the DOT language. It’s really simple. It’s only about three pages, if you print it out. And it’s really easy to understand, so you don’t have to buy a book o DOT. You can just read the grammar and understand the language and maybe look at a couple examples of it and pretty quickly figure out how it works. It’s just nodes and edges, so pretty simple.
My next pick is an app pick. It’s DuoLingo. I recently moved to Berlin, Germany and I spoke no German before moving here and installed this app on my phone. They just released a new iOS 7 style app for the iPhone and there’s also an Android app. And it’s awesome. It teaches you a language and it’s a completely free app and it’s an awesome app. How could they have such a great app that is completely free? Where do they get the money from this?
And it turns out that the frontend, the sales end of the business, is selling online language translations for this and you’re the backend. You’re translating. So it has this really strong incentive to teach you to a level where you could actually translate random snippets of text on the web and then once you get that good at German, you’re providing a translation service for them which they charge people for. So the app is free, but their goal is to get you really good at whatever language you’re learning so that they can make money from you. But they can only do that if you get to a certain level. So seems like an awesome idea.
And I didn’t think to learn a new language, a new human language. We always talk about learning new programming languages, like learn a new language every year. But I never thought to do that for human language until I moved to Germany. But really, there was nothing preventing me from learning a language before. And I’m learning so much and it’s fun to speak German and learn German. I actually wish I had done it earlier. There was no reason not to. So yeah, I would really recommend downloading DuoLingo and try to learn a new language on your phone. It’s a great thing to do when you’re sitting and waiting for the bus instead of playing Bejeweled or whatever you do on your phone that’s old school, Angry Birds, whatever people do today. Just learn a language instead. It’s way better.
My next pick is Charlie Kaufman who’s a hero of mine. He’s a writer and producer of films. You might be familiar with his films without actually knowing who he is. He did ‘Eternal Sunshine of the Spotless Mind’, he did ‘Being John Malkovich’, ‘Adaptation’, ‘Synecdoche, New York’, and a lesser known film called ‘Human Nature’. And these are actually five of my favorite films of all time. So I would really recommend, if you’ve seen one of them and liked it, I would recommend seeking out the others and watching it. They’re just really great movies. But my pick is actually not the movies. It is. Go see those.
But if you’re only going to do one of my picks, it would actually be this one which is this lecture that he gave at the BAFTA, the British Academy of Film and Television Arts. Basically, it’s the first lecture he ever gave and I’m not sure he’s given one since. It’s just the most epic, incredible lecture I think I’ve ever heard. I can’t recommend it strongly enough. I know we’ve gone long but I’m almost inclined to just read the first two paragraphs to you because they’re so awesome and it’s just very raw, very real. It covers topics like Impostor Syndrome, which I know is a common topic of discussion on this show. And he’s just very open and honest about his practice and what he does. And I think a lot of it applies to programming, but it’s also just a great, great listen.
Then I’m also going to pick Louis CK. He has a television show called Louis. It’s been through three seasons. Similar to the Charlie Kaufman pick, I think Louis is just one of the realest shows on television. It’s fiction and I guess it’s comedy as well. But it’s a really different brand of comedy than maybe you’re used to seeing on television and addresses some real issues, real life issues, in ways that so-called reality TV doesn’t even scratch the surface of. So it’s a great show. And he also just released a comedy special. It aired on HBO back in the spring and won an Emmy for the best writing and now you can download it on his website for five bucks. And it was just released today.
I actually haven’t listened to it yet. But he’s done this before and I really appreciate his entrepreneurial spirit in just routing around any sort of traditional distribution platforms and retaining his rights to his comedy, to his work, and just putting it up on the internet himself for a fair price and with minimal DRM. So I would recommend checking that out if you like Louis CK and his brand of comedy. There’s a new standup special for you to download for five bucks. Totally worth it.
And my last picks, last but not least, are actually Twitter accounts. I don’t know if it’s normal to pick Twitter accounts on this show, but there are a couple of Twitter accounts.
JOSH: I’ve done it a couple of times.
ERIK: Great. Okay, good. Then in the rich and long tradition of picking Twitter accounts on Ruby Rogues, I will select @Brilliant_Ads. This is such a cool Twitter account. They just tweet little photos of billboards and magazine ads and sometimes YouTube videos to television ads. But it’s normally just little picks that you can consume pretty quickly on Twitter. And they’re really clever. A lot of them are just funny or interesting or really well-written. And most advertising’s crap. Most everything is crap, I think. But when it’s good, it’s really good. And this Twitter account just features the best ads from all over the world.
Then my second Twitter account pick is @SeinfeldToday which is tweets, plotlines from the Seinfeld television show if they were happening in modern times. So if Kramer had access to social media, for example, is the premise. The people who write it, I know Seinfeld and watched Seinfeld and know the characters really well and to me the voice that they write in is just pitch perfect for these characters. So if you enjoyed Seinfeld and you miss it, you can watch the reruns or you could just follow @SeinfeldToday on Twitter. And those two accounts really cheer me up in my timeline.
JOSH: You’d probably like TNG Season Eight.
ERIK: Ah, yes.
JOSH: Although I think they’ve stopped tweeting.
ERIK: Oh, is that a Twitter account as well?
ERIK: I hadn’t seen that.
JOSH: Yeah, there’s a Twitter account that was pretty amusing. There’s also a Bay Area TNG [inaudible].
ERIK: Ah, right. I get it. There was only seven seasons. I get it.
JOSH: Yeah. But no, I’ve been following modern Seinfeld for a while. It’s pretty funny.
CHUCK: Awesome. Alright, well I just want to remind everybody we are gearing up for another book club book. And that will be ‘Confident Ruby’ by Avdi Grimm. We’re going to be doing it next week.
JAMES: It’s not too late to read it. It only takes a couple of hours. Even if you go through everything, the video, the other book it comes with. Lots of great stuff.
CHUCK: Yeah, there’s a lot of terrific stuff that’s there. So definitely take advantage of that. The discount code is ROGUESCLUB, all one word, all uppercase. And it’ll get you 20% off. Anyway, we want to thank Avdi for writing an awesome book and we’re looking forward to talking about it on the show. And with that, we will wrap up and we’ll catch you all next week.