00:00:07.839
Hey, my name is James Britt. I'm going to talk a bit about what I call black boxing with Ruby.
00:00:14.799
A little bit of background about myself: I run some Ruby sites, probably most notably Rubydashdoc.org, and I've been writing Ruby code since about 2000 or 2001. I've also written a number of Ruby articles and parts of books.
00:00:28.400
The basic idea of what I want to discuss is sort of an overview, recounting some experiences I’ve had while trying to work with applications, primarily web applications, that aren’t written in Ruby.
00:00:34.640
These applications don’t necessarily expose the kind of API or interface that I want. Yet I want a decent Ruby API from my client code, say, for command line tools or some other applications.
00:00:42.480
So the definition here of black boxing is just interacting with some other app that doesn’t have my particular interests in mind. For my purposes, a black box is just an unknown entity that you may only know how it works from its outside behavior.
00:00:54.480
You might not have any access to its internals or any opportunity to really hook into it. I think, for our purposes, this is a good enough definition.
00:01:13.119
The story behind this is that I needed some sort of project tracking tool. In another case, I wanted some kind of commenting system for a particular application. In general, I liked a whole bunch of stuff that just wasn’t written in Ruby.
00:01:25.600
There’s a lot of nice stuff out there. There’s Track, a project tracking tool that some people have mentioned and I know a lot of people use WordPress for various things, which is actually quite good if you’re doing blogging or certain kinds of presentation work.
00:01:43.759
I like Amazon’s EC2 Elastic Compute Cloud for various things. There are some Ruby applications for it, but they aren’t quite as complete as I’d like. One of the sites I run, Rubystuff.com, is a portal aggregator for a bunch of Cafe Press shops.
00:01:56.320
All these cases are things I want to work with using tools that were written from moving my end to things that weren’t necessarily Ruby-friendly on the other end.
00:02:07.120
One question that comes up when you talk to people about this is: Why not just build everything myself? Right? If I can’t find a project tracking tool that has just the right API I want, why not just build it?
00:02:28.959
The reason is, well, because that’s just insane! I know that many people, when they work on projects, half the fun is building the tools to help you build your main project.
00:02:48.080
But it’s a serious milestone you can just chase forever, spending more time building tools than actually building your project, and I’ve been there and done that. So I don’t really want to chase that all the time.
00:03:06.000
Why not use a Ruby app? Well, the truth is, there’s not always a good selection available. People do talk about writing a Ruby substitute for Track. There are Ruby options that aspire to what WordPress offers.
00:03:21.200
But I’m not sure if they’re quite there. Even if they are, there’s another aspect to this which is just plain mind share.
00:03:33.920
Even if you find an application written in the language of your choice, when a bug is found, when there’s a security problem, or when there’s a feature request, how many people are going to be out there to fix it or to contribute?
00:03:46.000
I’m pretty confident that if I’m using Track and there’s a problem, all those developers are going to jump on it. The best part is I’m not going to be one of those developers having to fix it, which leaves me free to focus on the things I want to do.
00:03:58.000
So what it really comes down to is that when you need a particular tool, it’s secondary to what you’re mainly trying to accomplish or just has some particularly useful feature.
00:04:14.400
Yes, it’s nice when you can do everything in pure Ruby, but the reality is that isn’t always what’s going to work best for you. You needn’t be blinded by this kind of language fundamentalism.
00:04:21.199
Basically, the P languages are not the work of Satan, but don’t let that get out of this room, okay? I’ll deny it.
00:04:33.919
Another big motivation for me personally is the curiosity of wondering if you can take this and hook it up with that, and experiment with various combinations. Anyone who had a chemistry kit growing up knows what happens when you mix the blue stuff with the red stuff.
00:04:50.240
A lot of that thinking applies to mechanical devices too. Oddly enough, I grew up being known as the one who always broke stuff, even though I was also the one who always fixed stuff.
00:05:04.960
I view a lot of what I do as an opportunity to experiment with certain ideas.
00:05:10.880
When you do things like that, you end up in odd development territory and wind up learning or doing things you wouldn’t have considered if you were to take perhaps the 'right' path or the obvious route.
00:05:31.199
So keep that in mind as you go through this.
00:05:36.720
I think for most speakers when they give a presentation, this is what they want from the audience. Right? This is what maybe it’s all about.
00:05:42.720
That’s fine, but this, however, is the path to enlightenment, so I’m good with that.
00:05:53.440
Let’s start off with Track. Track is an excellent project tracking tool. You can argue with me afterwards if you want, but I’m quite happy with it.
00:06:05.120
It does basically what I want, gets out of the way, has nice features, lets me look at my SVN repo, has a wiki, accepts commissions—it works.
00:06:15.360
But there’s way too much mousing required for many things. If you’ve ever tried to add a ticket to Track, you know you have to open a browser, click on stuff, and go through all of that.
00:06:26.880
It’s fine for one-off things, but it is particularly useful if you open up your Track repo to clients and give them an opportunity to submit things.
00:06:38.960
However, it wasn’t really what I wanted to do, and just in general, web pages are poor data entry tools.
00:06:55.120
So I asked myself: Hey, I wonder if I could use Track from the command line? The situation really was this: I find myself working on projects, coding away, and when I come across something that I see as a problem.
00:07:12.240
I don’t want to fix it right away, but it’s also not the main problem I’m facing right now. Perhaps I notice that the CSS alignment on a certain page is just wrong. I want to make a note of it.
00:07:27.680
I don’t want to write it in a temporary notes file and then later on remember to post it on Track. What I wanted, while at the command line, was to type it out and have it magically appear on Track.
00:07:43.840
So that was a practical thing I needed to do, so I wouldn’t break the flow of my work. And now the answer is: Yes, you can use Track from the command line.
00:08:01.599
This is an application/library I’ve written to interact with Track, primarily from the command line and through Rake tasks.
00:08:14.720
Let me say that I actually get this to work. I tried to do some screen capturing, as I don’t like live demos. The medium of live demos has a really bad history.
00:08:30.640
So I’ll see if I can get this to perform well enough. To give you an idea of what it’s like, you can type a Rake task, track: tickets.
00:08:45.000
It goes up to the server and pulls back a list of all the open tickets. That was something I just wanted to have available at any time while working on something.
00:09:02.960
Now, likewise, I want to be able to add tickets from the command line through a series of prompts.
00:09:14.720
Here’s another high-tech audiovisual presentation: similar to a Rake task, you can type track: ticket.
00:09:29.440
It prompts you for a bunch of information, and there are some reasonable defaults I’ve put in there.
00:09:44.880
This may look practically unreadable, but trust me—there’s a gracious prompt asking you what milestone it belongs to and what the component type is: is it a task or a defect?
00:09:59.000
It will then post it back up there, and that’s exactly what it does.
00:10:10.880
Personally, I found that much nicer than having to open a web browser every time I have a ticket.
00:10:27.520
Even if you leave the browser open, it just wasn’t what I wanted to do.
00:10:39.840
Some of the capabilities show how it works. It’s not rocket science—it’s just HTTP mechanized, going up there and pretending to be a web browser.
00:10:57.599
It goes up there and simulates a request. There’s a config file involved that loads your username, password, and the URL for the Track repo, along with a couple of other things to make it easy.
00:11:14.560
This setup worked well for me because I’ve gotten to interact with an application ostensibly written in Python.
00:11:31.680
I’d be lying if I said I didn’t have to actually look at the Python; I did.
00:11:45.760
So there’s the URL if you want to poke around. I realize that URL isn’t going to tell you how to get the code or the gem, but I will have to update that.
00:11:59.360
It’s kind of raw and in a beta/alpha state, so you can let me know if and when you find problems with the code.
00:12:15.920
This is great—it solved my problem. However, there were some glitches with it. One thing I noticed is that every time the Python developers updated Track, it was different.
00:12:31.920
It was like it was new, and new enough in different ways that it would break things. When I first started with Track, the form field for submitting a ticket was quite straightforward.
00:12:45.839
I had to change servers, re-install Track, and when I went back to use it, it just wouldn’t work.
00:12:58.120
It turns out there’s now a hidden form field that performs verification against a cookie, which has a grid for your specific process.
00:13:14.960
Fixing that was not phenomenally difficult, but it was just an annoyance.
00:13:29.680
As I spent more time with Track, I became more aware of plugins. I figured out the Python egg installation process and how to get things done right.
00:13:44.720
There’s quite a lot of nice stuff available. For example, most of my Track sites are on a URL with HTTP basic authentication, using .htaccess files to restrict access.
00:13:59.160
But for the Track site, I wanted a general open page and a nicer login. Track has a plugin that handles that, but the irony is that Track Dracula doesn’t actually work against the Track site.
00:14:20.040
This is largely because of a different means of authentication. So, there’s a certain amount of brittleness introduced when you try to do this sort of thing with a web page.
00:14:35.680
I guarantee that the people maintaining the page aren’t thinking of what they’re presenting as an API. For them, it’s just whatever it is that people click on.
00:14:55.040
Some lessons learned: First, HTTP mechanized truly kicks ass. If you haven’t spent any time with it, you really should.
00:15:10.920
If you’re manipulating HTML that comes down from pages, they do a really good job of fixing randomly sloppy HTML.
00:15:25.040
You can reach in and grab images, forms, tables—whatever information you need.
00:15:39.600
Second, if it’s on the web, it has an API. Granted, yes, it’s fragile, but at least consider that as you look at things.
00:15:56.240
Anything that’s out there that you can access through a browser, particularly with tools like HTTP Cad and mechanized, should lead you to think of how to automate the interaction with this website.
00:16:09.840
When you fetch a page, you’re just getting text back. It’s text that follows some well understood rules. You can grab it, manipulate it, and post it back.
00:16:25.200
The tools available now in Ruby for this have gotten really good. But yes, there’s fragility to deal with, as someone could decide to shift around where the tables are or change what a form field is called.
00:16:42.000
Everything can kind of fall apart, but the upside is it is very easy to get started. It didn’t take me that long to get a basic version of Dracula up and running.
00:16:55.680
Most of what I ended up doing afterward was just trying to clean it up so I could open it up and let others use it.
00:17:09.520
To echo what Gregory was talking about earlier, there’s real motivation in doing that. While I wrote this for myself, I would like to see it do more.
00:17:23.200
I don’t want to be the only person working on it. It would be useful to others. To the extent that I can make an effort to get others interested and give back, it becomes more valuable.
00:17:37.120
Even those who are working on projects—a lot of times when you start out to build something just to scratch your own itch, it’s about self-interest.
00:17:51.440
There’s a way to look at this to make it worth your while to get some docs up, have a nice page, and make it easy for people to get started.
00:18:04.720
So yes, there are still some features missing—that’s okay. I’ll add them when I need them. Basically, what it does for me now is I can get a list of tickets, post a single ticket back from the command line.
00:18:18.000
Another very useful thing is I can create a YAML file that describes a whole slew of tickets and post them in bulk.
00:18:35.440
This was valuable because there is a plugin for Track that lets you attach time estimates and figure out velocity for your projects.
00:18:50.560
I found it very useful when going through a spec, as I had a contract to run down a list of requirements and start putting times against them.
00:19:06.720
I would then post the whole thing up into Track, let it figure out my estimates, and work off of that. It seemed like a reasonable way to store information without having to type it repeatedly.
00:19:24.640
However, the idea of entering all these tickets manually was just too much work for a lazy person like me.
00:19:39.680
I’d rather invest that time and energy into writing code. Now, yes, I could sit down and make a big bug list of what’s wrong with my project, type it into a simple structured YAML file, and have it all uploaded.
00:19:55.680
What Dracula does is it loops over the YAML file, creating single postings as it goes without me having to worry about it.
00:20:09.760
Another problem here is that I haven’t found an easy way to request a list of current milestones from Track. So I cheat: I go on the web page, handcopy it, and post it into my config file.
00:20:24.000
This way, when Track runs, it knows what to display. It’s handy because I found that automatic posting would fail if I did not provide a proper milestone for any ticket I was submitting.
00:20:39.840
The code now ensures that I provide a milestone that makes sense or it doesn’t bother trying to post at all.
00:20:54.240
One nice thing at the end of doing all this is that by using such a tool and avoiding trying to go against Track directly from any particular piece of code.
00:21:06.960
When the time comes that Track changes or adds new features, I simply have to change one library. I only need to update that in my client code.
00:21:21.680
All my different projects that use these Rake tasks will hopefully remain oblivious to any changes.
00:21:34.479
This helps buffer a lot of the changes that would occur. You can at least isolate the fragility of working against someone's web page as an API.
00:21:49.440
Ultimately, Track is going to have a plain XML RPC interface as a standard part, if it isn’t in there already. When that time comes, it will make things simpler.
00:22:06.720
But at least I don’t have to wait for that point.
00:22:20.720
The next application I wanted to work with was WordPress.
00:22:34.239
Years back, I started working on a book titled 'Beginning Ruby'. It was just a bad time to be working on books.
00:22:47.920
I finally decided to put this on the web and wanted to allow people reading the book to leave comments on the content.
00:23:01.919
So I decided to roll my own commenting system, starting out with a Nitro application for publishing that uses a form of enhanced Textile and hooks into its own commenting system.
00:23:17.440
I had gotten to a point where it was pretty much done when I came across the Django Book.
00:23:34.080
Now you might think I’m talking about doing it in Django, but no! The Django Book has an amazing commenting system.
00:23:50.720
If you go to djangobook.com, they have this online book, and while it’s in development, you can leave comments with a super sweet AJAX interface.
00:24:04.800
When I saw this, I thought it was a million times better than what I was doing, so I decided to steal it.
00:24:18.480
I contacted the author of the Django Book, said, 'Dear author of the Django Book, I’m going to steal your code. Are you good with that?'
00:24:36.680
He replied positively, but I should note that Jack Slocum had written extensions to the Yahoo UI library, which powers much of this stuff.
00:24:55.760
So I dropped by his site and gave him a donation.
00:25:14.000
I grabbed the code and started working on it. This is what the Django Book looks like; if you click on any of these things, you get a nice little comment box that stores the comments for that chapter.
00:25:31.320
However, it wasn’t quite what I aimed for.
00:25:46.560
In the Django Book, they have the entire chapter ready and available while it collects comments, attaching comments based on position.
00:26:00.560
If you move a paragraph or insert text, all of that information might get lost.
00:26:16.080
My approach, rather, was to give HTML elements a unique ID derived from the content, which is unique enough.
00:26:33.600
The comments will match these IDs, rather than relying on element locations, which could be too fragile.
00:26:47.680
One reason I chose WordPress is that I think it’s among the best for this purpose.
00:27:04.560
I’ve seen other people talk about using it, as it provides a site not meant just for comments.
00:27:20.960
You can easily route users to a WordPress site, which has nice admin tools, plugin support for spam handling, and comment management.
00:27:35.920
Why build all of that yourself?
00:27:50.079
The process I came up with was to fetch or create the source HTML. I ran it through an element processor that examines the page text and rewrites it by adding unique IDs and class attributes.
00:28:05.680
It writes out a new page, and in theory, you could take any plain HTML page that can go through HTTP and turn it into a system layered with commenting.
00:28:20.800
When you visit beginningruby.com and poke around, you’ll see it operates somewhat similarly to the Django Book site, with changed colors.
00:28:36.240
Clicking on the comment box lets you see comments attached to that specific chunk of text identified by a hash key.
00:28:52.320
A bit more about this process with WordPress: the client code runs locally or on the server and modifies element nodes by sending requests to an application I simply called Comet.
00:29:11.200
The Comet engine sends requests to an instance of WordPress, creating new posts with the title of that ID.
00:29:27.360
Now, the comments attached to content on the Beginning Ruby site are actually comments attached to posts on this hidden WordPress instance, with each post related to a specific chunk of text.
00:29:42.160
When a user wants to add a comment, the static page comes off Apache as plain HTML, and the JavaScript that comes down behaves similarly.
00:30:00.480
When you make a request back, it gets routed through mod_proxy to this comment server.
00:30:17.920
You now see two types of signaling going on: just plain HTML delivery and the comment behavior overlay.
00:30:31.280
My professional graphics should clarify this if my explanation wasn’t clear.
00:30:44.880
Any questions?
00:30:58.720
Yes, regarding the commenting system.
00:31:14.880
The system does exactly what I wanted it to do.
00:31:30.160
My thought is, if I change the text, the comments that applied to it might no longer apply.
00:31:44.400
When it fetches again, these could become obsolete. However, it’s a problem I’ll worry about when it arises.
00:32:00.000
Any other questions?
00:32:05.760
Thank you very much.