Yehuda Katz from EngineYard talks about using JavaScript development using jQuery.
Monthly Archives: November 2008
Volatility: it's not just for sublimation any more
Multithreaded programming was a hot topic at RubyConf this year, and a common theme in many talks was the use of functional languages to prevent contention between threads. This totally makes sense to me, to the limited extent that I can wrap my head around truly functional programming, and I’m sure it’s an excellent approach. However, imagine a case in which we can’t just drop in a new language, so we need to write some multithreaded code in Ruby. I’m sure you won’t have to think too long or hard.
Now, one point several speakers at RubyConf made that I would like to reiterate is this: multithreaded programming is difficult. Gosh darn difficult. People who write software tend to thrive on determinism and linearity. After all, computers always do what we tell them to, right? They don’t make mistakes or change their minds; not like those silly, silly humans. But now big, bad concurrent programming comes along and suddenly computers can come up with different answers depending on, oh, the alignment of the planets. Chaos.
So, functional programming languages aside for the moment, what tools do we have to rein in the inevitable entropy that will, more than likely, eventually bring the planets into alignment against us?
Several years ago Andrei Alexandrescu wrote this excellent article on how to use the C++ type system (stick with me, it’s all Ruby after this paragraph) to automatically prevent race conditions at compile time. I recommend you read it; it’s quite short. Now, however you feel about static typing, you must admit that the approach he describes is a beautiful use of the expressiveness of the C++ type system. The question is, can we do something analogous in Ruby?
First off, lets start with some thread-unsafe code, similar to what Jim Weirich used in his talk on threads at RubyConf:
account = Account.new
threads = []
1000.times do |i|
threads << Thread.new(account) do |account|
account.credit(1)
end
end
threads.each { |thread| thread.join }
puts account.balance
This code results in an account balance somewhere between 1 and 1,000. The exact value depends, of course, on the planets.
Now, to make this thread-safe. I came up with a few attempts using #alias_method and #undef_method, but didn’t find anything satisfying. After that, I figured I’d try a simple proxy to approximate the effect. Here’s a first cut:
class VolatileProxy
attr_reader :obj
def initialize(obj)
@obj = obj
end
def method_missing(method, *args)
raise "Unsynchronized message '#{method}' sent to volatile object"
end
end
def volatile(obj)
VolatileProxy.new(obj)
end
def locked_scope(volatile, mutex)
mutex.synchronize do
yield(volatile.obj)
end
end
Now, calls to methods on objects you declare as volatile (shared across threads) will fail messily unless you use them within a locked_scope. To make this work the example code now becomes:
mutex = Mutex.new
account = volatile Account.new
threads = []
1000.times do |i|
threads << Thread.new do
locked_scope(account, mutex) { |safe_account| safe_account.credit(1) }
end
end
threads.each { |thread| thread.join }
puts account.balance
This example has some issues, namely:
- The final call to #balance will actually fail, since it’s not in a locked_scope; it would be nice to be able to declare individual functions as volatile without too verbose a syntax.
- It’s tempting to name the locked account object the same name as the unlocked account object, but doing so will cause them to overwrite one another (fixed in Ruby 1.9, of course, but until then…)
- The unlocked object is easily available. Given the opportunity to circumvent the lock, someone will do something horrible.
I really like the idea of using blocks to scope behavior like this. This particular example doesn’t feel particularly clean to me yet, but hopefully it will give some people something to think about. If you have a better approach, please don’t be afraid to shout it out.
Standup 11/14/2008: XXL Mongrels and Non-Model Reports
Interesting Things
- The iPhone SDK version 2.2 was released.
- An interesting Selenium Object Pattern was discussed.
Ask for Help
“How big should a typical mongrel be? Ours is starting out at over 200 megs but is not leaking from that point.”
Everyone agreed that 50MB to 70MB is standard and anything over 100MB is considered pretty big. People suggested RubyProf for inspecting object counts and possibly tracking down the memory hogging code.
“What pattern does everyone use for non-model Reports with ActiveRecord? We are trying to create a report that counts a single model and groups by two associated models”
There was consensus around modeling a distinct report object and calling the referenced models. For example, FooReport and FooReportController fit nicely in a RESTful Rails world.
Pattern for Functional Testing
Regular Selenium tests (in Java) might look like:
selenium.open("/login");
selenium.type("id=username", "bob");
selenium.type("id=password", "password");
selenium.click("Login");
selenium.waitForPageToLoad();
selenium.click("My Account");
selenium.waitForPageToLoad();
assertEquals("bob", selenium.getText("//table[2]/tr[3]/td[2]/");
After a few tests, this kind of thing becomes painful to manage. The typical solution is to create a bunch of constants for IDs and Xpaths, but that doesn’t help too much.
Fellow Pivot Mike Grafton came up with a cool pattern for improving on this. The idea is to create a class representing each page of your web app. Each class contains two types of methods: a bunch of action methods (clickMyAccountLink(), typeUsername()), and a bunch of inspection commands (isLoginButtonEnabled(), getLoggedInUsername()).
When an action takes you to a new page, the corresponding action method returns a new class representing that page. When it stays on the same page, the method just returns “this”. This allows methods to be chained to make the tests more readable.
Here’s how that test would look using this new pattern:
MyAccountPage myAccountPage = new LoginPage(selenium)
.typeUsername("bob")
.typePassword("password")
.clickLoginButton()
.clickMyAccountLink();
assertEquals("bob", myAccountPage.getLoggedInUsername());
The constructor of each page class should validate that it’s on the correct page (waiting if necessary, and perhaps asserting on the page title).
Standup 11/13/2008: ActiveScaffold and Object Mothers
Interesting Things
- ActiveScaffold was surprisingly easy to use for admin interfaces. One possible gotcha is that you have to manually configure namespaced RESTful routes (e.g.
map.resources :tasks, :active_scaffold => true).
Ask for Help
“What are your current favorite Object Mother implementations or patterns?”
There are several approaches:
- Factories-and-Workers
- Object Daddy
- Roll Your Own – Your Object Mother will likely be so domain specific that you should just write it from scratch.
“Does anyone know how to disable caching in Safari? Caching can often break JSUnit between test runs”
Go to Develop -> Disable Caches and you get a fresh non-caching Safari.
Pivotal Tracker Fluid Icon
Here’s a hot Fluid icon for Pivotal Tracker. Thanks, Ted!
![]()
Check out a couple of other icons in this Flickr upload.
Standup 11/12/2008: JSON2.js borked?
Interesting Things
JSON version 2 has problems with its JavaScript implementation json2.js, specifically when calling
JSON.stringify()on arrays:// JSON version 1 [1] => "[1]" // JSON version 2 [1] => ""[1]""We’re not sure if this is a bug or a feature. We’re sticking with JSON version 1 until further notice.
Pivot Adam has a very interesting blog post about functors called Give up the func. Check it out!
Ask for Help
“We were having problems when mocking an ActiveRecord association under Mocha when we called
expectson a method that calls a method.”
The solution was basically to not mock associations.
“Mod_rewrite + SSL was causing problems when redirecting to a subdomain behind SSL.”
A wild-card SSL certificate solves the problem.
Standup 11/11/2008: Firefoxen goodness
Interesting Things
- In response to our ask for help, Ray Baxter answered us in code with a script called Firefoxen. “It’s a script to automatically configure multiple installations of Firefox so that they open with different profiles.” You can grab Firefoxen on GitHub. Thanks Ray!
IE7 sends odd
Acceptheaders (*.*instead of an explicittext/html) which can cause undesired behavior in Rails. Someone suggested manually setting the format in abefore_filter:params[:format] ||= 'text/html'
This was discouraged because it can cause problems elsewhere. A better solution was to put the html format at the top of any `respond_to` blocks:
def show respond_to.html # run by default when type cannot be determined respond_to.js end
The Ruby MySQL Gem version 2.7 leaks memory for very large queries. The solution is to remove the 2.7 gem and manually install version 2.8 from source. This library is no longer a gem and must be installed from the mysql-ruby-2.8 tarball.
Ask for Help
“As a followup to Firefox SSL certificate problems…”
It turns out that our server running nginx had an old version of OpenSSL installed. Upgrading OpenSSL solved the problem.
Standup 11/10/2008: Memory profiling tools for Ruby
Interesting Things
- IntelliJ IDEA 8 was officially released over the weekend.
Ask for Help
“We’re having an issue with a long running Ruby process consuming too much memory and failing. What tools are available for finding and patching Ruby memory leaks?”
Several tools were suggested:
- Valgrind – Considered very powerful but difficult to use. “It will do what you want if you can figure out how to properly ask it to do so.”
- BleakHouse – Ruby specific leak detection. It’s available as a gem called “bleak_house”
- Leaks – This is native to OSX. The Google Web Toolkit uses this for leak detection.
- DTrace – Also a native OSX tool. There was a RailsConf presentation on Everyday DTrace on OSX.
“Rake will often silently ‘fail’ when running RSpec. It will not blow up but rather silently quits in the middle of the suite. This seems to happen intermittently, usually on the first run of our test suite. If we run the suite again, it works.”
It was suggested that this might be a Rake version issue since there have been other test suite problems with Rake 0.8.3. Though, this particular type of problem was not identical to previous Rake versioning issues and may be something altogether different.
Keep reading for a more detailed description of this weird RSpec + Rake issue.
More on the RSpec + Rake issue:
“It always manages to go through the integration tests, but when it hits the main tests, it will randomly quit (without a failure or error message) before all the tests are complete. At this point it’ll give us a summary message (X tests run, X tests passed) as if no other tests exist. We’ve worked on the problem a little bit this morning and tried the following things, all without success: >1) upgraded to the latest version of rspec and rspec-rails (1.1.11)
2) downgraded from rake 0.8.3 to 0.8.1
3) tried running with rspec and rspec-rails gems only
4) tried running with rspec and rspec-rails plugins only.We’ve tried it on another machine with similar results. Right now, I want to say it only happens when we’ve modified a file in the project, but that may be confirmation bias (we ran about 60 full rakes on one machine where we have not been mucking about in the codebase and it seems to have successfully run all of them).
There was one other mention of this online in this ticket: http://rspec.lighthouseapp.com/projects/5645/tickets/587-conflict-with-loadby-and-reverse#ticket-587-3, paraphrased below:
‘This was caused by an error in handling a certain mal-formed spec; it was causing rspec to exit silently in the middle of one spec file. As I would edit files, –loadby mtime would cause them to load in different orders, which would then run different #s of examples because it would hit the file, and then quit silently, in different places’
You can close this one, I’ll report another bug that’s appropriate for the silent-exit-without-exception problem.”
Anyways, at this point we’re out of ideas and are leaving the problem behind for now, but we’d love to fix it, as it makes testing somewhat unpredictable.”
Tracker: the iPod of project management software?
Nivi, from Venture Hacks, wrote a great article about why Pivotal Tracker is great for startups. It’s worth reading even if you’re already a fan of Tracker, and nails down the key ingredients to successful project management. Check it out: