Massiv ups for Phusion Passenger

Posted by max on June 03, 2009

I hadn’t worked with a Rails application server since back when Mongrel was the cool thing. Boy, is Phusion Passenger (mod_rails) a wonderful surprise! It is exceedingly rare to see software have such clearly presented installation and support documentation. The installer executable is non-confusingly verbose, telling you what it’s checking for and precisely what to do to fix what’s broken. Bravo, Hongli Lai and Ninh Bui.

Their site design is nifty-looking, too.

No Ranting, No Railing, Just Grading

Posted by amy on January 15, 2008

A few of our students, people new to ruby and rails, are pretty turned off by the ranting and railing in the rails community that’s been on super-duper heavy display lately, what with the Zed thing and the Dreamhost thing and all. (No links, google Zed Shaw and Dreamhost Rails for your ownselves.)

These students want to know: what’s up with the rails community being so childish, ranty, obscene, profane, and macho? If rails wants to be treated like a grownup framework for grownups, shouldn’t rails act like a grownup? How are we supposed to take rails seriously when the guy in charge of rails thinks people who are offended by swearing are not worth his time? And why should we want to join a community that appears so unwelcoming?

To which I say the following:

First, my job is not to defend rails and all the people associated with it (Right, say students, your job is actually to finish grading our assignments. Could you finish?!? I’m working on it, I swear). If Rails is a ponzi scheme I have not been let in on it; I get no kickbacks from duping students into learning it. I am enthusiastic but not passionate about rails ( I believe, as I’ve said before, that my only true passion may be cheese), and I hope I’ve managed to share some of my enthusiasm with our students, without appearing cultish.

Second, I could point out that the Ruby and Rails communities are not isomorphic. There is a lot going on in Ruby that is not rails. But it’s also true that many people come to Ruby through Rails, so if the rails community is unwelcoming, then fewer people may make it over the hump to discover the Ruby in which Rails is built. That’s too bad, because they’d be missing out on something truly lovely. Still, there are other truly lovely languages out there too. “Let a hundred flowers bloom, let a hundred schools of thoughts contend,” except without all the reeducation camps.

Third, it’s possible that Rails will hit a wall due to personality problems. It’s also possible that, being young, Rails will grow out of its personality problems. If you don’t like the personality of the rails community right now, just wait, it’ll probably change. Or jump right in there with your own personality problems, mix it up a little.

Whatever happens, though, I think that Rails has a few good tricks that the rest of the web development community has and will continue to learn from. I think that Rails, like all frameworks, will someday go out of fashion, and then, out of date, and then, eventually, fade into obscurity. And I think more good and interesting and beautiful things will come out of Ruby.

In any case, as I wrote to one of the students who was a bit depressed by the recent rails flame wars:

For me, I know that if it had not been for rails getting popular, I would not have gotten into Ruby, and if I had not gotten into Ruby, it might have been much, much longer before I’d realized that life could get a whole lot better than:


Iterator iter = collection_thingy.getIterator();
while (iter.hasNext()) {
Thingy thingy = (Thingy) iter.next();
}

No one can take each away from me.

Fearless Play. Or, What We Did in 2007

Posted by amy on January 01, 2008

This morning I just rediscovered a year-old post on James Gray’s (of Textmate: Power Editing for the Mac fame) blog, in which he answers the question “How do you get so much done?”

I can’t tell you how often I see people say things like, “I’m not really qualified to do that,” or similar excuses. Oh hell, neither am I, but I wouldn’t let a little thing like that stop me! You learn as you go, you drag in the help you need, or whatever. Passion will conquer so care enough to have some. Be the driving force and the rest will take care of itself.

He fingers both fearlessness and passion as important to getting things done.
Me, I don’t much care for passion. I distrust passion. Except, as I pointed out in August, as regards cheese:

I still think passion is overrated, though. Except where cheese is concerned. I am passionate about cheese. For example, this Vermont Brie is really fantastic. If only someone would make a truly artisan domestic parm…! But I digress…

I like interest, friendship, love, playfulness, curiosity, satisfaction, absorption, and joy. Maybe that’s because passion implies a kind of singlemindedness that I’ve finally accepted that I just don’t have, and don’t want. Maybe it’s because I find that I cannot be passionate and fearless at the same time: passion makes me cautious. My best work, my best ideas, and my best productivity come when I am playing with something that is not excruciatingly important to me. It’s a spirit of fearless play, not passion, that drives what I do.

