Saturday, 23 April 2011

Gotcha: NoMethodError: undefined method RuntimeError

So... I wrote some code in a plain-ruby class that raised a RuntimeError somewhat like below:

    class MyClass
      def initialize(opts = {})
         # do stuff
         thing = opts[:thing]
         raise RuntimeError "must have a thing!" unless thing.present? && thing.is_a?(Thing)
         # more stuff
      end
    end

and when I ran my fresh new rspec spec over it -> which looks somewhat like:

    it "should raise an error if we don't pass a thing" do
      lambda {
        my_class = MyClass.new(:thing => nil)
      }.should raise_exception(RuntimeError)
    end

I kept getting something weird:

    expected RuntimeError, got 
    #<NoMethodError: undefined method `RuntimeError' for #<MyClass:0xb5acbf9c>>

You may already have spotted the problem... ah, single-character bugs, doncha love em?

Here it is.

WRONG:

     raise RuntimeError "must have a thing!" unless thing.present? && thing.is_a?(Thing)

RIGHT:

     raise RuntimeError, "must have a thing!" unless thing.present? && thing.is_a?(Thing)

of course, you can also just go ahead and leave out the RuntimeError entirely:

     raise "must have a thing!" unless thing.present? && thing.is_a?(Thing)

because it's the default anyways... which makes it nice and defaultish for you.

Tuesday, 19 April 2011

RubyCAS - logged_in?

A logged_in? method is fairly common in rails authentication these days. We use it to determine if there *is* a logged-in user for layouts that are shared public and private - for example to use for greetings, login-only navigation features and displaying the correct login/logout buttons.

Once you've implemented CAS signup and a current_user method, you can use the very simple code below on your ApplicationHelper to get the logged_in? functionality

  def logged_in?
    @current_user.present?
  end

Some authentication applications (eg restful_auth) will use a call to logged_in? as an opportunity to actually try to log a user in... but RubyCAS is more complicated than a simple cookie-login... so I've left actual authentication just to the filter-mechanisms already described.

If you have templates where - if you *can* login a user, you'd like to... but you'd like them also to be available to non-logged in users, then you'll need a Gateway filter.

This is one article in a series on Rails single-sign-on with rubyCAS

Thursday, 14 April 2011

If a bricks-and-mortar shop were run like a web-deploy

"Hello, emergency response unit, what is your emergency please?"

"Yes, hello, I'm glad I *finally* got you... you have to do something immediately, it's an emergency"

"Yes sir, please tell me what is the nature of your emergency"

"Welll you see, I was in the middle of taking a customer's order, and they were trying to pay me the money, but then the till drawer got stuck and..."

"I'm sorry, sir, did you say the *till* got stuck?"

"Yes, that's right! The drawer got stuck and wouldn't open, and of course, you know, that means I can't take orders... so I called you and you have to fix it."

"I'm sorry sir, we don't really deal with this level of problem - perhaps if you called your building manager during normal work hours..."

"You fix things that are broken, yes? so fix it!"

"Yes, but you've called the emergency support line, not the..."

"What? I pay for this support service, I know you can fix it... just get it working, it's losing me business!"

" have you tried ringing up the sale first?"

...silence...

*taptaptap* *kerCHING!*

"Oh"

*click*

...later that day... after the building manager arrives

"No, no, I'm sorry but you're just going to have to destroy the entire store and start over.."

"I really don't think that's necessary, it's just a few design issues that we need to sort out..."

"Just a few design issues! This is a total branding failure. The display at the far right of the store isn't showing the products we asked for, this will completely ruin our business!"

"But... you're the ones that are supposed to set those products - we just filled it with some cardboard-cutouts so you'd get the idea of how to use it"

"I don't care - it's not what I expected! I expected it to work properly and it doesn't... I swear, I've been looking at sales, and they aren't as high as they should be and so it *must* be this display putting them off. There's nothing else that will do, you just have to destroy the new store and rebuild the old store for us!"

"What? We can't do that at this stage! Do you know how much work it'd be to tear down this new building and rebuild the old again? Are you going to pay for it?"

"Why should *I* pay for it? You messed up the display!"

Another day...

"That's it, close the doors, no customers are allowed in!"

"What's going on? why are you closing up?"

"It's a disaster! You see this picture here? it should be over there! and it's hanging askew!"

"Askew? I don't see it."

"Look at the other two pictures here... they line up with the edges of the cashier's desks exactly... but this one? Do you see why it's so wrong?"

*looks*

*looks some more... *

"I'm... really sorry, but I just don't se..."

"I don't believe it. See, does this help?"

*holding up a ruler*... "the third picture is *1cm* over the edge of the desk"

"Oh, I see it now. Yes - we should straighten that up for the next store-refit"

"Next refit!" *shocked look* "It's a disaster! We can't wait until the next refit! It's terribly unprofessional!"

"...but it's scheduled for tomorrow night, and it's not like it's impacting your cashflow..."

"not impacting... !!! ... It's *ruining* our brand-position! How could you have let something like this go out the door! Can't you get *anything* right? the entire design is ruined!!!"

*stunned look*

"OMG! *that's* we we aren't taking any orders, it's all your fault! we're losing business because of this! fix it now!"

...

Tuesday, 29 March 2011

Designing serious games - a request for help

I've been hanging out a lot on Less Wrong, which is a community for people trying learn about being more rational.

Some of us are also programmers... so we've decided to get together and have a hackday (in London). But we're still trying to figure out what would be both cool/interesting *and* help us build our rationality, *and* still be doable by an odd collection of random hackers over a single day.

One idea would be to have a go at designing serious games - games specifically created for improving our rationality, a bit like Lumosity builds games for improving mental agility.

But we need help coming up with ideas. Ideas that are not only small enough to fit into the time-schedule of a hackday... but that also demonstrably improve some aspect of our rationality.

If you have any ideas (or would be able to comment on those we've got), come over to our site and add our comments to the Designing serious games discussion.

Thanks

Saturday, 26 March 2011

Link: UX lessons from Angry Birds

Angry Birds is one of the most successful games out there right now - consuming millions of hours worldwide every day. What have they got right? This article tears down the user experience and explains Why Angry Birds is so successful and popular. It's a thorough and thought-provoking look into the sorts of things that make up a truly engaging user experience.

Wednesday, 23 March 2011

How to learn about everything

In How to understand everything and why, Eric Drexler (author of Engines of Creation), explains the importance of a broad education simply:

"It’s important... because it makes creative work more productive and makes costly blunders less likely... "To avoid blunders and absurdities, to recognize cross-disciplinary opportunities, and to make sense of new ideas, requires knowledge of at least the outlines of every field that might be relevant to the topics of interest."

he then follows with a brief discussion of how to go about learning everything - a method that seems straightforward, and even fun. Worth a read.

Thursday, 17 March 2011

Link: Assuming goodwill

Seth Godin's blog is packed full of great insights, but I thought I'd outline a recent one.

Assuming Goodwill is about the decision to trust, because trust pays.

It's one of those common-sense things that we often forget, that people will live up to your expectations. Expect the worst and that's what you'll get, but expect great things and you'll get the best. Seth talks about trust as it relates to, say, a restaurant trusting you to pay *after* you've eaten your meal... or Tiffany's trusting you to try on their expensive jewels... but obviously this has application to the full breadth of life.

For example, an employer trusting their employees to be productive and loyal builds an environment that is more conducive to productivity and loyalty, than one who micromanages productivity, or constructs labyrinthine rules about allowed corporate protocol.

Yep, sometimes your trust will be abused... life is like that. But sometimes you have to risk a little, to gain a lot.

Friday, 11 March 2011

Heads-up: new EU cookie laws

The laws are changing around cookies. From the 25th May, websites require explicit, opt-in consent for the use of certain cookies. It seems to be mainly (though not exclusively) aimed at targetted advertising, but it's worth having a read of a good overview of the upcoming cookie privacy laws to see if it will affect you.

Monday, 7 March 2011

Adding custom HTTP headers to soap4r request

When you're using soap4r, you don't have access to the bare httpclient - which means you have absolutely no way of passing in custom HTTP headers (note, not SOAP headers which definitely have an API).

Monkeypatch time!

See the patchfile below. You need to a) vendor soap4r (if you haven't already), then b) update several files with the given patch.

Then you can pass in your customised headers directly via the soap driver before you call the soap method. Here's an example of use:

driver = SOAP::RPC::Driver.new(url, SCHEMA)
driver.add_method 'MySoapMethod', 'MyParam'

driver.options["protocol.http_custom_headers"] = {'MySpecialHeader1' => 'abc', 'MySpecialHeader2' => 'xyz'}
driver.MySoapMethod 'MyValue'

and here's the necessary patches (note: they're in svn-diff style):

Index: vendor/gems/soap4r-1.5.8/lib/soap/rpc/proxy.rb
===================================================================
--- vendor/gems/soap4r-1.5.8/lib/soap/rpc/proxy.rb (revision 4217)
+++ vendor/gems/soap4r-1.5.8/lib/soap/rpc/proxy.rb (working copy)
@@ -32,6 +32,7 @@
   attr_accessor :allow_unqualified_element
   attr_accessor :default_encodingstyle
   attr_accessor :generate_explicit_type
