forumwarz and rjs: a love/hate affair

54
Forumwarz and RJS A love/hate affair

Upload: guest06ed72

Post on 13-Jul-2015

1.199 views

Category:

Business


1 download

TRANSCRIPT

Page 1: Forumwarz and RJS: A Love/Hate Affair

Forumwarz and RJSA love/hate affair

Page 2: Forumwarz and RJS: A Love/Hate Affair

An internet-based gameabout the internet

Page 3: Forumwarz and RJS: A Love/Hate Affair

LOL WHUT?

Page 4: Forumwarz and RJS: A Love/Hate Affair

The Internet is a wonderful, magical place!

Page 5: Forumwarz and RJS: A Love/Hate Affair

But it’s also terrible.

Page 6: Forumwarz and RJS: A Love/Hate Affair

Very, very terrible.

Page 7: Forumwarz and RJS: A Love/Hate Affair

John Gabriel’s Greater Internet Fuckwad Theory

Page 8: Forumwarz and RJS: A Love/Hate Affair
Page 9: Forumwarz and RJS: A Love/Hate Affair

Exhibit A

Page 10: Forumwarz and RJS: A Love/Hate Affair

Have you heard of it?• One of the most popular forums in the

world

• Almost all its users are anonymous

• Unfortunately, it’s hilarious.

Page 11: Forumwarz and RJS: A Love/Hate Affair

The anonymity of the Internet means you can

be anything...

Page 12: Forumwarz and RJS: A Love/Hate Affair

You can be another ethnicity!

Page 13: Forumwarz and RJS: A Love/Hate Affair

You can be another species!

Page 14: Forumwarz and RJS: A Love/Hate Affair

You can even be beautiful!

Page 15: Forumwarz and RJS: A Love/Hate Affair

(Even if you’re not.)

Page 16: Forumwarz and RJS: A Love/Hate Affair

Are you going to explainwhat forumwarz is, orjust show us hackneyedimage macros all night?

Page 17: Forumwarz and RJS: A Love/Hate Affair

Role-Play an Internet User!

Camwhore Emo Kid Troll

Page 18: Forumwarz and RJS: A Love/Hate Affair

• Each player class features unique abilities and attacks

• Many different ways to play

• A detailed story line ties it all together

Role-Play an Internet User!

Page 19: Forumwarz and RJS: A Love/Hate Affair

An interface heavy in RJS

(please endure this short demo)

Page 20: Forumwarz and RJS: A Love/Hate Affair

Let’s get technical

Page 21: Forumwarz and RJS: A Love/Hate Affair

Forumwarz Technology

Page 22: Forumwarz and RJS: A Love/Hate Affair

Some of our stats• ~30,000 user accounts since we launched

one month ago

• 2 million dynamic requests per day (25-55 req/s)

• Static requests (images, stylesheets, js) are infrequent, since they’re set to expire in the far future

• About 25GB of bandwidth per day

Page 23: Forumwarz and RJS: A Love/Hate Affair

Deployment• Single server: 3.0Ghz quad-core Xeon, 3GB

of RAM

• Nginx proxy to pack of 16 evented mongrels

• Modest-sized memcached daemon

Page 24: Forumwarz and RJS: A Love/Hate Affair

Thank you AJAX!

• One reason we can handle so many requests off a single server is because they’re tiny

• We try to let the request get in and out as quickly as possible

• RJS makes writing Javascript ridiculously simple

Page 25: Forumwarz and RJS: A Love/Hate Affair

why we rjs

Page 26: Forumwarz and RJS: A Love/Hate Affair

A simple exampleExample View

Example Controller

#battle_log There's a large monster in front of you. = link_to_remote "Attack Monster!", :action => 'attack'

def attack @monster = Monster.find(session[:current_monster_id]) @player = Player.find(session[:current_player_id]) @player.attack(@monster) update_page_tag do |page| page.insert_html :top, 'battle_log', :partial => 'attack_result' end end

Page 27: Forumwarz and RJS: A Love/Hate Affair

Pretty cool eh?

• Without writing a line of javascript we’ve made a controller respond to an AJAX request

• It’s fast. No need to request a full page for such a small update

• It works great*

Page 28: Forumwarz and RJS: A Love/Hate Affair

* but it can haunt you

Page 29: Forumwarz and RJS: A Love/Hate Affair

Problem #1: Double Clicks

• Often, people will click twice (or more!) in rapid succession

• Your server gets two requests

• If you’re lucky they will occur serially

Page 30: Forumwarz and RJS: A Love/Hate Affair

A Solution?

var ClickRegistry = { clicks : $H(), can_click_on : function(click_id) { return (this.clicks.get(click_id) == null) }, clicked_on : function(click_id) { this.clicks.set(click_id, true) }, done_call : function(click_id) { this.clicks.unset(click_id) }}

• Use some javascript to prevent multiple clicks on the client side

Page 31: Forumwarz and RJS: A Love/Hate Affair

A Solution?

def link_once_remote(name, options = {}, html_options = {}) click_id = html_options[:id] || Useful.unique_id options[:condition] = "ClickRegistry.can_click_on('#{click_id}')" prev_before = options[:before] options[:before] = "ClickRegistry.clicked_on('#{click_id}')" options[:before] << "; #{prev_before}" if prev_before prev_complete = options[:complete] options[:complete] = "ClickRegistry.done_call('#{click_id}')" options[:complete] << "; #{prev_complete}" if prev_complete link_to_remote(name, options, html_options) end