Not, note, that I am claiming to actually accomplish an awful lot. I’m just pointing out that, to the extent that I accomplish anything, it’s because I don’t take it too seriously. The second I start taking something seriously, I completely freeze up.

For example, this time last year, I’d just had a baby. I hadn’t worked for pay in about three years, and I had no plans for that to change anytime soon. Then Max had a contract end and decided he wanted to learn Ruby on Rails (this was back when he thought he really wanted to be an app developer, before he realized that his sweet spot is all the technical stuff that has to do with app development that isn’t actually about writing application code.) Anyway, so he was having a hard time motivating himself to do the AWDR tutorial. Fine, I said, I’ll do it too, maybe we can motivate each other.

Then I convinced him that we should try to start consulting together, and we started the blog. Hey, I thought, no one is reading this thing, I can write whatever I want. For example, here’s a quote from my very first blog post, in March:

Someday soon we’ll be able to say “yep, we know Ruby on Rails” and we’ll have our fantastic contributions to the open source world to prove it. “Right,” you’ll say, after reading this blog. “We’re looking for someone with five years experience with Ruby on Rails. You have three months.” And we’ll say “That’s the way it goes, suckas. You want to hire people who don’t actually exist. We, on the other hand, exist.” About Ruby. We’d originally decided that Max would pick up Ruby on Rails, and I would freshen up my Java skills with STRUTS, which was just coming out last time I did serious Java coding and which I am, by all rights, long past due for learning. This felt very serious and sensible. Also not fun.

And then, later that day, the key to it all:

How are we able to be so marvelously decisive? We just pretend that everything we’re doing is fake, and therefore of no consequence.

If we’d been really passionate about the whole thing, and utterly convinced that this was our calling in life, that our business absolutely had to succeed, that everything had to be done right, we would never have gotten anywhere. But we started out not caring. We did not know ruby on rails. We did not know any ruby on rails developers. We had no idea where we would find clients. I hadn’t done any programming whatsoever for nigh on three years, having devoted my time instead to recovering from the nervous breakdown I had when I was pregnant with Ari, learning to garden, grinding my own wheat for baking bread, writing a political blog, rediscovering my love of painting, visiting and eventually applying for and receiving visas for permanent New Zealand residency and, finally, being bedridden and anemic and puking during most of my second pregnancy. So hey, why not try something new? Who knows if we’ll like it? Who knows if we’ll be any good at it? Who knows if it’ll work out? Who cares?

Here’s me a month after we started the blog, in April:

I don’t know where this all is going, exactly. I’m not ready to work full-time right now. I’d rather Max not work full-time either. I want us to find a way to work together, and not all the time. I want everything — the perfect setup! I am not sure how we’ll get to our dream work from where we are right now. Will we find a job to share, or will we be laughed out of any company we tried to convince to hire us for one? Will we do some consulting, or will it turn out that we can’t stand all the self-promotion required to consult? Will blog.thirdbit.net end up going to that great bloggie graveyard in the sky? Will I work for pay again, or spend my days sitting in the park snickering at the bugaboo strollers? Is the final cylon really who we think it is, or was this year’s season finale a red herring?

In May, we got our first clients. In July, I saw a post on the Boston Ruby Group that someone needed a TA for a Ruby on Rails class at Harvard Extension. Hey, I thought, I’ve been a TA at extension before, maybe I could do that. I went to the interview and was like “yeah, I’ve been using RoR since, uh, March.” And John, bless his heart, was like “oh that’s cool, whatever.” He wanted a TA who already knew how very much work it was to grade all those programming projects, and how very little money Harvard thought all that work was worth.

In August I wrote a blog entry about method_missing which somehow got Reddited and then mentioned on Ruby Inside, which resulted in a huge spike in blog traffic.

And I ended up TA’ing this class. And it’s been absolutely a blast, and John hired Max to do some systems consulting work (migrating his company over to a new bug database).

And after John introduced me to Steve Yegge’s blog I started feeling I was just a completely crap developer who knew nothing about anything, and that gave me an idea for a book one night when I was up with Aya who was teething, and wrote up a proposal the next morning, and sent out the proposal, and got a book contract. So now I am writing a book, about which more soon.

And since I was TA’ing the RoR class I made sure to show up to the Boston Ruby Group meetings and eventually everyone got used to me being there and started to know who I was, and I started corresponding a bit with Greg Brown over email so when he came up to speak at the December Ruby Group meetingI was like, what the hell, and invited him to dinner, which was a lot of fun.