+  attr_accessor :http_headers
   attr_accessor :use_default_namespace
   attr_accessor :return_response_as_xml
   attr_reader :headerhandler
@@ -57,6 +58,7 @@
     @allow_unqualified_element = true
     @default_encodingstyle = nil
     @generate_explicit_type = true
+    @http_headers = nil
     @use_default_namespace = false
     @return_response_as_xml = false
     @headerhandler = Header::HandlerSet.new
@@ -135,7 +137,9 @@
 
       :generate_explicit_type => @generate_explicit_type,
       :use_default_namespace =>
-        op_info.use_default_namespace || @use_default_namespace
+        op_info.use_default_namespace || @use_default_namespace,
+      :http_headers =>  @http_headers
+
     )
     resopt = create_encoding_opt(
       :envelopenamespace => @options["soap.envelope.responsenamespace"],
@@ -168,6 +172,9 @@
     end
     reqopt[:external_content] = nil
     conn_data = marshal(req_env, reqopt)
+    if reqopt[:http_headers].present?
+      conn_data.extheaders = reqopt[:http_headers]
+    end
     if ext = reqopt[:external_content]
       mime = MIMEMessage.new
       ext.each do |k, v|
@@ -299,6 +305,7 @@
     opt[:default_encodingstyle] = @default_encodingstyle
     opt[:allow_unqualified_element] = @allow_unqualified_element
     opt[:generate_explicit_type] = @generate_explicit_type
+    opt[:http_headers] = @http_headers
     opt[:no_indent] = @options["soap.envelope.no_indent"]
     opt[:use_numeric_character_reference] =
       @options["soap.envelope.use_numeric_character_reference"]
Index: vendor/gems/soap4r-1.5.8/lib/soap/rpc/driver.rb
===================================================================
--- vendor/gems/soap4r-1.5.8/lib/soap/rpc/driver.rb (revision 4217)
+++ vendor/gems/soap4r-1.5.8/lib/soap/rpc/driver.rb (working copy)
@@ -211,6 +211,9 @@
     opt.add_hook("protocol.generate_explicit_type") do |key, value|
       @proxy.generate_explicit_type = value
     end
+    opt.add_hook("protocol.http_custom_headers") do |key, value|
+      @proxy.http_headers = value
+    end
     opt.add_hook("protocol.use_default_namespace") do |key, value|
       @proxy.use_default_namespace = value
     end
Index: vendor/gems/soap4r-1.5.8/lib/soap/streamHandler.rb
===================================================================
--- vendor/gems/soap4r-1.5.8/lib/soap/streamHandler.rb (revision 4217)
+++ vendor/gems/soap4r-1.5.8/lib/soap/streamHandler.rb (working copy)
@@ -34,6 +34,8 @@
     attr_accessor :is_nocontent
     attr_accessor :soapaction
 
+    attr_accessor :extheaders
+
     def initialize(send_string = nil)
       @send_string = send_string
       @send_contenttype = nil
@@ -42,6 +44,7 @@
       @is_fault = false
       @is_nocontent = false
       @soapaction = nil
+      @extheaders = nil
     end
   end
 
@@ -230,6 +233,13 @@
     extheader['Content-Type'] = conn_data.send_contenttype
     extheader['SOAPAction'] = "\"#{ conn_data.soapaction }\""
     extheader['Accept-Encoding'] = 'gzip' if send_accept_encoding_gzip?
+    # allow us to pass in custom HTTP headers
+    if conn_data.extheaders.present?
+      conn_data.extheaders.each do |key, value|
+        extheader[key] = value
+      end
+    end
+
     send_string = conn_data.send_string
     @wiredump_dev << "Wire dump:\n\n" if @wiredump_dev
     begin

Wednesday, 2 March 2011

Gotcha: migrations with trailing commas

Trailing commas are bad m'kay?

I had a pretty standard migration, which included something like the following two lines:

    create_table :my_widgets do |t|
      t.string :name, :colour, :flavour
      t.integer :supplier_id
      t.integer :height, :width, :depth,    # note this extra comma...

      t.timestamps
    end

Looked fine at a casual glance, ran just fine - no hiccups. Been using it on dev for a week or so now... no problems... Only noticed an issue when I glanced at db/schema.rb

  create_table "service_report_stats", :force => true do |t|
    t.string   "name"
    t.string   "colour"
    t.string   "flavour"
    t.integer  "supplier_id"
    t.integer  "height"
    t.integer  "width"
    t.integer  "depth"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "#<ActiveRecord::ConnectionAdapters::TableDefinition:0xb5c35504>" # WTF???
  end

Something seriously wrong with that last "integer" column... mysql shows that yes, that is actually the column's real name:

+-----------------------------------------------------------------+----------+------+-----+---------+----------------+
| Field                                                           | Type     | Null | Key | Default | Extra          |
+-----------------------------------------------------------------+----------+------+-----+---------+----------------+
| id                                                              | int(11)  | NO   | PRI | NULL    | auto_increment |
| supplier_id                                                     | int(11)  | YES  |     | NULL    |                |
.... etc ...
| created_at                                                      | datetime | YES  |     | NULL    |                |
| updated_at                                                      | datetime | YES  |     | NULL    |                |
| #<ActiveRecord::ConnectionAdapters::TableDefinition:0xb5c35504> | int(11)  | YES  |     | NULL    |                |
+-----------------------------------------------------------------+----------+------+-----+---------+----------------+

Right now I have NFI how to actually remove the column... because trying:
alter table my_widgets drop column #<ActiveRecord::ConnectionAdapters::TableDefinition:0xb5c35504>;
Just results in: ERROR 1064 (42000): You have an error in your SQL syntax; , and it won't accept it if I put it in quotes either... so the column currently remains as is.

Luckily I was playing with a branch of the real system - so it's only my dev-box's code that has been mucked about... and I can change the migration before anybody else uses it... but this is seriously weird behaviour on Rails' part. Not a raised exception or even a raised eyebrow... it sailed right through and is continuing on regardless.

To actually fix it, I had to create a migration with the following:

    remove_column :my_widgets,  "#<ActiveRecord::ConnectionAdapters::TableDefinition:0xb5c35504>"

Seems the Rails itself can tell mysql about a weirdly-named column somehow. I'd still like to know the actual SQL involved...

Wednesday, 23 February 2011

Mere globs of gas...

Poets say science takes away from the beauty of stars -- mere globs of gas atoms. Nothing is "mere". I too can see stars on a desert night, and feel them. But do I see less or more? The vastness of the heavens stretches my imagination - stuck on this carousel my little eye can catch one-million-year-old light. A vast pattern -- of which I am a part -- perhaps my stuff was belched from some forgotten star, as one is belching there. Or see them with the greater eye of Palomar, rushing all apart from some common starting point when they were perhaps all together. What is the pattern, or the meaning, or the why? It does not do harm to the mystery to know a little about it. For far more marvelous is the truth than any artists of the past imagined! Why do the poets of the present not speak of it? What men are poets who can speak of Jupiter if he were like a man, but if he is an immense spinning sphere of methane and ammonia must be silent?

-- Richard Feynman

I'm reading The Feynman Lectures on Physics and had to stop and share this quote. It's so perfect.

Saturday, 19 February 2011

Make it easy to be good

I'm trying to be good these days and eat a healthier diet. But doing it "the hard way" is just as difficult as going cold turkey. So I've been trying to find ways that actually make it easy to eat a healthy diet.

One way I'm doing this is through Riverford farm[1] - they deliver a box of fresh fruit and veg to your door once a week (or once a fortnight) for the same price (and much better quality) that you get in the supermarket.

I find that cooking then becomes a surprise instead of a drag. It makes eating your vegies a little bit fun. "What am I going to cook today? Lets see, what do we have here in box number 1?" :)

Something as simple as this helps with inspiration - which is often the only kick-start you really need. But I don't underestimate the "it's delivered to your door" aspect... No fuss, no muss. It really helps make it easy to be good.

On a similar vein, I also get myself graze.com[2] boxes twice a week. They send out a box full of delicious nibbles, randomly chosen from items that you've already rated as something that you've liked. It's novel, it's fun, it's generally pretty healthy. It's enough to eat for lunch and much better than the local greasy-spoon. ...but I don't do it every day, so I don't feel like I'm starving myself or denying myself all of life's pleasures. They also taste delicious. So it doesn't feel like I'm doing any stringent dieting.

Again - just making it easy to do yourself a little good.

How does this apply to programming?

Well, there are heaps of things we *ought* to be doing. Testing, code reviews, refactoring... But somehow it often seems like this stuff just never gets done.

In these cases, it really helps to make it easy to be good.

In my case, I've picked a language and framework where testing is assumed to be done as the default case. It's really easy to do proper testing in Rails. More than that - you're looked-at funny if you don't... like you're actually doing it wrong. So tests, in Rails, tend o get written more often than in other languages (where you often have a hard time justifying to people why you've got to write them).

Once you have tests in place, it's really easy to refactor - because you can do it, knowing that you have a comprehensive test suite to catch you if you break something - gives you the confidence to get it done.

