Close and Go BackBack to Viget

Right Way/Wrong Way: Closed Betas

Ben Scofield
Ben Scofield, Development Director, April 29, 2008 12

That’s right, everyone—it’s time for a thrilling episode of “Right Way/Wrong Way,” in which we see two possible solutions to a problem. One of ‘em’s good, one of ‘em’s bad, but we can all learn something from both of them!

This time: closed betas.

The closed beta scenario is very common; you’re working on a site that will change the game completely, and you want feedback from various people while you’re fine-tuning things. You deploy the site, but you want to keep the whole thing (except a teaser homepage, usually) behind some sort of login.

Solution 1:

Require people to log in to access any part of the site, and make the registration form available only via invitation. This is as simple as slapping a before_filter :require_login on your ApplicationController (with the appropriate skip_before_filter for your registration action)—but it’ll bite you when you go to take the site out of beta. You’ll be forced to go through controller-by-controller and add the login requirement individually. What’s more, your functional test suite won’t be as useful anymore, since you won’t be testing any cases with an unauthenticated user (all of which would’ve failed during the beta). This, then, is the Wrong Way.

Solution 2:

Instead of requiring login at the application controller level, go ahead and build your site as it will eventually be—some actions requiring authentication, some not. Then, for the closed beta, slap on an after-market extra authentication piece, either using Rails’s built-in support for HTTP authentication or some sort of cookie-based system. One version of this I’ve used in the past has invited users visit a special URL that sets an invited cookie with a two-month expiration (or however long the beta will last). Anyone who lacks the cookie sees only the teaser homepage, but once you’ve got it the whole site is open to you. Transitioning out of closed beta is as easy as removing the bolted-on extra authentication piece. Welcome to the Right Way.

Of course, there are other possibilities; the point of this isn’t to describe the only workable solution, but to get you thinking about the issue. While we might not be doing Big Design Upfront, we still need to keep the bigger picture in mind at times (which the Wrong Way here fails to do)

Tony Pitale said on 05/08 at 12:44 PM

Very nice but, how would you go about using HTTP authentication. I know how the auth is done in rails but, how would you position it to not screw up your tests?

Mike Breen said on 05/09 at 10:28 AM

I might be missing something but couldn’t a clever person spoof the cookie?

Ben said on 05/09 at 07:08 PM

@Tony: there are helpers to make HTTP basic auth easier to test. We don’t use it very often, but I’ve experimented with it a bit and don’t remember running into any issues in particular.

@Mike: possibly, but the exact approach we’re using isn’t just a cookie with invited=true - it’s a hash that’s specific to the invitation used. If we see unusual levels of activity tracking back to a single code, it’s pretty easy to dig in deeper and find out what’s going on.

Mike Breen said on 05/10 at 09:41 AM

Thanks for the reply Ben.
So you guys find it easier to track, and if need be investigate, cookie activity than to have a :before_filter? Couldn’t you have a script or rake task modify your Controller files when you’re ready to come out of beta?

Ben said on 05/10 at 11:36 AM

@Mike: The deep issue with putting :login_required statements on individual controllers is that it obscures your intention; when the sort of site I’m talking about comes out of beta, it’ll have some public pages and some pages hidden behind a login. You could write a script to go through and remove all and only those filters that you don’t want to keep in the public code, but it’s a hassle - and having those extra ones in the code during development confuses the issue of what should and should not eventually be public.

Your tests suffer from this same issue; under the Bad Way, most of your functional tests will require you to pass in a logged-in user, which means that you won’t be testing what pages look like to the public at all. That’s the recipe for a world of pain once you move out of beta.

Mike Breen said on 05/10 at 12:09 PM

I see where you’re coming from Ben. Thanks for being patient with me.

btw - I just recently found the Viget blog and have enjoyed reading it. Thanks for sharing guys!

Josh Adams said on 05/13 at 05:54 PM

I haven’t done it this way before, but wouldn’t it be a kind of good idea to name the different types of controllers something descriptive and subclass from them?  I’m thinking something like the following.

class PhaseHandlingController < ApplicationController
case CURRENT_PHASE
when :closed_beta
before_filter :hide_from_uninvited
when :open_beta
... something? ...
end
end

Then you can have somewhat robust control of your operation from environment.rb or some configuration file that sets CURRENT_PHASE for you.  Then you’re only changing a configuration option instead of changing code to handle phases, which smells much better to me.  Any reasons it’d be bad to just descend all but the teaser from the PhaseController?

Ben said on 05/14 at 06:38 PM

That’s an interesting idea, Josh - I’d think it would work fine, but it seems like a lot of structure to handle a temporary state. The benefit of the approach in the post is that once you’re out of beta, you get rid of the obsolete code. I’m a big fan of deleting code outright once it’s no longer used.

Josh Adams said on 05/15 at 08:33 AM

I tend to delete code that’s no longer used as well...but this is the kind of long term controller you can commit to on all your projects and put in your base project for all future apps.  This way you could copy/paste the controller into a new project when you needed that functionality, too :) Plus, having the controller there allows you to extend your site with similar functionality at any time in the future (ever release new features to a select group of people?)

Ben said on 05/16 at 06:47 AM

Good point, Josh - it’s an approach that definitely bears thinking about. Quick question, though: why would you even need to make this another controller. I’d think you could just drop that case statement into ApplicationController directly.

Josh Adams said on 05/16 at 09:07 AM

Ben,
Only those controllers that are subject to being involved in the phases thing would subclass from PhasesController.  Content pages, etc. would just descend from ApplicationController.

The real answer is: I don’t know.  I’ve never used this in a live site setting, but it seems like a nice programmatic way of getting around the (smelly) ‘delete code when the time comes’ idea.

That’s all.  I’d love to find out if it works well in practice, but I just have no call for it right now ;)

Ben said on 05/16 at 04:14 PM

Ah, that makes sense - but it wouldn’t work in the later case you mentioned (new features after launch), since you’d have to reset all your other controllers to inherit directly from ApplicationController again to avoid improperly protecting already-released functionality.

Name:

Email:

URL:

Not a robot? Prove it by entering the word below.


Remember my personal information

Notify me of follow-up comments?

A Development Community for Viget Labs and Beyond

Every team member here at Viget Labs strives to be an innovator. We members of the development team are no different - that's why we're constantly engaging in community discussions and exploring the unknown that is the next generation of open-source web applications.

Viget Is Hiring!

Viget has job openings for Ruby Developers, Interns, and Front-End Developers. Learn More »

Recent Comments

Interesting.

I’ve been (mis)using similar behaviour in javascript for years.


var i = 0, car;
while( car = cars[i++]){
// do stuff
}

I suppose that the reason it works is exactly the same reason it works in Ruby ... but in this case I think the code is actually very easy to read.