And Max and I each got more clients doing exactly the kind of thing we each like most to do right now. ( Obligatory self-promotion: Look here for more info if you might want to hire one or both of us!)

Anyway, it has worked out for us. Not exactly the way we imagined it might, but nothing ever does. And since we weren’t all that invested in what we’d imagined in the first place, it didn’t bother us that much to change it.

I don’t know what will happen next. But I do know that everything great that we’re getting to do, all the good stuff happens when we treat our lives like a game, and play, fearlessly.

Database Constraints, Stereotypes, Rails, Culture, Talmud, Gender, MINASWAN, Religion. But ABSOLUTELY NO BONDAGE PLAY

Posted by amy on November 02, 2007

This post started out with a plan to compare constraints in software to bondage play, and suggest that DHH is a top who likes to constrain others (”opinionated software”) but is extremely uncomfortable being himself constrained (by, say, the database). I was going to suggest that DHH maybe needs to get a little bit more confident and comfortable being a ‘bottom’.

Now, that would have been a wildly, wildly inappropriate post, don’t you think? So it’s lucky for me that as I was writing it, I realized that not only was it inappropriate, it was completely unfair. So this post is still about rails culture, and still about database constraints, but I am not, I repeat, NOT arguing one way or another about DHH’s predilections in bondage play (assuming he has any, and if he does, not that there’s anything wrong with that ), about which I am, and hope and plan very much to remain, ignorant.

That out of the way, how did this all come up? Yeah, my mind’s a little twisted. But here you go:

My friend and partner-in-teaching-crime* (well, boss in teaching-crime, technically, and is teaching really a crime? To my students: do not answer that!) John complained recently about the difficulties of writing a migration to turn a plain HABTM join table (two foreign keys, no primary key, nuthin’ else) into a join table with state, linking two other tables with the :has_many :through association. Unfortunately, as he describes, ActiveRecord won’t let you add a primary key column to an already-existing table, so he had to migrate all the data over to a new table.

Couldn’t you just drop down to “execute ‘db-specific sql here’”? I asked.

Yeah, but you wouldn’t be database-agnostic, of course. John likes to be agnostic. He has historical reasons for that, just like I have historical reasons for thinking that ads comparing servers to who won’t give blow jobs are kinda offensive. But anyway, I don’t have those reasons that John does to prefer agnosticism. I figure that in most cases, people are sticking with the database they’ve got, so database agnosticism isn’t that important to me. The ORM is one of Mr. Spolsky’s leaky abstractions, and while that’s no excuse to start poking extra holes through just for the fun of it, I don’t have any need to pretend that the holes that exist aren’t really there.

In any case, I drop down to the database to put in foreign key constraints.

[Aside: John said in email:

“There is a distinction to be made between this narrow case of
agnosticism (fiddling with keys) and the general case. The narrow case
is easier to disregard. In the general case, it is very difficult to
argue against agnosticism, because the primary driver is: You get to
know less. That is frequently (more frequently than not) beneficial,
right? In the general case, I would rather write
user.find_all_by_last_name rather than the raw SQL. etc.”

I agree wholeheartedly, and in that sense I too am in favor of database agnosticism. But obviously we have different levels of allegiance to the idea, because I would never have put in the effort to come up with a database-agnostic migration from a HABTM to a has many through relationship, and he did. Maybe it’s just that I am lazier than he is, though…]

So this post was going to be about how it is the rails way not to use foreign key constraints at all, but to rely on ActiveRecord and your own unit testing to maintain data integrity. (hah!) And I was going to say “that’s freakin’ insane and evidence of all that is wrong with the whole culture of Rails.” But while it would be fun to see what this temporarily did to my site stats, (assuming it got dugg or reddited or something) it wouldn’t be fair.

I found very little evidence that not using foreign key constraints is considered to be a best practice by most people in the rails community. The main thing is this caboose posting, from last year. This was mostly a complaint about how big of a pain in the ass foreign keys are, especially where fixtures are concerned. But it actually only at the end claims that foreign keys are not needed, if you are using ActiveRecord Associations correctly. And even then, it’s a weak claim, about foreign keys in the development database:

The time thing sold me on not using foreign keys in development. I’m sure there are a number of arguments that can be made for using foreign keys etc etc, but it’s just stuff that gets in the way in a framework like rails. Do we test w/ foreign keys in place before milestones(what I’m leaning towards)? Do we test w/o the fks in place(obviously not :])? Maybe somebody can come up with a better way to handle them, but I don’t really think you need fks if you’re using rails associations correctly. If you are forced to use them though, the above approach might be a good place to start.