and code reviews? well - if you've been regularly refactoring, then you won't be as ashamed to show off your code to other developers... because it won't be a horrible, hard-to-grok mess... and that makes it much less likely that the code reviews will be put off due to it being "too hard"

Each little step makes it easier and easier to be "good", which makes it far more likely to actually *happen*.


Notes:

[1] Riverford farm only deliver to the UK - but I strongly recommend them - I've been eating their small fruit+veg box once a fortnight (which is enough for just me), and they're always fresh and yummy.
[2]graze.com The graze link is an affiliate link - it will give you a free box so you can try it out yourself. Normally they're around £2.99 each. They ask for a CC to register - but it's easy enough to cancel.

Friday, 11 February 2011

Blind spots

Some people like to hang dingly-dangly things from their car-mirrors.

I always thought it was a bad idea, and it took a little reflection to figure out why.

If you get used to seeing something swaying back and forth in a certain sector of your vision, eventually you learn to ignore movement in that sector. This means that if/when the Bad Thing happens - and suddenly there's an accident happening right in that spot... it takes longer for you to recognise, and react to that accident, because you've learned to ignore stuff happening there.

Well - I was thinking recently about things that were less obvious. Things that I'd put somewhere in my life for amusement value - or even for a good purpose... but which are also serving as a blind-spot. As a place where I "should ignore what's going on".

One of those spots (for me), is in "standing up for myself".

You see, I'm a geek... but more than that, I'm a geek *girl*. I engage in activities that are traditionally considered the province of males... and I get funny looks for doing so. Not from everybody, but enough that I've had to continually resist assumptions (and even outright contempt) all my life.

For years, I've had to work *very* hard to stand up to people that treat me like some kind of weirdo for actually having an interest in things like science, maths, science fiction, martial arts, role-playing games... the list goes on.

I treat any criticism of my choice to pursue these interests as an infringement of my individual rights... and rightly so. It's my business whether I enjoy these things or not. Your opinion does *not* count.

But I've come to notice that it does lend me to have formed a particular blindspot. It's the "don't infringe on the way I do things" blindspot.

I find I'm quicker to resist, to stand up and fight-back, to take offense at people that try to press the boundaries of "the way I do things".

Needless to say, this heuristic can sometimes be misapplied.

After all, I am not perfect, and the way I do things can very well be stupid, wrong or otherwise detrimental to the health and happiness of other people.

But when I'm "called" on it - I currently still have to fight the impulse to fight back. To resist because "I have the right to do my things my way"... and sometimes I lose that internal fight.

So - if I've ever done that to you - my apologies. I'll try to do better next time.

Sunday, 6 February 2011

gotcha: Unpacked gem in vendor/gems has no specification file.

Ok, this one had me stumped for a little while. When I was running rake, I'd get these warnings:

  config.gem: Unpacked gem difftmp in vendor/gems has no specification file. Run 'rake gems:refresh_specs' to fix this.
  config.gem: Unpacked gem difftmp in vendor/gems not in a versioned directory. Giving up.

I'd seen this one before - when I'd thoughtlessly unpacked a gem into vendor/gems, then patched it. But for some reason rails doesn't like it when you unpack gems without using rake gems:unpack. I've never been in the habit of using that, because I didn't want to unpack everything. Later, of course I discovered that you can pass "GEM=blah" and it'll only unpack a single gem... but I thought I had done I this time around...

So I blindly followed the instructions to run rake gems:refresh_specs

However, that then spewed on me with an equally-familiar exception message:

rake aborted!
undefined method `installed_source_index' for #<Gem::SourceIndex:0xb76aa218>
... much stacktrace garbage follows...

I sighed deeply and googled the exception... to get the usual suspects, which suggest that I need to refresh the specification file. So I went back to the original error message to see which actual gem was causing the problem.

... then stopped.

You see it became pretty clear that I'd never actually *read* the original error message. "difftmp" is obviously a temporary diff-file showing me the patch I'd made on one of the gems. Now, you could argue that rake shouldn't be stupid and assume that a flat text file is a gem (requiring a specification)... but it was then also quite clear what to do to fix the "bug".

rm vendor/gems/difftmp

Problem solved

Friday, 4 February 2011

assert_difference for any value

I like assert_difference. It does exactly what it says on the tin - and in a nice, rubyish way.

However, I noticed that you can't assert a difference in something that isn't numeric. You can assert that creating a Customer will change the Customer.count, but you can't assert that updating the customers name will actually change the customer's name. Or, conversely, that updating a customer's name with *bad* data *doesn't* change the customer's name.

In my mind, it shouldn't really matter if the thing doing the changing is an int or a string or some complicated object. If the changing-thing responds to "==", you should be able to check if it changed. As long as you don't actually care what the exact change is that occurred - just whether or not a change *has* occurred.

So I wrote one that did.

assert_any_difference/assert_not_any_difference

Example tests. Note that you can pass a whole array of tests. These should nest, just like assert_difference

    should "not change anything if the account is active" do
      @cr = customer_records(:active)
      assert_not_any_difference ['@cr.customer_number', '@cr.is_active'] do
        assert @cr.register!
      end
    end
    should "update active status if registering a non active customer" do
      @cr = customer_records(:in_active)
      assert_not_any_difference ['@cr.customer_number'] do
        assert_any_difference ['@cr.is_active'] do
          assert @cr.register!
        end
      end
      assert @cr.active?
    end

And the assertions. You'll need to add these to test_helper.rb

  def assert_any_difference(items, &block)
    actual_diff(false, items, &block)
  end
  def assert_not_any_difference(items, &block)
    actual_diff(true, items, &block)
  end

  def actual_diff(test_if_equal, items)
    # save the old values
    old_vals = {}
    items.each {|item| old_vals[item] = eval(item) }
    # run the block
    yield
    test_fn = test_if_equal ? :assert_equal : :assert_not_equal
    # check each one
    items.each do |item|
      new_val = eval(item)
      send(test_fn, old_vals[item], new_val, "should #{'not' if test_if_equal} have been a difference for #{item}, but had: #{new_val}")
    end
  end

Wednesday, 19 January 2011

Rails namespacing test gotchas

We have some controllers that are namespaced as Admin controllers eg: Admin::ProductController.

...and this is a legacy system, and never had any functional tests created for those...

So I was trying to get started on adding some functional tests. I created a test/functional/admin folder, then added a product_controller_test.rb under that, with the usual:

class ProductController < ActionController::TestCase

At first, the tests wouldn't even load properly, and I was getting the following error:

uninitialized constant ActionController (NameError)

That, apparently, is solved by explicitly putting:

require 'test_helper'

at the top of the file. After which it loads fine, and the null-test runs. but after that, I kept getting the following error:

RuntimeError: @controller is nil: make sure you set it in your test's setup method

It seems that you need to namespace your tests too, so instead of the class declaration I have above, you need:

class Admin::ProductController < ActionController::TestCase

The admin folder isn't enough.

Sunday, 16 January 2011

Link: Building mazes with Ruby

JamisBuck has started writing a whole bunch of posts on techniques for maze generation, with examples in Ruby.

It's a fascinating read, and I love the little javascript visualiser for the technique (pretty!).

His idea is that maze-building algorithms are a great way to learn a new language - small projects, but fascinating. I agree.

Friday, 14 January 2011

Bosses prefer overconfidence to accuracy

Well, this should come as no surprise, but it's confirmed that bosses prefer overconfidence to accuracy when asked for estimations.

I've spoken before about how I personally prefer Truth over Harmony, with estimation as a prime example. Mainly because, when it turns out that an estimate was inaccurate... you know who's going to get the blame for "coming in late".

And yet I've found in the past that if I try for accuracy, the truth is taken as "pessimism" (by comparison with the overconfident, optimistic estimates given by others).

What I found particularly scary (and accurate) was the final quote of the article:

"Thus bosses of software managers take accurate estimates to be a signal of a lack of competence."

This is not how the world should work :(

Friday, 7 January 2011

Seven signs your company is really a cult

I just read this article on signs you might be in a cult and Eliezer Yudkowsky's article on cultish countercultishness (where he discusses the cultishness of all groups of humans, and a few theories on how to fight against it happening) and realised that most of the places I *didn't* like to work in - displayed strong cultish tendencies.

Here's a list of the common tendencies I noticed in companies I didn't like working for:

1 - Hierarchical authoritative structure

While hierarchy is inherent in almost all businesses, it was particularly strong in the ones I didn't like working for. What got me was the fact that these companies *stressed the importance* of the hierarchy - ie, the higher up you were, the more important you are and the more you should be faithfully obeyed, rather than, say, the more responsibility you were taking onto your shoulders.

I follow the spider-man principle that "with great power, comes great responsibility"... rather than "with great power comes greater ability to boss everybody else around".

Of course, exaggerated hierarchy goes hand-in-hand with "exaggerated adoration of the respected leaders" (one of the cultish-signs in the articles).

I find this especially the case in companies with strongly charismatic CEOs (or even just one or two managers). Especially so if they can name-drop other big names of the business world they've worked with/for (whether human or corporate)

When you start feeling that you cannot criticise anything that the CEO/manager says simply *because* he's your manager/CEO - then something is rotten in the state of Denmark.

Nothing is absolute - even the perfection of "our great leader". Everybody has faults, and everybody has the potential to learn, yea even from the mouths of babes. So when people are literally told off for having the gall to question "orders from above", you've got something fishy going on.

Sometimes, this idea can affect the whole company:

2 - Absolutism about the company

Either you adore the place with tears-of-joy staining your face, or else you're suspect, "not a team player".

How do you expect the company to improve if you start from a position where everybody must repeat the mantra "the company is perfect and can do no wrong"?

Unfortunately, I've seen this particular problem run hand-in-hand with the next one:

3 - Total immersion

Absolutism can be taken to a personal extreme when you get the sense that you are being told that you are a better person, the more you do for the company. If you spend all your waking hours at work - it shows how virtuous you are, how much of a "team player"... conversely, if you show yourself to be less than ecstatic at a chance to work unpaid overtime, then you must be "not a team player", and thus are suspected of being against the company (somehow)... rather than just, say "a normal person who likes their homelife".

4 - In-groups vs out-groups

AKA "group members encouraged to distrust outside criticism as having hidden motives"

While all companies will of course have in-groups (ie members of the company) vs out-groups... some companies go on to demonise those in the out-groups. I've noticed two obvious groupings that fit in this category:

4a - The inter-company version

"We're much better than *that* company - our competitor over there... everyone there is evil... I mean, they create poor quality products, are trying to take our profits away from us, and are bad for business. They are out to get us! We must beat them and laugh in their faces!"

IMO it is not necessary to demonise your competitors to deal with them. They are just trying to get along in the world, just like "our" company - so they are quite deserving of being treated with the same respect that we'd like to be treated. For example, one should not take every opportunity to take advantage of them. It is certainly not necessary to revel in (or even to actively bring about) their destruction.

4b - The intra-company version

See also: "absolutism about the company" and "total immersion". Especially the use of derogatory phrases for out-groups such as "not a team player".

I've worked in companies where people that resign (even on good terms) are considered to be traitors. Yes, literally traitors, as though you are betraying the trust invested in you by the company. Sometimes they are treated as having taken advantage of the company for money (as though the company did not receive equal value for said money). If you're still working in that company, you're no longer allowed to associate with the "traitors" without also being tainted by the brush of distrust.

Clearly this is pathological behaviour.

In my opinion, healthy companies respect the fact that you are a person first, and a company-member second. People leave companies for reasons other than "betrayal" - and that should be respected, in the same way that an amicable split-up can occur.

Some (good) companies even go on to actually care about what happens to you *after* you leave the company - for example, the well-known google alumni program.

Still, the cultish companies tend to view this as a thought-stopper. If you leave the company, you are now part of the out-group and, by definition, evil. You are simply not allowed to think about it in any other way, or else you are also suspected of being part of the out-group.

Other ways of thought-stopping are inherent in:

5 - Thought-terminating cliches

Some companies are full of these. There are many things that you are *not* allowed to think. Taboos that you shouldn't break or be stigmatised, and they are often hidden behind a cliche that is intended to stop thought in the matter.

The best (general) case I can give is that of "the way things are done here". If this is uttered by anybody at your company, it is intended as a way to stop you from continuing the discussion. It's a big, flashing sign that says "Just don't go there". Trying to show the limitations of such taboo areas just puts you under suspicion.

IMO this is not a healthy attitude towards your company. If you have things that "are just the way we do things here"... then the question naturally arises as to *why*, and whether or not there might actually be a better way. Sure, we shouldn't needlessly poke holes in everything for the sake of it, but somebody asking why things are the way they are isn't trying to tear everything down.

It's also perfectly reasonable to answer the question with "well, it's not optimal, but the time it'd take to change it would outweigh the benefits gained".

That would be an honest answer, and would actually answer the question, instead of "Just don't ask alright?"

6 - Isolation from people not in the in-group

Not as common, but some companies try to keep everything in-house. I've found that the more cultish companies are more likely to look at you strangely if you decide to take lunch outside (you know, with regular people, instead of just with your team-mates every single day of every week...).

I find that this one tends to lead on from strong inter-company in-groupishness. ie, if you view all outsiders as suspect... then anybody that associates with outsiders must also be suspect.

It's also related to the "total immersion" idea. If you truly are a "team player", then surely you want to spend all your waking hours at your beloved company, rather than going out and having a break.

7 - All forms of individuality must be de-emphasized

This is more about the fact that individualism is actively quelled. If you're in a company where the only individual expression you are allowed is in what photo to sit on your desk, and what the trite saying is on your coffee-mug... then you're in trouble.

Cubicles, rules about personal items and the wearing of business-attire certainly all contribute to quelling individuality, but even if these are not present, individuality may be de-emphasised in purely psychological ways.

There are even interesting-but-weird cultural forms of this effect where you are expected to share the passions of your colleagues regardless of whether you, say, don't actually enjoy watching sporting events in favour of reading physics textbooks... or prefer to spend your lunchtime reading rather than discussing said sporting-games (or hairstyles and office gossip, in the case of one set of women I worked with).

It's ok to invite team-members to join into these activities. It's *not* ok to treat people as pariahs if they choose not to participate.

I've even had one company tell me off at my annual review because I wanted to abstain from the company "tipping competition"... regardless of the fact that I have no clue about the sport in question (I was advised to choose randomly... and that <the secretary> had found this strategy very effective to win.)

The most insidious individuality-repression I've found is with excessive worship of groupthink. Where you are expected to agree with all the decisions of your colleagues - and dissuaded from (or actively told off for) finding flaws in "the plan". This especially occurs in conjunction with leader-adoration.

I've spoken about the pitfalls of this in The two faces of optimism.

But it's all just a game isn't it?

Now, I recognise that even in the companies that inculcate these tendencies, the actual people involved (at least at the lower levels) realise that it's all kind of a game... That you don't have to actually *believe* any of this bullshit - just to play along and pretend, in order to "win".

but my response is: why do we have to pretend?

Surely it'd be healthier (for all of us) if we just admit that it's all bullshit and get on with actually enjoying our life?

Especially when a lot of the things we have to pretend actively work against you.

I do not want to pretend that I love unpaid overtime - because I actually hate it - as do most people in the vast majority of jobs that exist in this world.

I really do have better things to do than marching up and down the square... and I think that everyone can actually come up with something or other they'd rather be doing with their life. So why go through the charade? Why force me to lie to you about it? What does that gain?

There are actually companies that don't.

They are unfortunately few and far between... but they do exist.

I've noticed that smaller companies are actually far less prone to cultishness. Perhaps because there are so few people that everyone's more accountable, perhaps because they're too new to have an ingrained cultish culture... I don't know.

There are also companies who have purposely adopted a culture that leads to a good work-life balance.

I do like Eliezer's Cultish countercultishness post because it gives a good overview of the problem (with reference to his particular group), with the final moral being that almost all groups have a tendency to cultishness... that you have to actively work against these natural tendencies to make sure you don't fall into the trap.

So, in short, if you're in a company that is not cultish - my advice it to work hard to make sure it stays that way.

If you find that you are in a company that is irreparably becoming a cult... look elsewhere.

Saturday, 1 January 2011

Link: How to ask a blogger for backlinks

An excellent new post on kissmetrics about How to ask a blogger for backlinks and reviews.

It gives some great tips about how to be professional and non-spammy, and stands in stark contrast to my own recent experience.

...and no, they didn't ask me to write this :)

Thursday, 30 December 2010

Simple private messaging

Ran across this plugin the other day. It gives you very simple, private messaging for Users on your app.

Needs some fiddling to make the messaging private - otherwise anybody can read anybody else's message... but otherwise, pretty neat. It basically does most of the heavy-lifting for you, and lets you get on with the customisation... which is the point of using other people's plugins.

Friday, 24 December 2010

Gotcha: db index name must be a string

Might just be Rails 2.3.8 - an exception is thrown whenever I use a symbol for an index name. I get:

rake aborted!
An error has occurred, all later migrations canceled:
undefined method `length' for :my_index_name

The code causing this would be something like:

add_index :widgets, [:colour, :weight], :name => :index_by_colour_weight

it’s solved by just using a string instead:

add_index :widgets, [:colour, :weight], :name => 'index_by_colour_weight'

Sunday, 19 December 2010

Dosbox and old games

So... my favourite game of all-time is still X-Com: terror the deep. I've been playing it off-and-on now since it first came out 15 years ago.

It is a game with extraordinarily long game-play time. Come to think of it, I think I still haven't actually completed a game yet... it takes months of gameplay to complete... but it's still fun enough that I like to play it anyway.

Now, the thing is, it's a really old game now - it's a DOS game that was able to be played on the then-new Win95... but it hasn't transferred well up the line. I've had to keep around an old laptop for the precise (and only) purpose of playing this game.

For obvious reasons (including the bulk of said ancient laptop), I did not bring that laptop with me to the UK. Which means that I've been deprived of my favourite game for some time.

Lately, however, I learned of Dosbox - which I can now rightly praise as an awesome DOS emulator that actually works on Linux (as well as other, lesser O/Ss). ;)

I had some issues with getting the game to play and save - before realising that I hadn't properly "installed" the game before trying to play it straight of the CD - and thus it didn't have write-privileges, causing it to fail to save a game... or to write the sound-file etc.