• Add a helper, link_once_remote

Page 32: Forumwarz and RJS: A Love/Hate Affair

Our Example: v.2Example View

#battle_log There's a large monster in front of you. = link_once_remote "Attack Monster!", :action => 'attack'

Page 33: Forumwarz and RJS: A Love/Hate Affair

Surprise!

It doesn’t work!

Page 34: Forumwarz and RJS: A Love/Hate Affair

Why not?• Proxies or download “accelerators”

• Browser add-ons might disagree with the javascript

Page 35: Forumwarz and RJS: A Love/Hate Affair

Also, it’s client validated!

• Let’s face it: You can never, ever trust client validated data

• Even if the Javascript worked perfectly, people would create greasemonkey scripts or bots to exploit it

• Our users have already been doing this :(

Page 36: Forumwarz and RJS: A Love/Hate Affair

Server Side Validation• It’s the Rails way

• If it fails, we can choose how to deal with the invalid request

• Sometimes it makes sense to just ignore a request

• Other times you might want to alert the user

Page 37: Forumwarz and RJS: A Love/Hate Affair

Problem #2: Validations• ActiveRecord validations can break during

concurrency

• In particular, the validates_uniqueness_of validation

Page 38: Forumwarz and RJS: A Love/Hate Affair

The Uniqueness Life-Cycle

select * from battle_turns where turn = 1 and user_id = 1;

if no rows returned

insert into battle_turns (...)

else

return errors collection

Page 39: Forumwarz and RJS: A Love/Hate Affair

Transactions don’t help

• With default isolation levels, reads aren’t locked

• Assuming you have indexed the columns in your database you will get a DB error

• So much for reporting errors to the user nicely!

Page 40: Forumwarz and RJS: A Love/Hate Affair

A solution?• Could monkey patch ActiveRecord to lock

the tables

• That’s fine if you don’t mind slowing your database to a crawl and a ridiculous amount of deadlocks

Page 41: Forumwarz and RJS: A Love/Hate Affair

A different solution?• You can rescue the DB error, and check to

see if it’s a unique constraint that’s failing

• This is what we did. It works, but it ties you to a particular database

def save_with_catching_duplicates(*args) begin return save_without_catching_duplicates(*args) rescue ActiveRecord::StatementInvalid => error if error.to_s.include?("Mysql::Error: Duplicate entry") # Do what you want with the error. In our case we raise a # custom exception that we catch and deal with how we want end endend

alias_method_chain :save, :catching_duplicates

Page 42: Forumwarz and RJS: A Love/Hate Affair

Problem #3: Animation• script.aculo.us has some awesome

animation effects, and we use them often.

• RJS gives you the great visual_effect helper method to do this:page.visual_effect :fade, 'toolbar'page.visual_effect :shake, 'score'

Page 43: Forumwarz and RJS: A Love/Hate Affair

When order matters• Often you’ll want to perform animation in

order

• RJS executes visual effects in parallel

• There are two ways around this

Page 44: Forumwarz and RJS: A Love/Hate Affair

Effect Queues• You can queue together visual effects by

assigning a name to a visual effect and a position in the queue.

• Works great when all you are doing is animating

• Does not work when you want to call custom Javascript at any point in the queue

• Unfortunately we do this, in particular to deal with our toolbar

Page 45: Forumwarz and RJS: A Love/Hate Affair

page.delaypage.visual_effect :fade, 'toolbar', :duration => 1.5page.delay(1.5) do page.call 'Toolbar.maintenance' page.visual_effect :shake, 'score'end

• Executes a block after a delay

• If paired with :duration, you can have the block execute after a certain amount of time

Page 46: Forumwarz and RJS: A Love/Hate Affair

It’s me again!

This also doesn’t work!

Page 47: Forumwarz and RJS: A Love/Hate Affair

Durations aren’t guaranteed• Your timing is at the whim of your client’s

computer

• Your effects can step on each other, preventing the animation from completing!

• They will email you complaining that your app has “locked up”

Page 48: Forumwarz and RJS: A Love/Hate Affair

A solution?def visual_effect_with_callback_generation(name, id = false, options = {}) options.each do |key,value| if value.is_a?(Proc) js = update_page(&value) options[key] = "function() { #{js} }" end end visual_effect_without_callback_generation(name, id, options)end

alias_method_chain :visual_effect, :callback_generation

Thanks to skidooer on the SA forums for this idea!

Page 49: Forumwarz and RJS: A Love/Hate Affair

And then, in RJSpage.visual_effect :fade, 'toolbar', :duration => 1.5, :afterFinish => lambda do |step2| step2.call 'Toolbar.maintenance' step2.visual_effect :shake, 'score'end

• The lambda only gets executed after the visual effect has finished

• Doesn’t matter if the computer takes longer than 1.5s

Page 50: Forumwarz and RJS: A Love/Hate Affair

in Conclusion

Page 51: Forumwarz and RJS: A Love/Hate Affair

Nobody’s Perfect!

Page 52: Forumwarz and RJS: A Love/Hate Affair

Nobody’s Perfect!

• We love RJS despite its flaws

• It really does make your life easier, most of these issues would never be a problem in a low traffic app or admin interface

• The solutions we came up with are easy to implement

Page 53: Forumwarz and RJS: A Love/Hate Affair

this presentation was brought to you by

Page 54: Forumwarz and RJS: A Love/Hate Affair

this presentation was brought to you by

Any questions?