Okay, I found one other posting, from a guy who gave up his foreign key constraints (and wept) because they were too hard to use with fixtures. But most people in the comments of that post seems to think the problem there is not foreign key constraints, but fixtures, and that dropping the reliance on fixtures would be the smarter thing to do. Or fixing the fixtures, or whatever.

DHH has nothing to say on the matter that I could find. In AWDR, Dave Thomas explicitly advocates the use of foreign key constraints (2nd Edition, p. 324). Mostly what I found on the web about rails and foreign key constraints was a bunch of people talking about how they do use them and you’d be crazy and irresponsible not to. Yes, people differ on when in the development process they put them in (in fact, right this minute I have a development database with a near-complete lack of foreign key constraints, my rather pathetic excuse being that the client’s requirements are so changeable right now that we can hardly keep up with the foreign keys themselves…), how they use them with fixtures, and other details, but I really found very little evidence that anyone in the rails world seriously advocates putting into production web applications backed by databases without foreign key constraints. Relational database technology is mature, it’s well-tested, and it’s logical. I trust it much more than I trust either my own code or DHH’s. Database constraints are easy to use and good for you, just like flossing. And that appears to be the majority view.

So the evidence wasn’t there, and I had to rethink this post entirely. And so it’s become, in part, a post about stereotypes, and about culture, and about the ways that people confuse technologies, creators, fans, and users.

Rails is a technology. The technology exists in the context of a culture. The culture is greatly influenced by the fact that a single, very opinionated, um, strong personality developed the technology. Certain kinds of people are attracted to the opinionated personality, and become involved in the technology and its culture because of that. This is great for adoption of the technology. But then you get the fanaticism: rabid pro-Rails trolls who jump down the throats of people they perceive to be deviating from the One True Way of DHH. And equally rabid anti-rails trolls, screaming “Twitter”!

Now, is all this clash of personalities and hue and cry integral to the development of the technology, or is it epiphenomenal? (Is that a word?) I’m not sure. The anthropologist in me says it is, and that the culture of rails in some sense IS rails — drives its development, ensures or prevents its success, etc. The Marxist in me thinks perhaps the structure of rails itself is responsible for the culture surrounding it: the culture reifies the framework. And the poststructuralist in me suggests that, however determined things appear to be, however narrow and defined and boundaried and opinionated and one-true-wayed things appear, there’s always space for something else to arise.

There’s the One True Way of DHH. There are rabid fanboys. We talk of drinking the kool-aid, and we laugh at video advertisements comparing the separation of concerns, database-agnosticism, and ease-of-use of Rails to PHP, Java, et. al. “With rails, I can build a blog in 10 minutes,” we say. With rails, we never have to code again! Let’s just go to the beach instead! There was the Twitter developer scaling scandal, and the CDBaby switched-back-to-php-from-rails scandal, and a bunch of scandals I haven’t even heard of, no doubt. There’s the rails bandwagon, the rails hype, rails lets crappy developers wreak havoc quickly, rails is too slow, and rails is not ruby.

And that’s all fine and part of the fun, and part of the DHH Is Opinionated and So We Are Opinionated - ness of Rails culture.

But then there’s the technology, and lots of quiet, not-so-opinionated, flexible people who are using Rails because it’s a pretty good, pretty easy framework that helps them get their work done. There’s plenty of that too. And there’s no need to decry the partisan atmosphere of rails culture with a great big rending of garments about how the culture really has to change if it’s going to achieve more popularity, and it’s scaring people off because it seems too hyped, and badly executed rails projects are giving rails a bad name and how can we police that, and so on.

Let’s just all get on with our work, using rails, or not, as the work dictates. And in a mild-mannered matz-y way, talk about what we are doing, and why, and how, and what we like, or don’t, about it.

For me, rails is a web framework, not a religion. I know that not everyone feels or acts that way, and that’s fine for them. They can wave their hands and argue about what constitute a ’scale’ for the purposes of determining if a fish is kosher, or if one should use foreign key constraints. Me, I’ve got to get dinner on the table.


* Max would like it noted that he thinks there’s something very trite about the expression “partner-in-crime”. He’s right, of course, but I think I’ll leave it in anyway, to annoy him.

Fun Facts about Rails: nil.blank?

Posted by amy on September 02, 2007

$ script/console
Loading development environment.
>> nil.blank?
=> true
>> ''.blank?
=> true
>> [].blank?
=> true

