Text

My Viva

Last week I sat a viva (defence) for my PhD thesis. Here are my experiences of the examination, in case they might be useful to future PhD students.

Submission

After I submitted my thesis, my PhD supervisors and the university began to make arrangements for the viva. My viva took place roughly 2 months after I submitted. My supervisors and examiners made all of the arrangements for the day of the viva, such as room bookings and organising travel.

Preparation

I wasn’t sure how best to prepare for the viva. I reread my thesis and highlighted key sentences so that I could quickly remember the crux of my arguments in the viva. The highlighted passages weren’t as useful as I’d anticipated (I barely referred to them in the viva) but this part of my preparation did give me a bit of extra confidence.

While rereading the thesis, I spotted a few issues: typos, missing references and other omissions. One of my supervisors suggested that I needn’t worry too much about this because my examiners were likely to overlook minor issues (which can be fixed with corrections) and also I was likely to read the thesis much more closely (as I was already familiar with the work and the story).

On reflection, rehearsing a short summary of the thesis research was probably the most useful preparation I did. Friends who had passed their viva had mentioned that my examiners would probably start with a question like “How would your thesis be summarised? What are the main contributions?”. Sure enough, this was the first question that I was asked and I was very glad to have already thought a little bit about how to answer.

Immediately before the viva, I went for a coffee with one of my supervisors and a friend, which was the perfect distraction. We talked about anything but the viva, and I felt very calm when my internal examiner arrived to whisk me away to the exam. I would definitely recommend nattering about something completely unrelated to the thesis before sitting the viva.

Examination

My viva lasted for roughly 2.5 hours; I think this is fairly typical from the few people who have told me about their viva. I was asked quite a range of questions, mostly about: the overall goals and outcomes of the research; the research method; the evaluation techniques and conclusions; and technical questions about the tools I’d built and processes that I’d suggested.

My examiners pushed me quite hard on a few issues. Specifically, these harder questions related to: the way in which tools I’d built compared with other similar tools; the validity/usefulness of a specific evaluation technique; and justification for the way in which I’d chosen a particular semantics for the transformation language that I had built.

Apart from the (entirely predictable) examination nerves, the whole experience wasn’t unpleasant. In particular, I felt that I could take plenty of time to think about a question and answer slowly (I didn’t feel rushed by my examiners), and that helped me to settle down.

A couple of times at the start of the viva, I started answering questions without referring to the relevant sections of the thesis, and I think this was the most obvious mistake I made. My external examiner asked “Where is this in the thesis?” once or twice, and from then I often started my answers by finding the relevant section, waiting for everyone to find that part of the thesis, and then pointing at figures or tables. If I was to sit the viva again, I definitely would have used this style of answer throughout.

The viva concluded with my internal examiner asking whether I felt that there was anything more that we needed to discuss. As the questions had touched most parts of the thesis, I didn’t feel that there was anything more. I left the room, and my examiners discussed the result.

Results

After a short wait (which felt like rather a long wait), I was given the results by my examiners. In my case, this was “minor corrections” and, for me at least, this will entail making some changes to the thesis which are signed off by the internal examiner. Then a final version of the thesis can be printed, bound and deposited.

Overall, I was very pleased (and relieved!) with the result, and I actually quite enjoyed the experience once I overcame the initial nerves. I hope that these notes might be useful. If you’re sitting your viva soon, good luck!

Text

JRebel for enhanced hot-swapping in Eclipse

I run a lot of Eclipse plugins from source in a developer workspace, and often use a runtime workspace for my day-to-day work. This allows me to develop and test plugins in a single Eclipse installation. However, whenever I want to make a change to a plugin that I’m using, I have to shutdown my runtime workspace, make the change in the developer workspace, and relaunch the runtime workspace. I do this many times a day, and the process can take 2-3 minutes on my machine.

JRebel is an Eclipse plugin that can automatically propagate changes from the developer workspace to runtime applications I’ve been using it with my developer workspace, and changes are almost immediately reflected in the runtime workspace. Unfortunately, JRebel isn’t free (licenses start at $59 USD for a year). However, you can get a free 30-day trial via the Eclipse marketplace:

Installing JRebel via the Eclipse marketplace

Once installed, JRebel adds a tab to support launch configuration types. Below, for example, I’ve enabled JRebel for my runtime workspace:

Configuring JRebel for a runtime Eclipse application

Viola! That’s all of the configuration that I needed.

I’ve not decided whether it’s quite worth the cost of a license ($59 USD per year), but so far I’m very impressed. I hope that similar functionality becomes part of Eclipse…

Text

Enhancing existing types in Objective-C

The types built into Objective-C and the Foundation Classes provide many useful methods, but I’ve found some functionality to be missing. NSString, for example, doesn’t provide methods that search for substrings, which is a task I often want to perform in iOS apps. Fortunately, it’s very easy to add extra methods to existing types in Objective-C.

For determining whether one string contains another, I might like to add the following two methods to NSString:

- (BOOL) containsString:(NSString *)aString;
- (BOOL) containsString:(NSString *)aString
           ignoringCase:(BOOL)flag;

I could subclass NSString, creating NSSearchableString which has the above methods, and use NSSearchableString throughout my program. However, whenever I wanted to search an NSString, I’d need to first convert it to an NSSearchableString.

Categories enable an alternative approach. When they were first introduced, categories were used to break the implementation of a class over several files. However, categories are also used to add methods to existing types. For the substring example, we can use a category to enhance NSString with the methods defined above:

#import <Foundation/Foundation.h>

@interface NSString (SearchingAdditions)
  - (BOOL) containsString:(NSString *)aString;
  - (BOOL) containsString:(NSString *)aString ignoringCase:(BOOL)flag;
@end

Notice that we’re defining methods for the NSString type, using a category called SearchingAdditions (specified in parentheses, after the type). Conventionally, this interface is stored in a file named NSString+SearchingAdditions.h

After providing an implementation for these methods, we can call them as we would any other method on NSString:

NSString *email = [display text];
if ([email containsString:@"."]) {
   // ...
}

In summary, categories provide a neat way of transparently adding methods to existing types in Objective-C. For the curious, an implementation of the containsString methods can be found here.

Text

Time Travelling with Git

Today, I was in the midst of changing some code when I discovered a bug. I wondered whether the current set of changes had introduced the bug or if it had been around longer than that. Fortunately, I’m using Git for this project, which has some really handy commands for time travelling…

First of all, I used stash to store away my current changes and revert to the last committed version of the code:

> git stash

I discovered that the bug was still present in the last commit; I must have introduced it in an earlier commit. To switch to earlier commits, I used:

> git checkout <commit_id>

Using git log to find the correct commit_id.

When I found the cause of the problem, I restored the latest version of the code:

> git checkout master

I fixed the problem in the latest version of the code, and committed.

Finally, I restored the changes I’d been working on originally, “unstashing” them:

> git stash pop

Best of all, Git automatically merged the changes and the bug fix.

Hasta la vista!

Photo Set

Some photos from the MoDELS 2010 conference in Oslo, Norway.

Text

Cucumber and Web Services in Rails 3

Today I wanted to write a cucumber feature to check that a RESTful resource could be created by posting XML to my app:

Scenario: Post an event
  When An event titled "First event" is posted via the API
  And  I go to the events page
  Then I should see "First event"

Defining the first step took quite a lot of work. I discovered, thanks to Patrick Ritchie’s answer on StackOverflow, that Cucumber step definitions can use ActionDispatch’s post method to post XML:

post("/controller/index", xml_result, {"Content-type" => "text/xml"})

But this didn’t work for me; the raw XML was passed to my controller as a String, and not a Hash. The logs indicated that the content type was not “application/xml” or “text/xml”, but “application/x-www-form-urlencoded.” After inspecting the implementation of ActionDispatch::Integration::RequestHelpers#post, I found that the content type should actually be specified like so:

post("/events", event.to_xml, {"CONTENT_TYPE" => "text/xml"})

Et viola! The feature passed. The complete step definition looks like this:

When /^An event titled "([^"]*)" is posted via the API$/ do |title|
  post_event Event.new(:title => title)
end

def post_event(event)
  response = post("/events", event.to_xml, {"CONTENT_TYPE" => "text/xml"})
  raise "Posting the event '#{event}' failed." unless response == 302
end
Text

Freezing time in Cucumber

Today I found that I needed to write some date-sensitive tests for a little Rails app I’m building. I’m using Cucumber to capture my features, and I wanted to say something like this:

Scenario: See yesterday's date on yesterday's tracker
  When I am on the tracker page for yesterday
  Then I should see "27 July 2010" 

Where “the tracker page for yesterday” maps to a path like: tracker?date=2010-07-28

Because today’s date is the 28th July 2010, this test will pass today, but never again after today. Clearly, a brittle test like the one above is no good.

I recalled reading about a similar problem in a Thoughbot blog post. Sure enough, in the comments Pat Maddox suggested a neat Cucumber step to solve this problem:

Given /^the date is "([^"]*)"$/ do |date_string|
  Timecop.freeze Chronic.parse("#{date_string} at noon")
end

The step uses Timecop to stub out Time.now and Chronic to parse a date string. (I tried using Date.parse rather than Chronic, but ran into timezone problems).

Update Jonas Nicklas, the author of Capybara, notes that, for Cucumber scenarios, Timecop.travel is preferred to Timecop.freeze. The latter breaks Capybara’s autowaiting feature, and causes it to hang when it can’t find something on the page. Therefore, the step definition should be written:

Given /^the date is "([^"]*)"$/ do |date_string|
  Timecop.travel Chronic.parse("#{date_string} at noon")
end

This step definition allowed me to rewrite the scenario as:

Scenario: See yesterday's date on yesterday's tracker
  Given the date is "28 July 2010"
  When I am on the tracker page for yesterday
  Then I should see "27 July 2010"

Et viola, no time bomb!

Update 2 As supaspoida highlighted in the comments, it’s also necessary to turn off Timecop after the scenario has been executed. This can be achieved with a Cucumber hook. Here’s the code I’m using in features/support/unfreeze_time.rb:

After do
  Timecop.return
end
Text

Installing RMagick on Ubuntu 9.04

I’m using Ubuntu 9.04 as my production environment, and I had some trouble installing the rmagick gem (via bundler). I received the following error message:

configure: error: Can't install RMagick.
  Can't find Magick-config in ...

I tried Googling the error and followed various instructions for installing imagemagick on Ubuntu, but none of them worked. In the end, I realised I hadn’t updated aptitude’s package list:

sudo aptitude update

After that, I could install the libraries required for RMagick with:

sudo aptitude install imagemagick libmagick9-dev

However, installing the RMagick gem led to another problem. The version of imagemagick installed by aptitude was too old for the RMagick gem. At this point, I decided to install imagemagick from source:

sudo aptitude remove imagemagick libmagick9-dev

mkdir ~/sources
cd ~/sources
wget ftp://ftp.imagemagick.org/pub/ImageMagick/ImageMagick.tar.gz

The I followed the instructions from the RMagick FAQ. In short, I ran the following:

tar xvzf ImageMagick.tar.gz
cd ImageMagick*

./configure --disable-static --with-modules --without-perl \
 --without-magick-plus-plus --with-quantum-depth=8 \
 --with-gs-font-dir=/usr/share/fonts/type1/gsfonts

make
sudo make install

sudo reboot

Now, I could install the RMagick gem via Bundler.

Text

RVM for multiple rubies

Last week, Apple released a Snow Leopard update containing a version of Ruby that had a fairly major bug in BigDecimal. I wanted to patch my OS, but not break ruby.

RVM to the rescue! RVM allows several versions of Ruby to be installed on the same machine. I followed the installation instructions here, and installed ruby 1.8.7:

rvm install 1.8.7

I set this to be my default ruby:

rvm --default 1.8.7 

And checked my config with:

rvm list

After a bit of confusion, I discovered that a key to using RVM is to never install a gem as root, as described on the RVM page for rubygems. Bundler interoperates well with RVM, so I intend to use Bundler to install gems from now on.

I’m using RVM and Bundler on my production server too, running Ruby Enterprise Edition and Passenger as per the instructions from the RVM website. I did find that installing REE via RVM took almost 2 hours on my VPS though.

Text

Upgrading to Rails 3 beta (part 2)

This is the second part of a series of posts detailing my experiences while upgrading to Rails 3. The first part covered migrated configuration and framework files to play nicely with the new Rails 3 APIs. Now, we’ll look at booting the server, fixing dependency issues and walking through our app.

Fixing authlogic

Once we’re confident that we’ve migrated files to conform to the Rails 3 APIs, it’s time to boot the server:

> rails server

Depending on the gems on which your app depends, this may fail. My simple app, for example, depends on authlogic, which caused the following exception:

authlogic-2.1.3/lib/authlogic/session/timeout.rb:26:in 
`included': undefined method `before_persisting' for
Authlogic::Session::Base:Class (NoMethodError)

A little googling revealed the answer via this excellent bugmash summary. It seems that authlogic registers a bunch of callbacks, one of which is the before_persisting method mentioned above. The mechanism for specifying callbacks has changed in Rails 3, and so we get the error above.

Fortunately, a patch has already been written for authlogic, although it’s not made it into a gem release. To get the patch, we could install authlogic as a plugin or even better, use Bundler to grab the patched authlogic directly from github.

Installing authlogic from source with Bundler

Bundler allows gems to be installed directly from their source code repository. That way, patched code can be used, which hasn’t yet made it into a gem version. To run the patched authlogic directly from github, I needed to add this line to my Gemfile:

gem 'authlogic', :git => 
  'http://github.com/binarylogic/authlogic.git'

And then updated my bundle, running the following command in my application’s directory:

> bundle install

In the comments, dansby recommends running a rails3 branch of a forked authlogic. I’ve not tried it, but you might want to consider the fork if you want to use the authlogic generators. Simply use the following line in your Gemfile instead:

gem "authlogic", :git => 
  "git://github.com/odorcicd/authlogic.git", :branch => "rails3"
Installing authlogic as a plugin

In the original version of this post, I didn’t know that Bundler could be used to run gems directly from source, and so I recommended installing the patched authlogic as a Rails plugin. I strongly recommend managing all of your application’s dependencies through Bundler, but if you prefer to use a plugin, here’s how:

> rails plugin install git://github.com/binarylogic/authlogic.git

When running authlogic as a plugin, we don’t want to depend on the gem anymore, so we go ahead and comment it out in our Gemfile. We can switch back to the gem, if we wish, when the patch makes it into a release.

Fixing initialisers

My simple app didn’t have any other dependencies that affected the server’s startup, but YMMV. Try googling around, or browsing the source of your dependency.

Now, we’ve fixed our dependencies, our server should boot, right?

> rails server
config/initializers/new_rails_defaults.rb:14:
undefined method `generate_best_match=' for
ActionDispatch::Routing:Module (NoMethodError)

Wrong! This error originates from an initialiser with a suspicious name, new_rails_defaults.rb. Sure enough, the comments in the file indicate that it should be deleted when Rails 3 is released. I went ahead and deleted the file, and then my server booted.

Fixing routes

With the server running, we should try visiting our site. Fire up a web browser and point it at localhost:3000. I was surprised to be presented with the default Rails welcome page. After a bit of pondering, I realised that the Rails generator had regenerated a public/index.html file. We can remove that.

Now, I discovered that none of the routes were being matched. It seems that the routes.rb generated by the version of rails_upgrade I was using doesn’t generate a valid routes.rb file. We must ensure that the first line in our routes.rb looks like:

SampleApp::Application.routes.draw do |map|

and not:

SampleApp::Application.routes do

Run through the app

With routing back on its feet, we can browse our app and make a note of any problems. I found a few issues, which I’ll quickly summarise.

It’s worth watching the output from the server process while browsing your app, as it does spit out fairly good deprecation warnings, such as:

DEPRECATION WARNING: Setting filter_parameter_logging
in ActionController is deprecated and has no longer effect,
please set 'config.filter_parameters' in
config/application.rb instead.

In my app, the following code from app/controllers/application_controller.rb:

filter_parameter_logging :password, :password_confirmation

became the following in config/application.rb

config.filter_parameters << :password << :password_confirmation

Note that filter_parameters is now an array, and we can chain « to append to it.

I found a couple of problems in my templates, which were relatively easy to fix. The most significant change I noticed was that code like this:

<% form_remote_for @object do |f| %>

becomes this:

<% form_for @object, :remote => true do |f| %>

On a related note, this now generates unobtrusive Javascript using HTML 5. We can change our application layout to use the HTML5 doctype:

<!DOCTYPE html>

Right, that’s it for now. I’ve still got a couple of issues to work out, which I may include in a third and final part. Thanks for reading; happy upgrading!