There’s a joke that I’ve heard several times over the years. I don’t think I’ve ever told it for a laugh, really just as part of a larger discussion. It seems to apply here.

What do you call someone who speaks three languages?
Tri-lingual.

What do you call someone who speaks two languages?
Bi-lingual.

What do you call someone who speaks one language?
American.

Now, as an American who speaks only one language, I feel kind of offended but, I do get the bigger concept of the joke. That concept appeals to me as a developer. I’ve always found value in being familiar with multiple languages and tools; it’s always made it easier to chose the right tool for the job.

While the ideas here apply to developers in general, being part of the Ruby/Rails community I’m going to focus on that community.

Observing the Herd

I’ve always been bothered by the disdain shown for “foreign” technologies by the Rails community. The two biggest being the database and JavaScript.

The cheers I heard at the RailsConf MagLev presentation to someone shouting “screw relational databases” represent this problem well. There were many interesting aspects to MagLev but, what I heard the most about was the potential to do away with relational databases and do everything in Ruby. This is only the tip of the ice-burg as far as hating relational databases in the community.

The impetus for writing this post itself was a friend and fellow Ruby developer tweeting “wishing i could write iPhone apps in ruby.” Hearing something along those lines is all too common.

There are obviously exceptions and I applaud those exceptions but, I’m not talking about them in this post.

A Crippling Love For Ruby

The Rails JavaScript helpers have always been a sensitive topic for me. I’ve honestly never used them beyond the prototype phase in a project. I’ve always tried to go the unobtrusive route and hand-code my JavaScript. I do use jQuery though, I’m a bit insane but I’m not a masochist. Put simply, I’m a web developer and JavaScript is the language for programming in a web browser.

Another sore spot is the database. The common Rails idiom seems to be to do everything in Ruby and to avoid things that can’t be expressed in Ruby. This can lead to incredibly naive implementations that would run exponentially better in the database.

Before I hear the bellows of “premature optimization.” Knowing your tools and using them appropriately is not premature optimization. Things such as triggers and stored procedures can be incredibly powerful and should seriously considered.

Even indices seem to commonly trip up seasoned Rails developers. I’ve heard of at least a dozen instances of an application being sped up simply by properly indexing the tables. It’s just plain sad that something as simple as an index turns into a real stumbling block. This happens because the database is seen simply as a necessary evil that can be ignored until performance demands giving it a little attention.

To be continued…

I have a lot more I could cover here but, I see this post as simply the start of a much larger discussion. So, what do you think?

This was my second RailsConf and the change in the community are stunning. Last year was all about “fuck everyone else, we know the way.” As a rule, I like this attitude. The problem was that it was applied to things such as “sound engineering” and “good ideas.”

Last year there was very little interest in alternatives. Alternatives to ruby, rails and rails’ ideology were all soundly shat on by everyone I spoke to. This year things like JRuby, Rubinius, MagLev, Merb and DataMapper all had solid showings, large crowds and lots of excitement.

Things have changed

The general tone was more accepting of new ideas. The Rails Core panel showed the trademark cockiness [well-deserved in my opinion] but, expressed finally openness to real valuable changes to things like ActiveRecord.

Not much in this world could excite me more than discussion of an identity map in ActiveRecord.

I also saw real excitement over the alternative Ruby implementations. I’m sure this has something to do with their massive progress but, it really seemed people were finally ready to hear new ideas. I didn’t hear a single person expressing anything but excitement about these project.

Everyone loves the enterprise…

…not just enterprise software, although there was actual praise for the concept of the enterprise (a big change in this community) but, more traditional software engineering ideas as well.

The keynotes by Joel Spolsky and Kent Beck were great. More surprisingly, I’m in the solid majority with that opinion.

I have arrived… kinda

I did a lightning talk on a JamLab project and it was very well received. There’s actual interest and there was almost no laughing. To be honest, I was shaking while giving my stupid little five minute talk. I’ve never talked in front of a crowd that big before. I definitely have a new found respect for the people that get up and talk for an hour.

In the talk “The Worst Rails Code You’ve Ever Seen (and How Not To Write It Yourself)” by Obie Fernandez he talked about my plugin for almost a whole 3 seconds and I felt like a 90s schoolgirl at a NKOTB concert.

I also worked much harder at meeting people and talking to people. I’m not a social person so, it’s not easy but, the awesome Oregon beers and meeting great people like Steven Bristol, Grame Mathieson and Jim Weirich made things a bit easier on me.

That reminds me

Jim Weirich, Joe O’Brien and Chris Nelson gave, what is in my opinion, the best “better your craft” talk I’ve ever seen. It was called “Dialogue Concerning the Two Chief Modeling Systems.” Words don’t do it justice, especially not mine. There’s a decent summary here but, it’s not just the content that made this talk a thing of legends.

More to come

I just wanted to get some of my initial thoughts posted. I have some more specific technical issues I want to mull over before posting about. I can’t say my level of excitement after RailsConf this year matches last year but, my hope for and interest in the community as a whole has grown tremendously. I need to try a pull my weight by contributing more.

Epiphanies and Weird Ideas

April 30th, 2008

A lot has changed since I started this blog so I think I need to give this a renewed effort. I’m going to try and temper my obsession with getting everything perfect. My previous approach to blogging has resulted in 4 published posts in 9 months and about 40 drafts. What a fucking waste.

So from now on the content will be significantly shittier than it was and far more frequent, like a stomach flu. Here’s to fresh starts.

An unoriginal weird idea

I needed to do something weird in a plugin I wrote. I needed two models to represent the same table. I needed models that act like views. I’ve seen plugins that try to accomplish that goal but they have one of two problems:

  • Muck around with ActiveRecord internal data structures
  • Are pretty much all or nothing (no way of getting at the whole table through a scoped model)

The second issue I could have hacked around.

The first is a show stopper for me. Ruby gives you a ton of power to monkey-patch but, I think those changes should be kept as close to the public API as possible and never ever directly manipulate internal (to what you’re patching) data structures.

One day this may be promoted to “bad idea”

So I wrote my own. I’m not even convinced this is of general interest. So much so that it’s actually part of a larger plugin I wrote, just an implementation detail of that plugin really. That said, if there is a positive response, I’ll wrap it up and spec it out properly. For now, I’m going to go the worst possible route for software distribution, uploading it as an asset for my blog. Classy, huh?

scoped_model.rb

Just a simple ActiveRecord::Base.send(:include, JamLab::ActsAsScopedModel) and you’re off and running.

Usage is exactly like #with_scope

class DumbUsers < ActiveRecord::Base
  acts_as_scoped_model :find => {:conditions => {:is_dumb => true}}
end

Now use the model as usual and the proper scope is used everywhere. It makes absolutely zero attempt to control the creation of records in any way. You can create a record using a scoped model that does contradict the assigned scope.

An important note, I’m not using this in production yet so, this may be riddled with bugs. If you do find any, drop me a line.

I think he forgot the "humor" tag

September 21st, 2007

Some guy blogged about JRuby and CPython performance. For the most part he’s gloating that his stunning prediction that jruby would be slower than cpython has come to pass.

Get this man a Nobel…

Is there a single person in the Ruby, Python or Java communities that is surprised by this? At a minimum I’d argue that comparing Jython would be more appropriate but quite honestly, who cares? No one is using Ruby, or Python for that matter, for their blazing speed. It’s well known that both languages have speed issues and Ruby is definitely the slower of the two.

Hand tuned assembler may be faster than Jython

If you want speed, don’t use Ruby or Python. People aren’t turning to these languages for their performance characteristics. They’re using them for the sheer joy of working in these environments. I like both Python and Ruby, they have their strengths and weaknesses. In Ruby I find myself wishing for Twisted all the time. In Python it’s Ruby on Rails, I’m sorry Django, you’re beautiful but it’s really a personal style call at this point.

I can has pots and kettles?

Seriously, this is like a bunch of tortoises arguing who’s fastest. You’re all fucking slow compared to your competitors. Get over it and pick your fights more carefully. Focus on your strengths. The Ruby and Python communities have a lot in common and should focus on common ground instead of arguing who sucks at performance least.

Vlad: My new secret love

September 17th, 2007

updated The approach to staging deployments with Vlad in this post is ridiculously dumb and complicated compared to this one.

Recently I've been reading about Vlad the Deployer. Like many in the Ruby community I was a bit put off by how they've chosen to promote Vlad. Anyone who knows me, knows there's nothing I like more than a bit of well placed arrogance and trash-talking but, I figured Capistrano was fine so why all the big talk against Cap?

Then I looked inside the beast...

At this point I don't even remember why but, I looked through the Capistrano source. Now, I feel pretty confident in my knowledge of Ruby and software architecture in general but, the Capistrano source gave me a migraine. Don't get me wrong, it's very well written code, it's just architected in a way that only the original author could really feel comfortable with it (yes, I'm putting this far nicer than I usually would because I have tremendous respect for Jamis Buck, Capistrano's author).

I can honestly follow the Rails routing code easier than I can Capistrano but that's another topic for another post.

Rule #n+1: Use the tools you have

Vlad makes great use of Rake. By using one of the best Ruby libraries out there, they got a lot for free. For example, instead of special casing the before_* and after_* tasks, they used Rake's dependencies and it's ability to extend a defined task.

They also use the ssh command instead of Net::SSH. Net::SSH is a really interesting piece of code, especially as one of the few examples of dependency injection (via Needle) in Ruby. However, there have been issues with using Net::SSH in Capistrano. I'm not going to question the value of having a native SSH implementation but, I'm not entirely sure why Capistrano should use it when it can accomplish it's goals by shelling out to the ssh cli.

A minor contribution - Deployment Targets (ex. Staging Environments)

Nothing speaks louder than a contribution and I have a small but valuable one. While talking with Chris Saylor we came to the conclusion that implementing support for staging environments in Vlad wouldn't be all that difficult. With a little bit of research, on Rake not Vlad, I came up with this.

This should go in RAILS_ROOT/Rakefile

    namespace "vlad" do
      desc "Setup the deploy target overrides"
      task :target

      rule "" do |task|
        if task.to_s.match(/vlad:target:([a-z_-]+)/i)
          override_path = File.join(RAILS_ROOT, 'config', "deploy.#{$1}.rb")
          Kernel.load override_path if File.exists? override_path
        end
      end
    end

Thank you Geoffrey Grosenbach for the Rake version of method_missing.

With this code in place you setup your deploy.rb with your production config, as usual. You can also setup as many deploy.*.rb files as you like. Off the top of my head, deploy.staging.rb and deploy.qa.rb may be useful. These files contain the settings that differ from your config.rb. You would then use Rake's ability to chain commands.

config/deploy.rb

set :application, "example"
set :domain,      "example.com"
set :deploy_to,   "/var/www/apps/#{application}"
set :repository,  "svn+ssh://svn.example.com/var/svn/#{application}/trunk"

config/deploy.staging.rb

set :domain,      "staging.example.com"

Deploying to your staging environment from scratch:

rake vlad:target:staging vlad:setup vlad:update vlad:migrate vlad:start

Simple, easy to understand how it works and it's all standard Rake, no real Vlad magic involved.

Way out of scope

August 16th, 2007

I wasn’t planning on posting on this blog about anything but technology but this is too good. My current favorite band, Gogol Bordello, had their lead singer, Eugene Hutz, interviewed on NPR.

It was a pretty interesting interview. It included quite a bit about his childhood in the USSR and some good music mixed in. Take a look.

Let me just say in advance, I realize this won’t work for everyone. However, it will work for an awful lot of people that mistakenly think they currently can’t use Rails’ page cache. Also, in some examples I’m simplifying for the common case.

If you don’t want to read all my pointless rambling, feel free to jump down to the solution.

What is this “page cache” you speak of?

Put simply, Rails will generate your page once and then write it out to disk where your web server can serve it up from then on, requests never even hit Rails. You can argue all you want about Rails’ speed but, a web server serving a static page will always be several orders of magnitude faster.

Neither the fragment or action caches receive this benefit, it is exclusive to the page cache.

But, but, but…

…I don’t know about your application but, my pages are too dynamic to use the page cache.

I hear this way too often from people that should know better. Most pages in most Rails applications I’ve seen could make use of the page cache. The first question is, should they?

Sometimes it’s not worth the added effort for a page with dynamic elements. A good example of this would be a site admin tool with users counted on one hand. In this case some heavy weight reporting pages may benefit but other pages may just be wasted effort.

That leaves us with public facing sites, you know, where we make all our money and what truly matters. Now, I know premature optimization is the root of all evil but, we’re all well acquainted with the Twitter mythology now aren’t we?

