Skip to content
Jun 10 10

Review: Byline app for iPhone

by Topper

The Byline reader for iPhone is awesome. It syncs your google reader account into an offline cache that is simply perfect for the subway. I am currently using the new free version which is ad supported. The ads are unobtrusive and the app just seems to work.

I did have one problem that after reading several articles I would keep getting a white screen. I have hundreds of feeds with thousands of articles and interrupted a sync – so maybe that was the cause.

The app is so good I missed two subway stops on the way to work. Woops! But I recommend anyone who has an iPhone and a Google Reader account to get this app.

I am in no way affiliated with the Byline team.

Jun 3 10

Path to Pretty

by Topper

I’ve been thinking a lot about my pragmatic approach to programming (sorry to steal from very great books).

I’ve never been the zealot that makes sure all code is perfect before shipping. I also recognize the tremendous value that aesthetic code brings (that’s why I’m a ruby guy). However, the important part of writing code is getting it out to the users. Those users might be your fellow coworkers (if you’re doing something back-endy) or they might be consumers.

My code will not matter unless someone is using it. So I get it out quickly.

That being said, I’ve seen us cut corners too many times and it always comes back to haunt. It costs hours and hours cost dollars. Bad code is not good for anybody.

My users will suffer from bad code because I won’t be able to react to their needs in a timely manner.

I think I have been intuitively following a pattern now for a while that seems to work out. I’ve been calling it “Path to Pretty” in my head.

It’s ok to ship code that I would consider lacking if the intent and next steps for improvement are clear.

By clear I mean that I must be able to go back in 2 months, look at the code and intuitively see what I was trying to do. If it’s not fully optimized or there are 20 extra lines, so be it.

As long as there is a clear path to pretty I now consider my code shippable.

Footnote: I’m sure I’m not the first person to do this and there’s probably some other name for this technique. This article was mostly for my own selfish benefit.

May 27 10

Zookeeper – Distributed cluster software

by Topper

I read this article about Apache Zookeeper at Igvita and was intrigued.

I started looking around for ruby libraries, but nothing was as mature as I would like. I forked a branch on github and chugged along on getting the jruby and c versions to work with the same api.

Zookeeper exposes a super simple API, but with that simple stuff you can build a lot of complex cluster logic.

RUBY:
  1. zk = ZooKeeper.new("localhost:2181", :watcher => :default) #this will handle events using my built-in event handler
  2. zk2 = ZooKeeper.new("localhost:2181", :watcher => false) #this one won't receive watch events
  3.  
  4. zk.watcher.register("/mypath") do |event, zookeeper_client|
  5.   $stderr.puts("got an event on: #{event.path}")
  6. end
  7.  
  8. zk.exists?("/mypath", :watch => true) # returns nil, but sets up the app to watch for the existence of /mypath
  9. zk2.create("/mypath", "my data up to 1mb", :mode => :ephemeral)
  10. # create modes can be any of
  11. # :persistent_sequential, :ephemeral_sequential, :persistent, :ephemeral
  12.  
  13. # now the registered watcher will fire (at least within a few 100 miliseconds)
  14. # because we set that node to be :ephemeral - when zk2 closes its connection, the "/mypath" will go away
  15. # but watches are one-time firing only - so we need to set it up again
  16. zk.exists?("/mypath", :watch => true) #returns true
  17.  
  18. zk2.close! #or delete or whatever
  19.  
  20. # the watcher fires again and
  21. zk.exists?("/mypath") #returns false

A limited api of create, delete, get, set, watch lets you do some really advanced things around a cluster.

Examples

I added some abstractions based on the Zookeeper recipes.

Locks

RUBY:
  1. #these 2 clients could be on totally separate boxes, different processes, whatever
  2. zk = ZooKeeper.new("localhost:2181", :watcher => :default)
  3. zk2 = ZooKeeper.new("localhost:2181", :watcher => :default)
  4.  
  5. lock1 = zk.locker("/mypath")
  6. lock1.lock #true
  7.  
  8. lock2 = zk2.locker("/mypath")
  9. lock2.lock #false
  10.  
  11. lock1.unlock #true
  12. lock2.lock #true
  13.  
  14. # locks are also released on a client close/crash
  15. lock1.lock #false
  16. zk2.close!
  17. lock1.lock #true

Message Queues

I also implemented a simple message queue on top of zookeeper. However, because of the way the zookeeper "children" calls are made (returning all children), I wouldn't recommend using this for queues where pending messages will reach into the thousands.

RUBY:
  1. client1 = ZooKeeper.new("localhost:2181", :watcher => :default)
  2.   client2 = ZooKeeper.new("localhost:2181", :watcher => :default)
  3.  
  4.   publisher = client1.queue("myqueue")
  5.   receiver = client2.queue("myqueue")
  6.  
  7.   receiver.subscribe do |title, data|
  8.     # data will be whatever was published, title will be the node name
  9.     # for the message
  10.  
  11.     $stderr.puts "got a message with: #{data}"
  12.  
  13.     # having a true state from the block will mark the message as 'answered'
  14.     # sending back a false will requeue
  15.  
  16.     true
  17.   end

More...

There's a ton you can do with this thing (priority queues, meta data store, etc). I think it's a nice addition to the ruby toolset.

