Monday, July 30, 2007

This Blog Has Moved!

After more than a year on Blogger, I've bitten the bullet, bought myself a domain and installed WordPress. It's been good so far. Please update your feeds and links. Hope you like the new site and feel free to send me some feedback - the new site even has a contact form :-)

New Address
My blog is now to be found at:

http://jamescrisp.org


New Feeds
  • Full (http://jamescrisp.org/feed)
  • Technical (http://jamescrisp.org/category/technical/feed)
  • Personal (http://jamescrisp.org/category/personal/feed)

This Address
My previous posts will still be hosted on Blogger, but any new posts will be at the new address (http://jamescrisp.org).

Tuesday, July 24, 2007

Ultimate Laptop Protection




Better than money can buy.

Made by my dad :-)

Sunday, July 15, 2007

Monday, July 02, 2007

Adding a New Rails Project under Subversion

I generally use Subversion for source control when given the choice. In day to day usage, I like to use Tortoise SVN as it gives you a GUI with tick boxes for files to check in. However, it's handy to use the command line tool for project setup and automation.

Often, there is a subversion repository already set up and running on another machine. In this situation, I generally:
  1. Check out the repository at the top level into a temporary directory through Tortoise, add a new directory ([appname]) for the new project, and check it in.
  2. Generate the new rails app (rails [appname]).
  3. Check out [appname] from the repository into the local directory [appname] which contains the Rails project.
  4. Add and check in all files through Tortoise.
  5. Run the following commands from the command line to remove logs and tmp from the repository:

svn remove log/*
svn commit -m "removing all log files from subversion"
svn propset svn:ignore "*.log" log/
svn update log/
svn commit -m "Ignoring all files in /log/ ending in .log"
svn remove tmp/*
svn propset svn:ignore "*" tmp/
svn update tmp/
svn commit -m "Ignoring all files in /tmp/"

There's more Rails/Subversion info to be found on the Rails wiki.

Tuesday, June 12, 2007

The Castle Project - Rails for .NET

The Castle Project is an interesting open source alternative to ASP.NET / ADO.NET. Among other things, the Castle Project provides a Rails-like development framework for .NET. It has an ActiveRecord implementation built on top of NHibernate, a very Rails-like MVC setup called MonoRail, and uses NVelocity for template style views. It's worth checking out. This screencast gives a bit of an overview.

There's tough competition around the corner though, with Orcas already in beta, providing XAML, LINQ and O-R mapping.

Tuesday, June 05, 2007

Is .NET or Java dying?

Are C# and .NET losing ground as Martin Fowler suggests? Or is Java's market share dropping? What about Ruby? And what about the Australian market in particular?

Here's what I've been able to find.


Job Trends
Which technologies have the most demand for people?

From Indeed.com, which claims to search "millions of jobs from thousands of job sites", but I suspect may have a USA focus:




"Best Talent Index May 2007" from Best People Solutions gives an Australian perspective:



Here's job counts from the (largest?) primarily Australian job search site Seek on 5 June 2007, 3pm (today):
Keyword(s)Number of positions found
Java3,414
".NET" or "dot net"2,744
"c#" or "c sharp"1,722
ruby100

As an aside, I remember doing a search on Seek for "ruby" about 6 months ago, and getting under 20 jobs mentioning it.


Search Engine Number of Hits

Extract from the TIOBE Programming Community Index for June 2007:

Position
Jun 2007
Position
Jun 2006
Delta in PositionProgramming LanguageRatings
Jun 2007
Delta
Jun 2006
Status
1 1 Java 20.025% -1.10% A
2 2 C 15.967% -2.29% A
3 3 C++ 11.118% +0.45% A
4 4 (Visual) Basic 9.332% -0.85% A
5 5 PHP 8.871% -0.72% A
6 6 Perl 6.177% +0.17% A
7 8 C# 3.483% +0.25% A
8 7 Python 3.161% -0.30% A
9 10 JavaScript 2.616% +1.16% A
10 19 Ruby 2.132% +1.65% A



I think this gives a good idea of web buzz, but suggest that most non-IT companies do not publish information about their projects and chosen technologies and languages on the web.


Conclusion
The data collected suggests that:
  • Both .NET and Java are major players in the job market with thousands of positions advertised, implying wide industry adoption of both.
  • Neither .NET nor Java seem to be undergoing any significant decline in jobs.
  • Java has much more information about it on the internet, although .NET is slowing gaining ground and Java slowly losing it.
  • Ruby is comparatively tiny but growing rapidly in terms of jobs and information on the internet.


Thanks
Thanks to Jason Yip and Suzi Edwards for their help finding/sourcing information.

Sunday, May 20, 2007

Can you spot the bug?

In a model class which has 'quantity', 'quantity_already_taken' and 'quantity_requested' properties, I add the following:

def before_save
quantity = 1 if quantity == 0
if quantity + quantity_already_taken > quantity_requested
......

Tests blow up everywhere with:

TypeError: nil can't be coerced into Fixnum
(on the line with the addition)

Why?

After a little more debugging, it is clear that 'quantity' is nil. How could that happen?

The answer lies in the fact that Ruby requires an explicit self reference when using attribute writers (aka, property setters) within the class itself. This feels clunky to me, but for your information, here's a rationalisation of the explicit self requirement.

So, in case you're wondering, what happened above is that the 'if' line created a nil local variable called 'quantity'! This local variable then had higher scope precedence than the class attribute with the same name. The addition line was then using the local 'quantity' rather than the class attribute and hence failed with the nil error.

All fixed by explicity referencing self:

def before_save
self.quantity = 1 if (quantity == 0)
if quantity + quantity_already_taken > quantity_requested
......

Friday, May 18, 2007

Fixing a Palm Treo's Digitizer (Touch Screen)

Let me tell you a sad tale. One day, out of the blue, the digitizer on my palm started to drift. Every hour, it got worse. This meant that when you tried to click a button like 'Add' the Palm thought you clicked 'Delete' - no fun at all! It was possible to temporarily improve the situation by running the re-calibration program built into the system, but within a few hours, where you clicked again had very little relation to where the Palm thought you had clicked. After about a week, it was not possible to run the re-calibration program, as the digitizer was so far out (program just looped forever so I had to reboot the Palm). I discovered that there are actually keyboard shortcuts for just about everything, and that the 4-way nav button gets you most places, so the device wasn't a total write off. However, it was slow and cumbersome to use.

Now, one month later, I'm sure you'll be thrilled to know that things are better, the sorry tale has had a happy ending (touch wood!). Much googling led to many suggested approaches to fixing the problem including:
  • Various auto-calibration programs (AutoDigi, DigiFix, etc).
  • Running paper around the screen under the casing to remove gunk.
  • Cleaning the insides by putting a vacuum cleaner to all openings.
However, all of these approaches ended with disappointment and no noticeable improvement.

Finally, near buying myself a new device (aside: it is a shame that Palm has not managed to produce a device significantly better than my several year old Treo 600), I came across a site selling replacement Treo 600 digitizer/screen modules. They kindly provide a very useful movie on pulling your Treo apart to help you replace your digitizer/screen module. With little to lose, I decided to open up the case of my Treo and see if there was anything I could fix.

Following the instructions in the movie was not too difficult. I didn't have a small star alan key myself (required for opening the case), but I borrowed one from my dear dad, who has an amazing tool collection. Also, lacking a plastic case opening tool, I used a butter knife - this worked OK, but did damage the plastic of the case a little. If you have something made from thin and strong plastic, like the case opener in the movie, it would be a better tool for the job. I had a great time pulling everything apart and finally had all the components spread out before me. I cleaned the screen carefully (there was a fair bit of grot around the edges), fixed the buckled taping on the side of the screen, and put everything back together, carefully re-seating the various cables.

And now, almost a month later, the digitizer still seems to be working fine! Hurrah! So if you are contemplating what to do about your Palm's broken or drifting digitizer, I recommend pull it apart, clean it all and re-seat cables and then hope for the best!

Thursday, April 19, 2007

Experience of an International Amazon Virgin

Recently I ordered 12 books from Amazon. It was my first time.

The process started really well - quite easy and pleasant to find the books I was after. Not to mention that amazing range and the great option of getting cheaper second hand books. Adding to the shopping cart was also a breeze.

I was pretty impressed, good prices, nice process. But then the honeymoon was over. Time to check out - stream of consciousness. First, I need to enter address details. Fine, as expected. Then I get a message (from memory) "There is a slight problem with your order. Some of the books you have chosen cannot be shipped to your address. Change your delivery address or change the quantity to 0 on these books.". Not happy! One third of my books (second hand ones) cannot be sent. That means I need to cancel the check out process, remove 4 books from my cart and then try and find the same books from other more expensive suppliers which can be shipped international. So I try again, adding the same book from multiple suppliers to my cart, in the hope of finding one which can deliver to Australia. Then it's back to the checkout process again.. Problem - I missed one book and have to cancel the process and go back to basket process again. Great, all books are OK, finally time to complete the order. So I get to review my order, and it says at the top something like "With an Amazon credit card, this order would be $324 rather than $368". No other total including postage is provided. So is my order $368? Maybe? Further screens finally confirm that this is the case. Nowhere is it possible to see how much postage is per book - you have to work it out yourself doing best guesses and following the Amazon formula. Maybe it would have been better to get a new book rather than a second hand book, as second hand books have twice the postage charge.. ah well, too late now, I'm not going to go through the whole process yet another time! So finally I can check out and my credit card is charged. However, since my credit card is hit by a multitude of different vendors that use Amazon as a front, within seconds of each other, some transactions are rejected as my credit card does not allow too many transactions in too short a time (some sort of security feature?). Finally, after getting a few emails from Amazon saying the card could not be charged, and then telling Amazon to retry, my order is at last paid for and on the way.

Okay, so what could be done to make this better?
  1. Allow buyers to filter their results so they only see books that can be delivered to their addresses.
  2. Do not use patronising messages like "there is a slight problem".
  3. Do not suggest that people change their delivery address to another country.. that is clearly not going to happen!
  4. Show the cost of postage all throughout the process. Book buyers know they are going to have to pay postage and want to optimise their orders taking it into account.
  5. Do not show the order total including postage for the first time as a confusing advertisement ("With an Amazon credit card, this order would be $324 rather than $368"). Instead, provide a simple breakdown in a table, including postage on each book.
  6. Hit the credit card once per order, and divvy up the money at Amazon internally, rather than allowing each book vendor to do it and having credit card rejections as a result.
UPDATE: My books arrived about two weeks after I ordered them. Delivery was smooth and on time. Unfortunately, one of the CDs that came with a book was broken. Amazon has kindly agreed to replace it and the book.

Thursday, April 12, 2007

Tips for Developing Mephisto Plugins with Liquid and Rails

When I was writing a contact form plugin for Mephisto, I had a lot of trouble finding documentation and ended up reading lots of code and experimenting. That was fun, but fairly slow, so I hope this post can save future plugin developers time, and help them avoid some of the gotchas I stumbled over.

Repository Directory Structure
At the most macro level, your repository needs to have a 'plugins' directory, and then a directory named after your plugin. Eg,
.../plugins/my_new_plugin/...
If this is not set up correctly, your plugin will not be able to be installed via 'ruby script/install plugin ' method.

Liquid Plugins Directory and Init.rb
As you probably know, Mephisto uses Liquid for page templates. Liquid can be extended with new tags/blocks. The way to do this in a plugin is to set up a 'mephisto/liquid' directory with your extensions in it. See example here. So that's great, but you also need to register it in init.rb. Here's the contact form's init.rb - check out the line about 'register_tag'.

Mephisto Plugin Class
Mephisto trunk now has a base class for plugins - Mephisto::Plugin. Inheriting from this allows you to set up routes to brand new controllers you create. See contact form example here. This opens the door to writing Mephisto plugins which do postback and processing. It is also possible to add in tabs and forms in the administration interface. Rick's feedback plugin shows how to do this.

Using Liquid Templates from Your Plugin
One of the trickiest bits was getting the plug-in controller to render a liquid template. This is important if you want your additions to Mephisto to have the same layout and colours as the rest of the site. The way I'll outline below works fine, but it is not ideal. Hopefully there is a better way to do this (eg, some sort of Liquid API for Mephisto plugins).. if you know how a better way, please let me know!

I had my plugin controller inherit from the Mephisto ApplicationController to gain access to the method 'render_liquid_template_for'. You can see the code here. However, this led to thorny problems where the plug-in classes were getting loaded only once when the server started, but Mephisto (and the ApplicationController) were getting reloaded for every request. First request worked fine, but nasty errors were spat out on the second and subsequent requests. To resolve this, I removed the plug-in from the 'load_once_paths'. You can see how to do this in the init.rb.

Models, Views & Controllers Directories and Init.rb
Okay, this is open to personal taste. I like to have similar directories in my plugin to a normal app. Eg, separate directories for controllers, model, etc. This causes a bit more work, as you need to add the extra directories to various global path variables. For an example of how to do this, take a look at 'models_path' and 'controllers_path' in this init.rb and the physical directory structure of the contact form's lib directory.