We all hope our sites will get huge and while I don’t think Rails is unusably slow, I do think we shouldn’t ignore the tools Rails gives us. It’s tough to argue when you see a non-cached page happening at ~30 pages per second and the same cached page at over 800 per second.

We know the enemy and he is Bob

So you want every page to say “Hello Bob!” (assuming your user’s name is Bob)? Damn, we can’t use the page cache unless of course only Bobs may sign up for the site.

Now, we could use the fragment cache for big portions of the of the page but that’s not nearly as big a win as the page cache. Using the fragment cache still goes through the Rails request handler, it’s filters, session retrieval, the action, any ActiveRecord queries and the page rendering. You only save in portions of the page rendering.

Going counter-culture

So what’s the solution here? Ajax. Yes, I’ve read all those articles about how so much ajax on “Web 2.0” sites is putting additional, unnecessary strain on their infrastructure. The conclusion in most of these articles is “use ajax sparingly.” I don’t disagree, it’s good advice. There are cases though where the wins are much bigger than what you’re losing, this is of course one of them.

The solution

The specifics of the solution will differ based on the demands of your page but, the basic idea is common.

  • Create a new action for serving up the dynamic content.

Depending on your needs this could be a standard action with it’s corresponding ERB or it could be an action using RJS (to update multiple parts of the page). This action should do it’s work based on information retrieved from the session not URL parameters.

  • Use javascript (jQuery, Prototype or Rails’ helpers) to make a request to that action from the page to be cached.

Here’s an example (using jQuery) from a site I built:

<script type="text/javascript" charset="utf-8">
    $(document).ready(function() {
        $("#tinymenu2").load("<%= url_for :controller => 'member', :action => 'controls' %>");
    });
</script>
  • Enable page caching and revel in Ludicrous Speed.

What does this really give me?

Quite a bit. Like actually using Rails. A lot of Rails optimization articles I’ve read contained such gems as:

Avoid the use of dynamic URL generation (link_to, url_for) since rails needs to look up the routes table and that may take time. Just hard code the controller name and the action.

and

Try to avoid the excess use of helpers since it adds overhead.

In my opinion, if you’re doing either of those two things, you might as well switch back to PHP (or ASP or Java). Rails is about convenience and all these helpers help you as a developer. The various helpers in Rails keep things DRY and insulate your application from future changes.

The key is to be familiar with and use every tool Rails provides you with. With page caching combined with ajax you can use helpers as much as your heart desires and still have a very responsive app.

Conclusion

In the common case this approach will result in a massive speed increase. Also, since most javascript libraries can trigger when the DOM is ready (before images have loaded) and the result of the ajax request is likely quite small, the visual impact will be negligible (on my site the user specific ajax elements appear long before the page has finished loading).

So, what’s everyone think? I’ve also been trying to think of ways to pluginize this technique but it seems very application specific. If anyone has any ideas on that front, drop me a line.

Also, if there’s any interest, I’ll put together a simple application demonstrating the approach.

First Impressions

July 5th, 2007

In theory this would be an amazing first post. It would catch your attention and make the whole technology world hang on every word I ever post, however few words that may be. In reality this is just going to be the typical introduction.

Hi, my name is Rich Cavanaugh and I’m a Ruby developer

I’ve been meaning to start a blog for a couple years. When I was at the top of my game in PHP I wanted to blog. When I took on Python with real fervor, I wanted to blog. I’ve been talking about it since I took on Ruby and subsequently Rails. Basically I’ve been annoying the shit out of everyone around me. Without this outlet I’ve been ranting and raving to my wife about what precisely I dislike about ActiveRecord. For someone not so technical she’s become quite knowledgeable about ORMs or at least my opinions on them.

A week with my own kind

I work from home. I’ve worked from home for the better part of five years. These jobs have always been pretty much just me doing all the technology. In May two things happened. First my company hired a second developer and second I went to RailsConf 2007. This caused a bit of a revelation, I like people more than I thought. Especially very smart people and there doesn’t seem to be any shortage in the Ruby community and they’re all blogging.

Inflicting my opinion on the community

So this is the whole point. Whenever something occurs to me that I’d like to share, instead of giving a crash course on blocks and bindings to my wife, I’ll post here. I want to finally join the discussion at large and I hope I can contribute something to that discussion.