That’s useful, but I had either never read it, or had read it and forgotten it. Apparently I’m not the only one.

Annals of Idiotic Bugs

Posted by amy on August 21, 2007

I’ve decided I like bugs. Not in production code, of course, but in development code, yay for bugs. Fixing my code teaches me far more than writing it did. Perhaps that’s because, with example code and snippets and tutorials all over the internet, much of the code that I write I don’t really write. I copy something I saw from something else and modify it to suit my own needs, or I look it up in a recipe book, or I see someone else’s solution on a mailing list… When you’re new to a language, you often use code that you don’t quite understand. I’m curious, so I try to understand it, but I don’t always have the time.

But then you get the bugs. And to fix the bug, you have to understand the code. (no, I know, that’s not really true. you can fiddle around with bug fixes just like regular code, and find someone else’s fix and implement it and it works and you’re in a hurry so you don’t care why it works, just that it does…)

Anyway, most normal developer bugs are stupid. I suppose there are great developers out there whose bugs are subtle and interesting. Most of mine, anyway, are quite stupid.

Here are some of my stupid bugs:

1) Implemented a slideshow. Stored stuff in the session to use during the slideshow. At end of slideshow, remembered to clear the slideshow stuff out of the session. Yay for me! Oops, child calling, check in code!

Max: “Um, Amy, how come playing a slideshow deletes all the photos in the slideshow?”

Me: “Dunno, maybe it has something to do with clearing the session? Why would deleting a thing from a session destroy it?”

Here’s what I had to clear the slideshow out of the session:
session[:slideshow].clear

Here’s what I should have had:
session[:slideshow] = nil

Oh, and here’s what was in the slideshow:
slideshow = domain_object.photos

So it’s not like my slideshow was just an array of any old ActiveRecord objects. It was a particular other ActiveRecord object’s personal array: i.e., an ActiveRecord AssociationCollection. AssociationCollections have a method called clear. Clear removes all the objects from the collection, like delete_all. Except delete_all doesn’t, according to the doc, destroy records, it just deletes them. And assoc_collect_.clear definitely destroys them, because not only did calling it kill the database records for my photos, it also killed the actual photos on the filesystem. So are clear and destroy_all the same thing? The doc is thin, so I went to the source:

# File vendor/rails/activerecord/lib/active_record/associations/association_collection.rb, line 67
67:       def clear
68:         return self if length.zero? # forces load_target if hasn't happened already
69:
70:         if @reflection.options[:dependent] && @reflection.options[:dependent] == :delete_all
71:           destroy_all
72:         else
73:           delete_all
74:         end
75:
76:         self
77:       end

So, domain_object.association_collection.clear does to the collection what domain_object.destroy would do, which is either to delete or destroy the associated records depending on what options you set in your call to has_many:

:dependent - if set to :destroy all the associated objects are destroyed alongside this object by calling their destroy method. If set to :delete_all all associated objects are deleted without calling their destroy method. If set to :nullify all associated objects’ foreign keys are set to NULL without calling their save callbacks.

I’d set :dependent => :destroy_all, so that’s what calling clear did. Oopsie!

Why did I use .clear anyway? Apparently I was thinking of my rake task rake db:sessions:clear.

In any case I didn’t want to be storing whole photo objects in my session anyway. I just wanted IDs: session[:slideshow] = domain_object.photos.collect { |p| p.id }

2) Wrote some boilerplate code for a create action. On failed validation, Rails complains there’s no create template to render. Why are you trying to render a create template, Rails, when I clearly ask you to render new upon failed validations:

render :action => new

Uh, because I told rails to render :action => nil. So rails defaulted to its standard "render the template whose name is the same as the action invoked" and went looking for a create template. What I needed to be saying was:

render :action => 'new'

Problem fixed. That one took me way too long to track down. I wish Ruby would complain to me about things that look like local variables but don’t seem to have any values attached to them. I’m not quite used to bug fixing a dynamic language, without the crutch of the compiler.

Right, what else?

3) If I want, temporarily, a list of all the photos in both a & b, where a & b are two different ActiveRecord objects, I should not do the following to get the list:

list = a.photos << b.photos

This moves all the photos in b over to a, permanently, in the database. This is one of the pitfalls of the syntactic sugar of methods that look like plain old operators. They’re not, really. ActiveRecord sometimes does more stuff than you want or expect it to, behind the scenes. Not a save or update in that code to warn me that I’m calling the db, but I am.

4) Oh, and the stupidest thing of all:


if  x = y
	#do stuff