but after I figured that out - it's worked just fine. Awesome!

Monday, 13 December 2010

The perils of pagerank

Now that RubyGlasses has gained a bit of PageRank, I've noticed a marked increase in the amount of people emailing me requesting "Link swapping".

I've generally been deleting these along with most of the spam... google doesn't like linkswapping, and I won't do it. (all hail oh mighty google!)

However, I've also received one or two offers of advertising... and, to me, that's different. I'm happy for an advertiser to pay me to put ads on my site that are relevant to my audience.

However, after a recent email-conversation, I now have to make it clear to potential advertisers that these ads are going to be obviously ads.

I will freely confess that I don't get very many offers of advertising. I've had two so far... one that I've accepted (see if you can spot them) and one that I have most definitely not.

The first did want me to *not* use certain ad-like keywords in proximity to their ads... no doubt they're after a bit of my pagerank "link juice" as well as the actual click-throughs that are likely to accrue (yes, I actually asked them about this). That was ok to me, as long as it was obvious to my readers that what was going on was actually an ad... ie paid-for content inviting people to purchase something.

The reason I turned down the second offer, however... was different. In fact, I didn't even need to turn them down - just stated what I was and was not going to do.

The second exchange began with an offer to "have cooperation in marketing". I'll admit that maybe I didn't completely read the email in question because it also explained that they expected me to "add our product information with links to < thecompany > on your blog"... I read this and thought "advertising"... but in the following exchange (I asked if that's what she meant), discovered that she expected to write articles about her products... and put them on this blog.

After explaining that I write my own articles she responded with (and I paraphrase) "Oh ok, so *you'll* write articles about our products on your site, and put links to our products"

I had to then explain that I write articles about Ruby-on-Rails or web-development or freelancing... if her products were relevant to that then I might write an article on them... but I would *not* promise to be favourable.

She then responded with a "suggestion":

I have read your email, I have one suggestion, how about we write articles suitable for your site, and you put it on your site. We can also pay for you on adding them, but how much per article will you charge?

I mean, what does it take to get through to these people? My final email to her reminded her that I write my own articles, and that I will happily post paid advertising at the bottom of my articles - and that she could even dictate the text of the advertising... but that I would not post fake articles written by somebody else about her products.

She said she'd stay in touch...

Saturday, 11 December 2010

NaNoWriteOff

*sigh* I admit defeat.

Though I've "won" three years in a row, this year, I quit after a week... it's kinda sad, but I felt it was a necessary decision.

After a week of the usual noveling, I realised I had so many other commitments this year that one more was really piling on the stress a bit too thick. I weighed up whether or not I needed to complete this one time - and decided I didn't need to prove to myself that I *could* finish a novel as I've done it three times already.

So, for the first time since I discovered the wondrous new world of NaNoWriMo, I failed to finish.

I'm sad about it because this year I actually had a full plot. Most years I just began with an idea and a few characters... It was a Romance (I try a new genre every year) - which lent itself to easy plotting... but I realised a week in, that I just wasn't satisfied with that, and had already begun to add action/adventure elements (the hero was captured by desert pirates... leading to a chase...).

In any case - it'll be there, waiting for me in January - when hopefully I'll dig up a bit more spare time.

Wednesday, 8 December 2010

Less Wrong: the art and practise of Rationality... and Harry Potter

I just found an amazing website that basically constitutes a broad exploration (with much discussion) on the art of "being less wrong".

What's interesting is that I happened upon it because my sister pointed out to me the most interesting Fanfic I've ever read: Harry Potter and the Methods of Rationality.

I don't read fanfic, as a general rule... it's usually just somebody's personal fantasies, and almost never as good as the original fiction.

But this one had me hooked from chapter one. It seems to constitute a kind of course-by-example into the Art of Rationality. No doubt more poignant if you've actually read the original, but fascinating none-the-less. Try it and see for yourself.

If you're not into fanfic at all - then feel free to cut to the chase - skip it and go straight to the Less Wrong wiki.

All this stuff is brought to you by the Singularity Institute which is dedicated to making sure that the predicted technological singularity is Friendly, rather than unfriendly, towards us mere mortals. Less Wrong was created in order to build a community of rationalists that would be able to improve the world in general (including, but not limited to the singularity). The soundbite mission statement being raising the sanity waterline

Thursday, 2 December 2010

I'm not a militant feminist

I assume non-gender bias at the start; I don't care what pronouns you use, and most of those "war of the sexes" ads are just plain funny.

Which is why I was totally surprised by an ad I saw today which suddenly made my "feminism" detector spike off the charts.

I can't find a pic of it online, so I'll have to describe it.

It's for some kind of smartphone.

A smug-looking geek-boy is standing there, with a gorgeous-looking girl with her arm wrapped around him.

The caption: "It's about how smart you are".

...

In case I need to state the obvious - clearly, being totally smart means that if you're a smart guy you get the hot-looking bird... but what makes him look smug is just as clearly *not* about how smart she is.


Disclaimer...

I like geek-boys, and for me it *is* more about how smart they are... but I'd hope that for the geek-boys it'd be about how smart *I* am too!


On further reflection, I think I'd be almost as scandalised if the ad showed a smug geek-girl with an Adonis draped over her.

What mostly annoys me is that it implies that the main benefit of being smart is to be able to entice the beautiful people to hang with you despite how plain-looking you are. In other words - even though it says it's about how smart you are... it's still about how pretty you are... :P

Tuesday, 30 November 2010

Gotcha: heroku with git+svn pushes your working copy

For the MatchFounders website, I've been working with svn on Heroku using git just as a deployment tool... and I came across a bit of a gotcha the other day.

git commit will add your *working copy* to your next deployment.

Luckily it didn't turn out too badly for us - I was just mucking about with some pagination links... and quickly fixed the bug I'd been working on before deploying again... but if I'd been right in the middle of some big hairy code refactor, or something... I'd have had to go find heroku's docs on rollbacks pretty darn quick.

So - just be aware that if you use this method, to add a step to your process-control to make sure you only deploy from a 'clean' working copy.

Tuesday, 23 November 2010

Ruby median

Was trawling through the google analytics search keywords and noticed somebody was looking for an Enumerable#median method when they came to this site. Got me thinking...

I went googling for solutions and found that some of them were just plain wrong... can't have that.

module Enumerable
  def median
    # trivial cases
    return nil if self.empty?

    mid = self.length / 2
    if self.length.odd?
      (entries.sort)[mid]
    else
      s = entries.sort
      (s[mid-1] + s[mid]).to_f / 2.0
    end
  end
end

This one isn't the most time-efficient (the sort can get long). I'd need to implement the selection-algorithm for the most optimal solution... but it'll do for a quick fix. I'll post again here if I get around to the better one.

Friday, 19 November 2010

MatchFounders hits 500

MatchFounders.com hit its first milestone today: 500 registered members. I'm pretty pleased with that, seeing as how it's been a part-time on-the-side project that started on what's basically a hackfest.

Still got heaps to do before it becomes a world-dominating site, of course... but I'm pretty happy with that amount of activity after only a month and a half. Enough to post about it on the matchfounders blog... along with our upcoming dastardly plans.

Saturday, 13 November 2010

mobile broadband roaming

The directors of MoneySpyder have been reading "The 4-Hour Workweek" by Timothy Ferriss and are all fired up about the idea of us working from home (amongst other things). Basically, they're hoping to kick the expense of an office - which is fair enough.

So I casually asked "so, does this mean I can take my laptop on the road?"

I was kinda surprised when they answered yes.

w00t!

So, I finally have the option to live my original dream - spend a month in France, a month in germany, a month in spain...

BUT...

(you knew that was coming)...

I've just checked what it costs to get international roaming on mobile broadband, and it doesn't look pretty.

Actually, that's an understatement... it looks downright atrocious.

I'm currently on three mobile - and I pay around £15 a month for 5G of internet usage. As yet I've never busted that limit - I think I use around 1.5-2G. I used to have a 1G account (with O2) but that wasn't enough for me - eg when I needed to do a full ubuntu upgrade.

However - when I checked into the mobile broadband roaming rates I discovered that they don't bundle your monthly allowance - it costs per mg... and not at the usual overlimit pricing rate of around 10p per meg - it costs you £1.25 per meg!

This would mean my normal monthly usage would come to cost of £2000-£2500 PER MONTH!

Yes, that's over two thousand pounds per month!

Now - I can understand that it costs a fair bit more to use overseas carriers, than to use their own.... but even if *they* bought the data at retail prices, and then charged *us* retail on top of that - this would come to only *twice* our normal per-meg rate...

Not 166 TIMES my normal monthly amount.

There is something seriously wrong there!

Now - the pages all say "well, just don't use as much internet when on the road"... but unfortunately, I have no choice. I am a Web developer - that requires me to do a bit more than just checking email or checking the local weather online. I need to download the latest codebase, get copies of db dumps, upload and deploy sites, go to the online site and test it thoroughly... etc etc. Even if I cut out all recreational internet use (and where's the fun in that) I'd still be using about a Gig a month.

I've noticed that a very few enlightened companies have begun to offer something a *little* better (eg orange travel bundles), but even so - they're still not even approaching regular internet usage. The orange bundle offers 50M at £40 - which would make my monthly spend "only" £1200 - so, half the rate of the Three option... but still in the ridiculous zone.

Now, I've wandered about online in search of a better solution, but I have only a couple of viable options.

Firstly - I could spend my life in a Maccas or Starbucks (or equivalent) for the purposes of the free WiFi connections... rather than actually enjoying the variety of local establishments. Of course - they do expect you to actually purchase some of their wares - and I refuse to eat the former, and the latter is definitely not my cup of coffee-flavoured-milk.

Also - it's quite difficult to actually do real work in a busy cafe. It's ok for a few hours - but it's tough to be there all day. I'd also have to shut down, pack up and potentially lose my table every time I needed to dash to the loo. :P

The second alternative would be to just buy a new dongle from the country I'm visiting... for each country I visit. This feels expensive and wasteful... but if you compare it to the roaming rates - it actually works out cheaper... *far* cheaper.

With Three's quoted roaming rates, it would cost me an average of £85 per day.
Even if a new dongle cost me £100 (for the PAYG version) - I could buy one every two days - and still be paying less.

Ridiculous as this seems, it seems to be my best real option.

If anybody knows of a better solution, let me know!

Dongle-sharing?

But then I got to wondering: perhaps there's others out there wanting to do the same thing. If we each buy a dongle for a different country and then swap with each other - this would be far less expensive. Just buy our own PAYG sims. Or perhaps there are others of you out there already in a different country (that I want to visit) who'd be willing to rent me your own dongle for a month... I'd even pay a refundable deposit!

Any takers?

Wednesday, 3 November 2010

NaNo Wrides again!

It is the month of November, and once again would-be-authors are hurriedly scribbling on pages, or tapping away furiously to meet their daily goal... the elusive 1667!

NaNoWriMo has begun!

I've got my wordcount up on the left again, but you can see more at taryneast's author page.

For those not in the know, "NaNoWriMo" Stands for "National Novel Writing Month" - a writerly self-challenge where people from all around the world pledge to write 50,000 words in the month of November. No, it's not a charity, and it's not a competition... it's just a chance to give it a go and see if you can finally pull that novel out of yourself that you've been procrastinating about for years...

Before you dismiss it as an obscure, minor little thing that only a few weirdo wannabe-writers have heard of... you might want to know that it's more popular than you might think! As of yesterday there were 156,415 authors signed up worldwide, who wrote a collective 55 million words. Yes, that's millions, and yes that's just yesterday!

It's crazy-fun and I recommend it to anyone - especially anyone who thinks they're a terrible writer, or who thinks nobody wants to read what they write... but secretly has a tiny desire to be known as an author. Trust me, NaNoWriMo is for you.

It's only day two - there's still plenty of time to join in the fun! Go on, give it a shot! What have you got to lose? :)

Sunday, 31 October 2010

Gravatar in rails

Just a quick code-snippet today. A quick helper to take an email and spit out a gravatar image.

  # show the gravatar image for a profile - based on their email
  def gravatar(email, size = 100)
    the_hash = Digest::MD5.hexdigest(email).to_s
    image_tag "http://www.gravatar.com/avatar/#{the_hash}?s=#{size}&d=mm"
  end

This one displays the "mystery man" image if the person doesn't have a gravatar. More details on the options and how to tweak it further are available on the Gravatar Image Requests page.

Thursday, 21 October 2010

Profiling inside of procs

I've been using ruby-prof and kcachegrind to delve into our code recently - in an attempt to speed up some of our heaviest views - these are mainly big admin pages listing, say, all orders that are waiting on backordered products.

One of the joys of kcachegrind is the ability to see the actual lines of source-code with the actual time spent in each LOC nicely indicated. You can then click on that line and it'll jump into the slow method that is called by that line.. so you can dig down to where the actual pain is being caused in your app.

One of the problems with with the source-code tracking, though is that it just doesn't deal well with ruby procs. Kcachegrind assumes it's some kind of method-call, but when you click on that LOC, it doesn't take you to the code inside that proc, but you instead end up diving into the *ruby* source-code itself... definitions of blocks and procs etc... which are all aggregated together and thus you can't tease out the bits that you actually want (ie the code operating inside the proc itself).

So if you have something such as the following wrapping almost your entire view page:

   @orders.each do |order|
      # tons of lines....
      # displaying and formatting the order values follow...
      # ...
   end

You'll often only get a single, aggregated line of information n the "orders.each" line... and clicking it only takes you to Ruby's Array#each rather than your actual code.

Entirely unhelpful.

For the sake of profiling that code, though, you can unroll it into a while loop - just to check which LOC are the ones giving the pain by switching it (temporarily) to:

   idx = 0
   while idx < @orders.size do
      order = @orders[idx]
      idx +=1 # don't forget this line or it will take some time to finish.. ;)
      # tons of lines....
      # displaying and formatting the order values follow...
      # ...
   end

It's a dirty hack, but in the absence of "each" it's kind of a necessary evil - and it works. Just make sure to remove it once you're done!!!

Saturday, 16 October 2010

Quick RubyProf action filters

A good while back I spoke about using ruby_prof and kcachegrind at LRUG.

I was asked back then if I could stick up my ruby=prof filter-code... and I've been just a *little* bit slack about getting around to that... but recently I've been profiling again, so I thought I'd bring it out again for general use.

Here's a way to quickly add ruby-prof profiling to any given *action*. Use the following around_filter on your action. Note: this will *only* profile what happens in the controller-action. I use this on our uber-heavy summary-page views to make sure that the mammoth Active Record fetches aren't themselves the problem... before getting onto a full-stack profiling-run.

  around_filter :profile_it, :only => :my_slow_action

  # profiling around-filter - just does the controller-action only
  def profile_it
    require 'ruby-prof'

    logger.info "Starting profiling"
    # profile the first set
    RubyProf.start

    # actually do the action
    yield

    result = RubyProf.stop
    logger.info "Profiling finished, printing files"

    # Print the callgraph profile
    filename = Time.now.strftime("RubyProf_#{params[:controller].gsub('/','-')}_#{params[:action].gsub('/','-')}_%Y-%m-%d_%H:%M:%S.grind")
    File.open(filename,'w') do |the_file|
      printer = RubyProf::CallTreePrinter.new(result)
      printer.print(the_file, 0)    
    end
    true
  end

or to profile the full stack through to the template render, you'll want to split the start/stop. I tend to call start_profiling at the top of the controller action (to get rid of most of the rails loading time), and then call stop_profiling at the bottom of the relevant layout.

Put this into application_controller.rb

  # Will only start the profiling... to stop, you'll need to use the helper
  # at the bottom of your template.
  # Use this pair to catch template-rendering in your profiling data
  # Pass ":wall" as a variable to use wall-time instead of process-time
  def start_profiling(time_type = nil)
    require 'ruby-prof'

    logger.info "Starting profiling"

    RubyProf.measure_mode = RubyProf::WALL_TIME if time_type == :wall

    # profile the first set
    RubyProf.start
  end

Put this into application_helper.rb

  # Use this helper in your template to stop profiling. Asumes you have
  # called "start_profiling" in your action somewhere
  # Will asplode if you haven't actually *started* a profiler
  # (eg if the previous action threw an exception before completing the profiling run)
  def stop_profiling
    if RubyProf.running?
      result = RubyProf.stop
      logger.info "Profiling finished, printing files"

      # Print the callgraph profile
      filename = Time.now.strftime("RubyProf_#{params[:controller].gsub('/','-')}_#{params[:action].gsub('/','-')}_%Y-%m-%d_%H:%M:%S.grind")
      File.open(filename,'w') do |the_file|
        printer = RubyProf::CallTreePrinter.new(result)
        printer.print(the_file, 0)    
      end
    else
      raise "Stop profiling called when no profiling started!!!"
    end
    true
  end

Sunday, 10 October 2010

RedBubble Gallery page

I've posted earlier about how cool RedBubble is... but now they let you set up a gallery page, to show off (and even sell) your best pics. So here's the Ruby-coloured glasses gallery

Sunday, 3 October 2010

Heroku with svn

and here I was thinking I'd never get to play much with Heroku as I prefer svn over git... [*]

It seems you can easily use Heroku with svn, by using git just as a mode of transport onto Heroku.

If you've never used Heroku before, you must set up your keys and project before following the above instructions. Use the quickstart guide to get up and running in no time.

You may think that handling two version control systems is difficult, but so far I've actually found it fairly simple. Basically you treat git like you'd treat "tags" - you commit to git just before you push up to heroku.


[*] For most of my projects, I prefer having one source of truth. I've also had some rather spectacular failure-modes using git which I've not seen the like of in all my years of svn... if you're adamant on learning git, read my Number one thing to learn if new to git first...

Sunday, 26 September 2010

MatchFounders: a launch48 company

So, you are a business guy with a dream, looking for a savvy techie to turn your dream into reality

OR

You are a rockstar developer, looking for a business guru to take your idea to market.

Both of you are looking for somebody hard-working, willing to commit and sharing your values and passions.

They say that looking for co-founders is like a marriage, so how do you find your perfect match?

Match Founders will match your skills, values and passions against other people that also match your needs.

A bit of explanation...

Launch48 has begun, and this time around I'm running a team.

We're building a match-making service to help co-founders find each other, called MatchFounders.

We've got a blog on posterous: MatchFounders and are working on our initial web demo. Stick around to find out what happens...

Wednesday, 22 September 2010

To stealth, or not to stealth

I've been working on a new startup with two other founders that I found at launch48 last year. I've already mentioned launch48 on this blog, but I haven't yet mentioned my startup... That's because we've been keeping it quiet until recently... when we had a kind of "trial launch" at the previous launch48 weekend (in June).

Now, based on my reading on the matter (see links at bottom), I don't believe that "stealth mode" is actually a good way to go about building a web business. I think the reality is that if you've got a good idea, not only will it not instantly be stolen from you, but you'll have to cram it down people's throats before they take any notice...

But you see, I have two business partners. One of which is a strong believer in protecting your IP - and the other wanted to make peace between us... so we compromised and kept a lid on our idea until the trial launch.

Now, we're fairly new to the game, and we think there's a good idea in our startup, but it's no iPhone. It's not something people are screaming for and they aren't going to start beating path to our door immediately. Because of this, I was never afraid of people "stealing our idea" - because, to be honest, it just isn't sexy enough. When I explain it to people they go "oh, ok, cool I can see that... did you think about doing Y?" I've never seen a gleam of greed in their eye, followed by hasty notes scribbled down... and I never expected that this would happen.

So in my opinion, I don't see a big reason to keep it quiet.

Instead, I think it's important to get exposure to your idea as early as possible from people Out There in the Real World... that way you immediately get to see whether people think your idea is actually worth spending eight months of your life on... or not. This is simply my own reasoning behind Seth Godin's Ship it philosophy.

Stealth mode redux has some interesting case studies on which "startups" do and don't need to stay quiet about the product they have in production.

What I see most clearly is that stealth mode is mainly useful for companies that are large and already have a big audience... or who have enough funding to keep them going while they beaver away in secret on a product until it's perfect... ie companies that aren't actually startups.

The problem is that real startups - the tiny, self-funded groups of new founders - can't afford to be in stealth mode for very long - for the very simple reason that they do not have enough capital for long periods of development.

I'm not talking about people that slowly hack away doing a few hours every week while working a day job... I mean real "cash flow positive from day one" startups, rather than ones that require such extended self-funding.

Such things need to start gaining revenue asap, and the only way to do that is to attract customers... and the only way to do that is to tell everybody about them!

In the interest of balance, of course, there's a great post pointing out that releasing early is not always Good - which covers some of the reasons why *not* to release early... and they're all very fair points. But I'd argue that all of them point to a new variant of Einstein's famous "make it as simple as possible, but not too simple" ie:

"Release as early as possible, but not too early"


Update:

After having read The small man builds cages for everyone on The art of non-conformity, I'm convinced that NDAs and other stealth-measures are a cage-building habit.


Notes

Links on stealth-mode being bad, or the philosophy of "release early, release often":
Startup lessons learned
The Cathedral and the Bazaar

More links on stealth mode:
why choosing to go into stealth mode could be the kiss of death for your startup
Does Being In Stealth Mode Damage Your Business?

Wednesday, 15 September 2010

Single sign-out using ruby-cas... Not!

We considered this... right up until the point where I read that you were advised to disable forgery-protection.

It's easy enough to send a message to the rubyCAS server to invalidate a given ticket - but mostly users only authenticate with rubyCAS once, and from then on deal only with a given client-application. Killing rubyCAS's ticket only comes into play when a user tries to re-authenticate with the rubyCAS server.

I don't have a good solution to this one...

This is one article in a series on Rails single-sign-on with rubyCAS

Friday, 10 September 2010

Signup: Ask the right question

The sign-up process is much more than just the form that gets a potential customer's details. The majority of the sign-up process actually takes place inside the customer's head. A customer will sign up - even using a crappy signup form as long as they're actually motivated to buy your product... not that you should make a crappy signup form - because that also just puts hurdles in the way of an otherwise motivated potential customer.

This awesome presentation explains how you can design your signup process to get customers motivated and rearing to go on your site. It points out where the friction is in the process, where they usually fall out of the sales funnel, and the ways to change your way of thinking about your site: to provide ample opportunities for a confused or skeptical customer to change their minds. It also picks out the pain-points for the sign-up process - giving some great examples of how to get out of their way and let them get on with paying you money straight away... always a good thing.

I only wish I'd seen the original talk, but the slides themselves speak the story clearly and are well worth a few minutes of paging through.

Thursday, 9 September 2010

gotchas: gem cleanup

Note to future self: do not type "gem cleanup"...

...now reinstalling rails v 2.3.4, 2.3.5, 2.3.8... etc

Wednesday, 8 September 2010

Launch a startup in 48 hours!

Launch 48 teams up business-gurus and techies, where the aim is to pitch, plan and launch a viable web-product in the following 48 hour period. It's 48 hours of hard-slog startup-founding that is guaranteed to leave you buzzing (honest)

I've been twice now, and just signed up for a third time. It may sound a little crazy... but it is an awesome experience, and I confess I'm now addicted.

If you can make it to the conference (on the Friday) they also line up a set of speakers from some of the best IT companies in the world (google, paypal, et al), along with VC, successful IT businessmen and other assorted useful types to give a talk about how you can turn your idea into reality.

and it works too. Several of the startups have gone on to become successful online businesses... of course some don't but I can honestly say I've learnt a lot in the process. I even met my co-founders there, so I can attest to the benefit of working with people to see if you can work with them...

Early bird tickets are on sale for the next one (the 25th Sep)... so I hope to see you there :)