May 5 10

WebSockets

by Topper

I've been thinking a lot lately that websockets are going to fundamentally change the architecture of the web. It lets you think about backend architecture in a whole new light. Projects like Nanite, EventMachine, Mongo, Redis... I think these are the future. I even question the utility of rails in a client-side-app-always-connected world.

I'm just pondering now... trying to flesh out what I think is going to happen and how we can embrace it sooner.

TO COME:
Events: Modern JavaScript architecture is actually pretty powerful, how can we take the "bolted on functionality" approach to servers.
Messages: They're kinda like events right?
Request/Response Cycle: it's probably dead?

Apr 26 10

New Facebook Javascript API

by Topper

UPDATE:
http://developers.facebook.com/docs/reference/javascript/FB.login
Only allowed to prompt for permissions due to a user action. Which is shitty, but I should have seen is documented.

I love the *looks* of the new Facebook javascript API. It's got one major flaw though. It doesn't work in Safari or Chrome. I have an app setup to use http://localhost:7000/ as the connect url and everything works *great* in Firefox. Things even work mostly ok in safari or chrome... but as soon as you try to launch the permissions dialog box you get the browser cycling through "unsafe javascript attempt to access frame with URL."

Best part about this whole thing is: the facebook developer forums throw the *same* error.

Also, when I try to create an account on the forums (not using facebook connect) I get a "cannot connect to socket" error.

I guess I go back to their older clunkier API? Seems to be a number of complaints but no answers from Facebook.

Any ideas?

UPDATE:

That error just keeps growing and growing.

I'm initializing my facebook like:

JavaScript:
  1. FB.init({
  2.         appId  : '<myappid>',
  3.         status : true, // check login status
  4.         cookie : true, // enable cookies to allow the server to access the session
  5.         xfbml  : true  // parse XFBML
  6.       });


Minimal Repro:

If you put the following HTML at 127.0.0.1:7000 and hit the page you are UNABLE to do the following from the console:

JavaScript:
  1. FB.login(function (resp) { console.dir(resp);}, {perms: 'publish_stream'})

HTML:
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns:fb='http://www.facebook.com/2008/fbml' xmlns='http://www.w3.org/1999/xhtml'>
  3.     <title>
  4.       Test page
  5.     </title>
  6.   </head>
  7.   <body class='mbx'>
  8.  
  9.     <div id='fb-root'></div>
  10.     <script src="http://connect.facebook.net/en_US/all.js" type="text/javascript"></script>
  11.     <script type='text/javascript'>
  12.       //<![CDATA[
  13.         FB.init({
  14.           appId  : '10562765058',
  15.           status : true, // check login status
  16.           cookie : true, // enable cookies to allow the server to access the session
  17.           xfbml  : true  // parse XFBML
  18.         });
  19.       //]]>
  20.     </script>
  21.   </body>
  22. </html>

Mar 1 10

What the world needs now is Croons, sweet Croons

by Topper

Looks like we just did a big publicity push for Croon My Tune. Everybody should go check it out.

http://croonmytune.com

or read about it here: http://jumpcanopy.com/?p=21

Feb 28 10

_method in recent rails is brokenish

by Topper

I was trying to pass in _method: 'put' as part of a json body and for some reason rails kept not realizing that I wanted to put.

Then I came across this article: http://stackoverflow.com/questions/1249282/set-method-to-put-in-rails-xml-requests

So... if you're using prototype your "put" methods look something like this:

JavaScript:
  1. new Ajax.Request(url, {
  2.                 onSuccess: callback,
  3.                 requestHeaders: {'X-Http-Method-Override': 'put'},
  4.                 postBody: Object.toJSON(params),
  5.                 contentType: "application/json"
  6.             });

Feb 23 10

Game Theory

by Topper

You can skip the last 10 minutes or so when he dives into this odd crazy future... but the beginning part really makes you think about how you can add game theory to any business you're in. I really like the idea of experience points and leveling up for class. That's something any event-based business could really get into.

h/t Andrew Holz. via fury.com

Jan 27 10

Rails thread safety

by Topper

Calling Rails.configuration.threadsafe! at the end of your environment.rb does *not* turn on multi-threading. Adding config.threadsafe! to your individual environments (like production.rb) *does* turn on multi-threading.

You can also check that your multi-threading is active by seeing if ActionController::Base.allow_concurrency is true.

We add ::RAILS_DEFAULT_LOGGER.fatal { "Mulithreading is active? #{ActionController::Base.allow_concurrency}" }
to the end of our environment.rb to let us know that it worked.

Dec 2 09

Google Analytics Launches Asynchronous Support

by Topper

Google Code Blog: Google Analytics Launches Asynchronous Tracking

Google Analytics Launches Asynchronous Tracking
Tuesday, December 01, 2009

Today we're excited to announce our new Google Analytics Asynchronous Tracking Code snippet as an alternative way to track your websites! It provides the following benefits:

* Faster tracking code load times for your web pages due to improved browser execution
* Enhanced data collection & accuracy
* Elimination of tracking errors from dependencies when the JavaScript hasn't fully loaded

This is excellent news. I had implemented something similar on my own, but it always had its own problems. I'm glad to see it officially supported.