else
	# do some other stuff
end

How come the ‘other stuff’ is never getting done!??
Duh, because X will always equal y if you assign it to y instead of checking to see if it == y!

Conclusion

This concludes the first edition of: Amy reports dumb things she did in Ruby code so you don’t have to do them too. C’mon, be original, and come up with your own bugs! I do not release my bugs under a Creative Commons license. I want royalties on all software including these particular bugs. I am going to implement DRM on these bugs. Don’t you dare steal my buggy code! It’s mine, mine, all mine!

10 things you should know about method_missing

Posted by amy on August 01, 2007

[update, 9:27 a.m., 8/1/2007: welcome, reddit readers. annoyed at me for calling this post “10 things”? Well, then you’ll really hate me after reading this post!]

1. method_missing is a Ruby kernel method and everyone should know about it.

2. Rails implements some of its funkiest magic with method_missing. When you ask your model to find_by_freaky_column_name, and it does so, that’s because ActiveRecord::Base overrides the kernel’s method_missing method.

3. method_missing is the method of last resort. When you send a message to a Ruby object, Ruby looks for a method to invoke with the same name as the message you sent. (There are a bunch of different ways to send the message, but the most common one is just obj.method_name. But you can make the fact that you are sending a message explicit by using obj.send(:method_name)). First it looks in the current self object’s own instance methods. Then it looks in the list of instance methods that all objects of that class share, and then in each of the included modules of that class, in reverse order of inclusion. Then it looks in that class’s superclass, and then in the superclass’s included modules, all the way up until it reaches the class Object. If it still can’t find a method, the very last place it looks is in the Kernel module, included in the class Object. And there, if it comes up short, it calls method_missingYou can override method_missing anywhere along that method lookup path, and tell Ruby what to do when it can’t find a method.

4. Sometimes people use method_missing to implement some default behavior they want to occur; more often they seem to use it as a kind of method factory or dispatcher. They have a class or module that they want to have many methods that do generally the same kinds of things, they’re not sure in advance which methods people will actually want to call, or there are so many of them, and they’re all so similar, that it seems like a waste to implement them all by hand. So they just say, okay, if someone gives me a method that doesn’t exist, I’ll assume that they’re trying to do this general kind of thing, and I’ll make them a method based on their name that does the thing they probably want it to do.Sometimes they make a new method and add it to the class (factory); sometimes they just do what needs to be done in method_missing itself (dispatcher).

5. Basically, method_missing is one of the features of Ruby that make it remarkably easy to create your own DSL for fun and profit. DSLs are Domain Specific Languages, which, if you didn’t know — and of course, dear reader, you did, because you are oh-so-up on all the oh-so-fashionable programming paradigms, are the big thing that Martin Fowler is talking about a lot these days.

6. Here’s the kernel’s method_missing implementation. It’s in C, so I have no freakin’ clue what it’s doing, but I know what the result is: a NoMethod error:

irb(main):227:0> "thingy".invoke_method_missing_for_demo_purposes("arg", "other arg")
NoMethodError: undefined method `invoke_method_missing_for_demo_purposes' for "thingy":String from (irb):227

7. Now here’s Jamis Buck showing us how ActiveRecord::Base overrides method_missing. It’s a long but fascinating article that takes you step-by-step through some Rails source code. Go look at it now.

8. method_missing is said to be slower than calling an actually-already existing method, unsurprisingly, given that it’s by definition invoked only after Ruby’s looked everywhere else for your method. The speed issue may or may not matter for your intended use, and my impression is that it usually doesn’t. #{usual disclaimer about benchmarking, using profilers, and not prematurely optimizing your code.}

9. method_missing can also be a bit opaque to users of your code, since dynamically created methods are, of course, not documented in the API.

10. The use of method_missing falls under the general technique of metaprogramming, which is a big deal in Ruby, and not something ordinary folks ever fool around with in many other languages (like Java). At least, I never fooled around with it in Java. But hey, what do I know? What is metaprogramming? C’mon, people, it’s right up there with DSLs in the list of things the kewl kids know. But actually, it really is pretty cool, and it really is pretty much the way Ruby works. And it’s not as difficult as (but waaaay more useful than) say, Lacan, despite the poststructuralist-sounding name and the fact that the metaprogramming wikipedia article makes it sound very fancy.

Ignore the wikipedia article, listen to _why, in a discussion of method_missing: “I don’t think the idea here is to save memory or speed. The idea behind metaprogramming is to teach Ruby your conventions and let it do some guessing, in order to save you some code.”

Don’t trust that _why and all his chunky bacon? Here’s David Black, equally reassuring:

One of the great accomplishments of Ruby is that its object and class model bring about a wonderful unity and simplicity. Even things that might seem like they should be hard or obscure are actually very transparent, once you have the hang of how the model works.Unfortunately, there’s a trend toward drawing an increasingly sharp line between regular programming and “metaprogramming” in Ruby discussions, where metaprogramming is understood to mean… well, I’m not sure what it’s understood to mean, the way it’s getting used in connection with Ruby, and that’s the problem.There’s no natural separation between programming and metaprogramming in Ruby, and no reason to make life harder by breaking them apart. The thrust of Ruby’s design is to dissolve complexities, so that even things that appear to be “wizardly” or full of “dark magic” actually make perfect sense in terms of a relative small number of underlying language principles.

So here’s your takeaway #{max gagging sound}: method_missing is cool. It’s metaprogramming. It’s used to save programmer time and typing, and to make DSLs or provide default behavior. Most famously in ActiveRecord dynamic finders. Metaprogramming is not scary, and method_missing, like other cool Ruby features, may or may not float your boat. That’s cool, either way.

_why says: “I never use method_missing. Maybe twice. And both times I didn’t use it, regretted it, forcefully ejected the code from a moving vehicle, shed nary a tear.” Then he goes on to enumerate some of the very cool ways he’s seen method_missing used elsewhere, in non-_why code.

So: know it, love it, use it, hate it, kill it, eat it, break it, think it. As they say at Ari’s preschool: “Have fun, be safe, and USE YOUR IMAGINATION!” Matz wants you to.

Rails Ninjas We Are Not

Posted by amy on July 09, 2007

The other day I responded to an ad looking for Rails Ninjas. A very nice guy called me up to talk about his startup. He asked me to talk about our rails skills. Would I describe myself or Max as a rails superstar? I said “look, we’ve been using rails since March. We are not rails superstars.”

Why did I respond to an ad asking for Rails superstars when I make no claims to be one? Because there are many ads looking for Rails superstars and there are not enough to go around. There certainly aren’t undiscovered rails superstars around. We’re not talking supermodels here. You don’t take an ordinary Romanian peasant and turn her into a rails superstar overnight with a nice haircut and a manicure . Rails superstars have blogs and open source projects and debates about the importance of symbols on the rails-core mailing list. They have histories.

Me and Max, we don’t yet have a history with Rails. We are not superstars.

And yet, we are not script kiddies. Rails is full of amazing magic. How do instance variables set in the controller end up as instance variables in the view? Who knows? And who cares? Script kiddies don’t care. It’s automagically terrific, and that’s all they need to know.

If you look at the source code, though, you fall down a rabbit hole. You discover that Ruby itself has a method called instance_variable_set (be sure to check out the documentation on that!), that you can call on _any_ ruby class. How utterly transgressive! You can just shove whatever you feel like in anyone’s class at any damn time you please. You can make brand-new methods on the fly, when you need them, by using method_missing to make a new method whenever you call one that doesn’t yet exist. Amazing feats! And not implemented in secret or in C or something that isn’t any fun to look at and that there’s little hope of your ever being able (or particularly wanting) to do similar things yourself. All the magic is just hanging right out there for everyone to see. And it’s all just part of Ruby, a cute little language that’s fun to code.

And you think, yes, I can do this! Someday I too may tackle the continuation koans.

But not just yet.

What good is in_place_edit_for if it bypasses validations?

Posted by amy on July 07, 2007

I broke down and did some AJAX crap on our big rails app. Cool, I thought. I’ve got my drag-and-drop lists with acts_as_list and my in-place-edits. Don’t we look all sexy and modern? Except in_place_edit_for doesn’t bother validating changes to the model. Someone wrote a custom implementation which does do validation but I haven’t tried it out. I just yanked out my in-place-edits for the moment. I’m irritated. Gotchas everywhere. Oh, and I’m having routing issues today too.

On the plus side, I did solve some troubles I was having with Attachment_Fu’s thumbnailing. Though it’s choking now on destroy (thumbnail-delete troubles, I think I read about those somewhere). Full post on Attachment_Fu to come when we’ve ironed out all our weirdness with it.

Testing in Rails: Way More Trouble Than Flossing

Posted by amy on June 27, 2007

So the other day Max and I had a joint interview for a Rails job, and the hiring manager obviously felt that our knowledge of testing in rails left something to be desired. Too true, too true. But he also told us that he thought that learning to test in rails, and learning TDD in general, was basically straightforward and simple. As in, “you are idiots that you flubbed your answers to my questions about it.” I am sure we are idiots for some other reasons, but not completely grokking TDD should not be one of them. If TDD were easy to grok and easy to do, there wouldn’t be so much evangelizing around it. There wouldn’t be courses and lectures and demos and new articles every day about why you might want to bother doing it. Here’s Gregory Brown, just a couple weeks ago, still having to argue that rails testing is Not Just for the Paranoid.” :

The real issue most people have with testing is not that they think it’s a bad idea, but that it often means a whole lot more configuration, a whole lot more to learn, and lots of things that smell like extra work. Folks who have been in that crowd will be pleasantly surprised when working with Rails.

Thanks Gregory, but no, they really won’t be pleasantly surprised. Or at least, not immediately. We’ve been working with rails testing since March, and it still smells like more stuff to learn and more work to do. I’m sure it’ll start seeming easy in the future, but right now, not so much.

First off, there’s fixtures. Apparently everyone important agrees that rails fixtures suck. But mostly no one tells you this when you’re first learning to write tests. They reload before every damn method, which would be useful, except that they slow your testing down amazingly. I was feeling very proud of myself for using a Rails Recipe for erb in my fixture files to generate lots and lots of test data for very little effort, and wow, did it show in test slowness, not so much on my machine, but on Max’s, which is older and slower. Then there’s that whole weird transactional fixtures flag that Max wrote about, that no one tells you about but that can cause your db not to look anything like what you expect at the end of a test method. Lots of people refuse to use fixtures at all, or only use them to, hmm, load data directly into the test db, not for testing. Other people point out that fixtures are a pain to keep updated when you make changes to your db, so every time your model changes, all your tests may break because your fixtures no longer work properly. So then a model change involves: change your model. Make a db migration. Change your fixtures. Change your test code. Someone has written a nice little fixture migration task, but at this point, I think we’ll just change our testing strategy to not involve much in the way of fixtures.

Then there’s the TDD/BDD and third-party testing tools thing. Do we invest our efforts in TDD even though BDD is the new big thing, so should we just skip straight to RSpec? Do we learn Test::Unit really well before we switch over to ZenTest’s Test::Rails? What about MonkeyTest? And rcov?

Oh, and how about assert_select? I turned around the other day and suddenly I was knee-deep in the DOM. All I wanted to do was check to make sure that when my user was viewing an item that belonged to him, he also saw two buttons, ‘edit’ and ‘delete’. And that when he wasn’t, he didn’t. It wasn’t obvious how to do it, and it turns out that if I want to make it easier to use assert_select, I probably need to be putting way more ids in my html tags. And then, I added a new feature, and a new button, and my tests broke.

Of course, tests are always breaking. I understand that it is a feature, not a bug, to be forced to understand all the implications of new code. Still, it’s frustrating.

Finally, and this is, perhaps, the root of the problem, there’s all the additional decision-making overhead imposed by the very act of testing. Not all this overhead is ‘good’ overhead — that is, not all of it ultimately contributes to the quality of your code. Most of it is just one niggly decision after another. How do I organize my test code? What do I test? How many tests are enough? What should be its own test method, and what should just be a couple of lines in some other test method? Should I use setup or not? Fixtures or not? Which frameworks? There are fifteen different assert methods that will do what I need them to do, in slightly different ways: which one should I use? Oh wait, is that one deprecated? How come this assert method doesn’t work? Oh, because it’s a Test::Rails method, and I’m not actually using Test::Rails, I just saw it somewhere. All those decisions are exhausting.

Bitch. Bitch. Bitch. I realize I may now have destroyed all my credibility as a test-driven-developer by complaining about all the things I don’t get and don’t like about TDD in rails. But I think it’s annoying to be struggling with something and read nothing on the internet about it other than “it’s easy and awesome”. I have drunk the TDD kool-aid, obviously, because if I hadn’t I wouldn’t bother with it since it obviously causes me a fair amount of pain. And maybe in six months I too will say “hey, yeah, testing in rails is easy and fun!” But right now, it’s neither easy nor fun. But right now, today, I am saying it loud and saying it proud, to you, the internets, to you, other struggling Rails developers, to you, the world: TDD is good for you, like flossing, but it is much, much harder.

The moral of this story is that every night as you floss your teeth, you should thank your lucky stars that something so good for you is also so easy to do. I know I will.