PS: just to make it clear - I'm not affiliated with launch48 in any way except for having gone along to it (twice now) and found it to be awesome!

Wednesday, 1 September 2010

Rails 3.0 is Done!

As you've probably already heard, Rails 3.0 is done, no longer just a beta, it's out there and beginning to be used. Go look at all the goodies we've got lined up!

Tuesday, 31 August 2010

The culture I prefer

This article named telecommuting culture is an interesting look at how job ads can make it pretty clear about the associated company culture. It pretty much sums up my own experiences of how to tell a company culture that I like from one where I'll just never fit in...

"The world’s a big place. There’s a lot of developers in it. There’s even a few kick ass ones. Most of those don’t live near you ... By being up front about telecommuting not being and option, you’re telling me that company comes first ... Hiring someone good is important, but hiring the best you can afford isn’t."

There's a follow-on post on taking stances that points out how much of a controversy was stirred up by his original, highly opinionated post. He's nicely pointed out that his stance was a strong one - in order to generate discussion, but that he's not unreasonable, basically he just wants people to understand that job-hunting is a two-way street. The following quotes best summarise his (modified) stance.

"Companies that start the conversation with prospective employees by outlining the things they aren’t going to stand for are starting off on the wrong foot..."
"Companies, particularly in the tech space, are asking their potential employees to take a chance on them. Companies are taking a risk too, but when companies expect the employees to be the only ones giving (broadly disregarding monetary compensation from the companies for the moment), they set the wrong tone."

I completely agree with this feeling. Sometimes employers forget that they're not just interviewing you, but that you are also interviewing them - and that this really is a business proposal that has to be fair to both sides. If a company comes across as unwilling to be flexible for any reason, it doesn't bode well for the rest of the employment relationship.

I've too often seen employers that seem to think they own your soul once you sign on the dotted line... that they can make any demand of you and that you'll jump-to. This is the business equivalent of "the customer can have any colour he likes so long as it's black". Which may well work just fine for people that like black... but if you find it overheats in the sun and you need white... you'll find it best to take your business elsewhere. In fact I wrote about the lack of viability of this attitude (at length) in Up or out: the attitude for contractors.

This seems especially to be the case in a down economy as has recently been the case - where I've even seen some employers demand unpaid overtime and drop loud hints about how people should be grateful for having any job at all in this economy.

Apart from being incredibly rude, such employers are short-sighted. Firstly - the economy is going to pick up again... at which point, the indentured slaves are quite capable of picking up sticks and going elsewhere. Secondly - even in the down economy, there were enough jobs (at least in my field) to go and find somewhere that treated their employees like human beings rather than indentured servants.

It pays, in the long run, to be considerate to your staff; to even be flexible, or generous. After all, they're the ones who are literally making your company's money, day-in and day-out.

Tuesday, 24 August 2010

The two faces of Optimism

I've often been accused of being a pessimist.

I'm actually not. Far from it, I truly am an optimist. The problem seems to be that often people use the word "optimist" to mean something quite different to my (accepted) understanding of the word; and so, not agreeing with their worldview, they label me as a pessimist.

I think the real issue stems from divergent ways of viewing the term.

There are two definitions in common use.

A world of abundance

First is the one that I subscribe to. Optimism, for me, is to see a world of abundance, rather than a sea of troubles.

I believe that there is a solution to every problem (even if the solution is to throw out the old game and find new rules) and that anyone has the ability to get through the problems and find their dreams. Nobody is a lost cause and there is plenty of abundance to go around.

For me, that is optimism.

*You're* not an optimist

The other view I generally see in the pejorative sense. I can best explain by example:

You don't agree that my <* patently-impossible or highly-improbable *> plan will succeed, That's because you're just not an optimist!

I guess I'm just not a yes-man

Let me be clear: It's not "optimism" to be in deep denial about the efficacy of your plan, and I am not a "pessimist" just because I have looked at the numbers and found that they don't add up quite as well as what you hope them to be. I simply don't agree with you.

I am not a pessimist because I believe that *this* solution of yours won't work. I am an optimist because I believe that there *is* a solution, and that we will find it if we keep trying.

Optimism and employee relations

This issue often crops up at its most pathological in employee relations. In my experience, this is because there's a certain breed of manager that simply doesn't want to hear anything negative - even if it's the facts surrounding a potential solution. If solutions to a problem are proposed, then the most optimistic *sounding* solution will often win, regardless of actual likelihood of being the correct fit. Any nay-sayer to the offered solution will simply be dismissed as a curmudgeon, and thereafter will often be viewed as a "troublemaker".

As human folly goes, if the plan then fails, the nay-sayer is hardly likely to receive any recognition for having pointed out the potential... in fact, if the subject is ever brought up again, greater dislike is sure to follow - nobody likes being told "I told you so", especially on the heels of defeat.

More often than not, however, the initial solution will not fail miserably, but will simply provide sub-optimal results. The originator of the idea will be convinced that it was the best that could possibly have been achieved and that you were clearly a pessimist to think that it could fail...

Trust me... there is no point to trying to persuade them that your idea could have been better.

So, what to do?

The only way out of this dilemma is to make sure that instead of simply taking pot-shots at a bad idea, always provide an alternative solution that you can show is more likely to work. In this way you can show that you are optimistic about solving the problem, just not about the particular solution on the table. It's even better if you can reuse aspects of the original solution in your own - to show that the first proposal wasn't all bad, just needs re-alignment... but this isn't always possible.

It's certainly not a guaranteed solution. The first idea may well not be removed from the state of play - and may still be valued seeming more optimistic (ie providing a promise of a better end-solution... even if not more likely to succeed). This is even more likely to happen if the solution has been championed by a manager in an environment where Highest Paid Opinion wins reigns supreme). However, offering a solution will show that you are presenting a positive outlook, and you're less likely to be tarred as strongly with the pessimist/troublemaker brush. You show that at least you are trying to be helpful.

Of course... in some environments it still makes little difference, and even a dissenting opinion will brand you.

In this case, my suggestion is to be an optimist and trust that the world will get along in the end, and that perhaps there might be bigger, better places for you... if you choose to go looking for them. :)

Notes

Pessimist:

In reaction to them, I'll often tell them that I am a "realist" - which unfortunately makes them just snort and underscore the "pessimist" label in their heads. After all, I've found that a lot of optimists don't know the difference. Of course, mainly I'm just playing with their heads. :)

yes-man:

Sorry, "yes-woman" just sounds stupid, so I won't use it regardless of the truth of my actual sex; And I will bite anybody that suggests that I use "yes-person" :P

Wednesday, 11 August 2010

Controversy: too much choice in Ruby

A tongue-in-cheek post called "So you want to be a ruby dev" has sparked a bit of controversy in the community by pointing out the overabundance of options now available to ruby learners. A lot of commentary has happened on the hacker news thread for the article, with the loudest voices complaining that while there is choice - that it isn't mandatory to learn all the options, for example in the same way as examples such as Java.

Opponents point out that the proliferation of options is confusing potential newcomers to the field, who don't rightly know where they should begin. That the community (and therefore the documentation) seems to be fragmenting, where it isn't simply missing, or so old as to be effectively obsolete.

The article sums up the situation by lamenting: "Remember when Ruby and Rails was about getting stuff done?" The implication being that newbies have to spend so much time learning about all the possible solutions... simply to choose which one they should begin to use.

A follow-on article on Ruby Inside continues the discussion, pointing out that the variety of options available to Ruby-users is its strength, rather than being a drawback. It points out that what we are missing is just a few simple "for newcomers" help-pages that clearly show how you can get started with the minimum of fuss.

The post ends by calling for ruby-developers to remember the philosophy of having many ways to do something, but to have an opinion on what the best approach should be. It also strongly calls for more straightforward "Start by doing X, then Y" how-to posts for beginner Ruby users... emulating the rather better documented beginner tutorials on the Ruby on Rails pages.

Thursday, 5 August 2010

Link: Mind your ands and ors

I've posted before about the subtle (and insidious) difference between the 'and'/'or' operators and the nearly-but-not-quite-the-same '&&' and '||' operators... but likely lost amongst the rest of the noise in my acts_as-good_style post.

This post: Using “and” and “or” in Ruby does a much better job of explaining when to use each one - and goes further to suggest that you shouldn't simply give up on using 'and'/'or', describing their usage as control-flow operators.

It's a small thing, but every bit helps.

Wednesday, 4 August 2010

Rails 3.0 is out...

The Rails 3.0 Release Candidate has been out for a few days, and it looks like it has some great goodies in store.

There's a lot to catch up on, but I suggest you start by having a look at these Rails 3 screencasts by Gregg Pollack.

Update: and now Rails 3.0 is done! - no more beta, it's really out there and ready to use. Go have fun!

Monday, 2 August 2010

Life at 34

When I was 5 I liked to do jigsaw puzzles upside down (to make it harder) and blow bubbles off the balcony -- watching them drift over the street. I liked to walk to school by myself (one block) and learn Origami from the lady in the flats behind us.

When I was 7 I wished on every star that I could have a baby sister. When I was 8, I got one.

When I was 10 I liked to explore the backways of Oyster Bay, picking flowers to make perfume (which smelled terrible). I played fantasy make-believe games with my cousins - involving magic and unicorns, where we saved the world.

When I was 12 I got another sister.... I stopped wishing.

When I was 13 I liked to play make-believe with my sisters and all the younger cousins. Gordy and I plotted adventures for us all, in-amongst the bamboo.

When I was 15 I like to climb up on the roof and watch the clouds drift by. I liked to ride my bike home from school and play LARP in the park across the road.

When I was 17 I liked to swim in the backyard pool, drifting underwater with my hair floating loose around me. I liked to frantically scribble down my hurts in my diary and day-dream about the brat-packer boys; making up adventure stories or inserting myself as a character in my favourite movies.

When I was 20 I loved the freedom of being independent, waking up in my own flat to the sound of Cockatoos in the pine-trees. I liked being free to wake up in the afternoon and go for a walk in the twilight, or in the quiet time after the curfew painted the streets with night. I liked staying up all night, having coffee with friends, as television got progressively more idiotic. As the sky began to warm with first light - I went out again. I liked feeling the expectant hush of the cool dawn, then retiring before the hustle woke up.

When I was 22 I loved my writing diary - pouring out my heart or playing with words, crafting new worlds on a page. I liked learning new things -- drifting from subject to subject. I liked psychology, programming and the occult. I loved my cats. I liked it that I got married and was somebody's wife. I liked meditating with my husband -- humming toneful chords without meaning. I liked learning martial arts with him.

When I was 24 I loved my garden. I spent days drifitng through it and tending to the plants. I liked picking silver-beet and herbs and cooking up a meal that I'd taken from seed to table. I liked shopping at Bunnings for fruit trees. I liked spending Saturday nights with the Druids, singing, meditating, drinking mead and telling stories. Then the morning-afters, skinny-dipping in the wading-pool as the sun climbed the sky.

When I was 26 I liked exploring the back-areas of Chatswood in search of great food. I loved hacking together brilliant solutions for colleagues desperately late on their projects. I liked rock-climbing with my work-mates and playing network games in the training room until late at night. I yearned for a man that I couldn't have.

When I was 28 I loved freedom. The freedom to choose my own time, to choose what to learn, to work on my own projects. I liked smiling at my young class-mates who complained about the work - knowing this was easy compared with Real Work. I liked the meditation of archery. I liked spending my time reading while sipping coffee, or eating noodles at the local hole-in-the-wall. I liked long walks in the evening, scoping out my local territory.

When I was 30 I liked building my own small business, knowing I owned it and I could acheive whatever I wanted. I liked learning medieval crafts alongside eager students, and feasting with friends in a medieval campsite. I liked reading books, sipping coffee after a good workout at the gym. I liked watching myself learn how to walk again.

When I was 32 I enjoyed being a senior developer, I enjoyed being at the top of my form as well as earning high pay. I enjoyed choosing my first major investments in shares and buying my first property. I enjoyed planning what to do with my life, and choosing to gather interesting experiences around me - New Zealand, the Northern Territory, Thailand. I enjoyed learning photography, spanish and investing. I watched a *lot* of DVDs.

When I was 34 I loved exploring in a new country. I liked visiting ancient ruins and watching Shakespeare at the Globe. I enjoyed getting better at photography, meeting new people and places. I enjoyed building my own startup with friends. I enjoyed my morning coffee at the local in Windsor, and walking past a castle on my way to work in the morning. I enjoyed pottering around in my allotment late into the long, english summer nights.


This post began as an exercise: "for every five years, write what you enjoyed doing". It helps you find out what you most enjoy - and how your tastes change over time.