Saturday 31 December 2011

Who is the real user here?

If a site is developed ostensibly for one purpose, but the monetization strategy is skewed in favour of some other purpose... what do you think is going to happen to the site over time? Whose interests are going to be prioritised?


Sure, the intentions are good, and you'll try your hardest to serve all your end-users, but if you have an actual, paying subscriber demanding a particular feature (or they'll take their money and leave) vs a feature that the non-paying community has been asking for... which one is more likely to make the cut?


I mentioned recently in my Sparkpeople vs fitocracy comparison, Sparkpeople have a number of UI problems, and I believe they stem from a slightly mis-matched customer-needs alignment. Ostensibly, the purpose of SP is to help people trying to lose weight. But the only money is coming in via advertising - the result? big flashy ads on every page, special "javascript-only" links that won't let you open other pages in new links (because that way you'll be busy reading the other tabs instead of watching the ads), very few new features that *actually help people lose weight* - instead concentrating on increasing user-generated-content.


Who is the real user here? Well - the sponsors...


I'd actually have paid to get a better service than this - to get them to finally (after three years) allow me to get graphs in the metric system or to not see the advertising. But the CEO is convinced that he's being generous by keeping the site ostensibly "free"... unfortunately - the site clearly isn't free. It's paid-for by customer attention.


But how did it get this way? I mean the owner is clearly a fanatic about trying to help people to lose weight, willing even to spend a very large amount of his own personal fortune to set up and maintain this site. So why did these anti-features appear in the first place?


It's simple common human nature that's to blame.


If the motive for a site does not align with the motive behind the money-flow, then you'll have two masters to try to serve - and it's obvious which one will win out. It's a much better idea to find a way to align these two.


A good example of alignment is in White Label Dating (a company I used to work for).


They are a company that allows people to set up their own, branded dating sites. For example, a women's magazine might decide they want a dating site. Rather than building one from scratch - with the near insurmountable chicken-and-egg problem (not to mention a strongly gender-skewed audience), they can come to WLD and quickly build a site that has all the functionality ready-made... along with access to a *huge* pre-existing database of daters... but also allows them to put their own branding on top. It's a "white label" dating site.


Now WLD's monetisation strategy is as awesome as it is simple: they revenue share. That means that for any individual dater that pays for a membership through the magazine's site - a percentage of the money goes to the magazine, and a percentage goes to WLD. The magazine is incentivised to use their brand and existing audience to promote the site -> getting more memberships, which gives them more money. But better yet, WLD are incentivised to make a good service for the end customers (the individual daters) because that way people will be satisfied by the service and continue with their membership.


The end result is a system that works for WLD, works for the magazine... but *also* works for the individual daters that sign up for the service.


That's how it should be.

Saturday 24 December 2011

Autocomplete with acts_as_taggable_on

Basic tagging sorted, I went looking for a way to add auto-complete - cos it's a nice UI improvement that's pretty common on teh intarwebs these days. I did a lot of searching, as most of the solutions seem to require switching to jquery, and for reasons of laziness (and legacy code), I don't wanna do that right now.


Luckily my searching dug up a tutorial by Michael Schuerig called: auto-completion for tag lists that works with acts_as_taggable_on and the auto_complete plugin.


It pretty much covers all the bases for tagging, so I won't repeat it all here. But I think it's awesome, because it will auto-complete on just that part of the field after the last comma - just what you need for a keyword-list.


Do read all the way to the bottom of the page, as his later updates can change the way it functions a bit.


I did make one addition myself. We have one form that lets you upload multiple items at once, with a "add a new form" link. It just repeatedly inserts a partial-template onto the end of the existing list, each time it's clicked... but because it's called *after* the "onLoad" event, the auto-complete wasn't getting added to it.


To work with that, we needed to add the installAutocompletion(); call to our addNewForm function, and also make sure that each "tags_list" field had a unique id.


I also needed to slightly update the controller code so that it could *either* take params[:my_widget][:tag_list] *or* take params[:my_widgets].first[:tag_list], because the multiple-forms-on-the-page form always sends through an array of widgets instead of just the one.


Then I realised that installAutocompletion would just keep adding autocompleters every time it was called... even to fields that already had one. So I updated the code by adding the following around everything after:


/* only add it if it doesn't already exist */
   if ($(completions.id) == null) {
       element.parentNode.insertBefore(completions, element.nextSibling);
       ... everything else after the above line too
   }

After that it was all gravy.

Monday 19 December 2011

"Our greatest asset"

I've just discovered 1.00 FTE. :)

Here's one to get you started:

Oh and, just like XKCD, there's always a rollover tidbit (not included here, go look at the site to see it).

Tuesday 13 December 2011

fitocracy vs sparkpeople

Update: Here's a fitocracy invite (if you want one)

I've been using sparkpeople for several years now, to track my workouts and weight progress. I heard about fitocracy a while back. It's gotten a fair bit of buzz in the geek crowd, and I've been hoping to play with that to see how they compare - but they never did get back to me with an invite... so I googled and grabbed one from a random fitness website :)

So now I can finally have a look at it and see what all the fuss it about, and find out which of the two I prefer. I've only been using fitocracy for a month, but here's my pros/cons so far.

Fitocracy

pros

  • Founded by fitness enthusiasts
  • Better centred around actual fitness scores (eg you can graph your reps or dumbell-weight, not just "number of times logged")
  • Better-designed interface (cleaner, better inter-page linkage, less cruft etc)
  • Can enter individual sets (rep/weight) all at once - which makes drop-sets and ladders much easier
  • Can save a "routine" full of sets (even from different exercise types) and copy it to a new day
  • Can actually can deal with the metric system! In every place where units are used (both entry and display and on graphs)
  • More motivating scoring system (at least I think), including fun quests etc
  • It tracks and notifies you if you've reached a new personal best (eg more reps, more weight, faster time etc)
  • Scoring system seem better weighted towards actually improving a person's exercise/fitness, rather than creating the user-generated content (or reading/viewing the sponsored content)
  • The developers are active in the forums, and actively work to change the system to meet the community's goals.
  • freemium - I like that they make a premium service available. That means they may not end up as advertising-supported site (which skews feature-design through the who is the real user here problem)

cons

  • *still* in beta, and you need an invite (you can get one yourself from my fitocracy invite code - I got mine from spartanwarrior's blogpost )
  • Some "growing pains" style bugs now and then (though I notice they disappear very quickly)
  • No run-distance tracker (you have to use another tool)
  • Smaller community (so far)
  • Still putting together a full set of data (eg exercises and advice), though it's sufficient for general use, and they take suggestions.
  • Can't go back and add your past workouts if you're, say, halfway through a multi-week challenge and just arrived on the site (4 days back only, even if you've *just arrived*)
  • Can't track goals you're working towards (eg goal weight/reps/distance ?) - though you can graph your current "personal best"
  • Not really set up at all for weight-loss tracking (you can enter your weight, but can't track it, and there are no quests or points for weight loss goals)

Sparkpeople

pros

  • Founded by weight loss enthusiasts
  • Has extensive food/calorie/nutrition-tracking
  • Larger range of options - eg tracking custom measurements/goals/activities etc
  • A huge library of fitness and health information already
  • Regular health-based news, recipe books and personal webpage (including blogging)
  • Can go back and add past workouts at any time in the past (good for migrating to a new site and not losing your past)
  • Nice widgets eg the "starting/current/goal weight" tracker.
  • Integrated distance-tracking tool (uses google, but then you can add your time and click "add to today's workout")
  • Can set/track long-term and per-week goals (eg long term goal of 60kg or "do 650 calories of cardio each week")

cons

  • It's actually very difficult to put in strength-training. They assume you do same-rep/weight sets so drop-sets or ladders have to be entered over and over again one at a time.
  • I think the points-system rewards strange things eg you get much more points for watching their advertising or for blogging, making recipes and taking polls/quizzes than actually doing exercise - this makes me feel that they are rewarding user-generated-content creation (which makes their site look better) rather than actual exercise/weight/loss (which rewards the actual person and is the stated purpose of the site)
  • Strength-training has bad graphing - you can't graph individual exercises whether by rep/weight or even number of times done (even though you can enter the info)... only by "number of training sets in total" (with all exercises mashed into one blob)
  • Excessive flashy/movey ads everywhere - which slow the site-load down and are also annoying. They are also prone to z-index problems (ie the menus sometimes appear *under* the ads)
  • They have some weird attempt to try to force you to only ever have the site open in one tab at a time. They do this through excessive use of javascript "load into this window" rather than normal links.It's quite likely an attempt to stop people from browsing elsewhere while the ads are showing, but really annoying if you're a multi-tab geek like me. To me this is one more piece of evidence that the "real users" of the site are the sponsors, not the people coming to lose weight.
  • Years later and they still don't have metric graphs. It seems like they've only made lip-service towards the metric system. I can enter my weight in kilos, but all distances are entered/tracked in miles.
  • General US-centric approach: I've noticed many, many polls/quizzes and articles that refer to US-only brands/traditions and culture.
  • No Premium Service option. The site is clearly suffering the problems of a free service: heavy ads, frakking around with links etc - I would have paid for it to actually work the way I want to (and get rid of those ads) but there's no option for that. Unfortunately, this is because the CEO/founder had publicly stated that SP will always be free. I'm sure that seemed a good idea to start with... but as their userbase rose dramatically, they've clearly had to fill the gap with advertising - thus leading to the change of "real users"

My personal conclusions

Sparkpeople has done me great service, and I can't really complain too much about a free service. Still, it's been around for a long time now - and they seem to have stopped improving the actual exercise/weight features and moved to mainly improving the information and social aspects. These aren't the bits that brought me to sparkpeople in the first place. I want a great tool for measuring my progress - not just another "generic health information" website (plus recipes!). sparkpeople is centred around building the sparkpeople community. That's fine... but I'm increasingly feeling that it's just not for me.

So - is fitocracy a good replacement? So far I think the answer is yes. It provides a better tool for the kinds of things that I want from an exercise logger. It also has added community features which, in this case, don't seem to be getting in the way. It's still unfinished, and yet it has a more professional "finish" to it than sparkpeople has ever managed. From what I can tell - the only advantages that sparkpeople has over fitocracy are the recipe/food-logging tools (which I never use anyway) and the vast back-catalogue of information provided by the sparkpeople community (both paid-for and free), which is something that will come to fitocracy with time.

For a little while longer I'm going to maintain both - mainly because I have three years' worth of past-data in sparkpeople (which is motivating for me). But if fitocracy ever gave me a way of importing that, I don't think I have any hesitation in switching permanently.


What do you think? have you used them both? Have I missed something important?

Wednesday 7 December 2011

Acts-as-taggable-on

Tagging is pretty popular these days, and it was time to add it to our site. Unfortunately, lots of the gems are old, and it's had to know if that means "good and has stuck around" or "buggy, obsolete and no longer supported".

The rubytoolbox page on rails tagging has several gems - most of which are marked as inactive now. The only one that looked like it had any recent activity is: acts-as-taggable-on. It's also the top-most-downloaded, so that looked good.

Best news: it is rails-3 compatible AND supports a recent build-version that is still Rails-2 compatible. As I've mentioned before, my current client is still on Rails-2 - because the upgrade pain is not currently outweighed by the new features.

The only annoyance is that the rdoc only has rails-3 post-install instructions rails generate acts_as_taggable_on:migration. These don't work for rails-2, and if you try just substituting "script/" for "rails ", it'll give you an error saying: Couldn't find 'acts_as_taggable_on:migration' generator

I had to hack about a bit to find the new migration name, but what you need is: script/generate acts_as_taggable_on_migration

After that I used this extremely good tutorial on tagging with acts-as-taggable-on.

I don't like the tag-cloud style of tag-selection, and instead prefer something much more like Stack Overflow. So I created my own tag-list as per the code below.

It lists all current tags for the class (assuming similar code setup to the tutorial above), and filter based on that keyword - incorporating any existing search or pagination conditions you already have. It will highlight the current keyword, and change that link to a "deselect if you click" link.


    # code in index page
    <% @tags.sort_by(&:count).reverse.each do |k| %>
      <% url_opts = {:action => "index", :controller => "posts"}
         link_name = "#{k.name} (#{k.count})"
      %>
      <% if @keyword == k.name %>
        <%= link_to link_name, url_opts.merge(:keyword => nil), :class => "tag current_tag", :title => "Click again to see all" %>
      <% else %>
        <%= link_to link_name,  url_opts.merge(:keyword => k.name), :class => "tag", :title => "Click to filter by #{k.name}" %>
      <% end %>
    <% end %>


   # code in controller
   options = {} # any search/pagination conditions go here
   @tags = Post.tag_counts_on(:keywords)
   klass = Post
   klass = klass.tagged_with(@keyword) if (@keyword = params[:keyword]).present?
   @posts = klass.paginate( options )




  /**** and associated tag-cloud styles ****/
  /* basic tag-box */
  .tag {
    background-color: #eee;
    border: 2px solid #ccc;
    color: orange;
    border-radius: 7px;
    -moz-border-radius: 7px;
    padding: 2px 15px;
    text-decoration: none;
  }
  .current_tag {
    background-color: #ddd;
    color: orange;
    border: 2px solid orange;
    border-radius: 7px;
    -moz-border-radius: 7px;
    font-weight: bold;
  }
  .tag:hover, .current_tag:hover {
    background-color: #bbb;
    color: red;
    border: 2px solid red;
    border-radius: 7px;
    -moz-border-radius: 7px;
  }

Next up is to figure out ye olde ajax auto-suggest when I add them.

Sunday 27 November 2011

Snippet: random range

Being able to get a random number within a given range is something currently only available in ruby 1.9... but if you want to add a quick method that will do it for you, this one does the trick:

  def rand_in_range(val1,val2)
    rand(1+val2-val1)+val1
  end

  rand_in_range(1,5) # => one of: 1,2,3,4,5

  rand_in_range(100,999) # => anywhere from 100 to 999

Note: it only works for integer values...

Monday 21 November 2011

Genome GPS: crowdsourcing science funding

A friend of mine is using rockethub to fund scientific research. This looks like an innovative alternative to grant-grubbing and research built only around what BigPharma will pay for. Worth a bit of support (even if you can't afford much).

GPS for the genome on rockethub

Monday 14 November 2011

Link: How to avoid ghetto jobs

A great post on women 2.0 about how to avoid what she terms "pink ghetto" jobs. These are jobs that are just as bad for men as for women, and are often the first job or two you fall into as a new graduate. eg unpaid internships, poorly-organised, unfunded startups and those dead-end jobs where you end up maintaining monstrous legacy code on very low pay, rather than learning new skills.

The article takes a good look at how to spot the duds, and how to find better employment options.

I've fallen into the trap of several of these myself, over the years. From the "100% equity (but the product is totally unsaleable and we didn't bother to research that before you spent 23 man-days working on it)", to the poorly-paid legacy-code maintainer (plus guilt trips to keep me on even after having three months of unpaid invoices), to a job for a "web developer" (that actually mainly works on resetting our customer's forgotten passwords). So - it's definitely worth knowing how to spot these trucks coming before they run over you and leave you in the dust, bleeding financially.

Have you had any experiences of ghetto jobs yourself?

Tuesday 8 November 2011

Full-length feed: love or hate?

I've been reading a few other blogs on which people have mentioned that people prefer the full article in their feed reader. rather than just a short section and requiring a click to take them to the full article

I personally prefer the short version as I have a lot of stuff in my reader and hate dragging down hundreds of full-length posts when I'm likely to only read a few here and there via the reader, but it seems that a lot of people prefer it the other way.

So.. as an experiment, I flipped it over to the other way a month ago - to see if anybody noticed and changes the way they read. My site's not exactly high volume (maybe 1200-1400 uniques in a month), so not sure if the changes are really that massive yet, and I guess we can see as time goes on. But I'm impatient, so I figured I'd just ask. I'll happily accede to the wishes of the majority...

So: do you love it? hate it? even notice a difference at all?

Monday 31 October 2011

Yahoo group spam: how to avoid it

I've been getting a lot of this spam lately. Generally by receiving a *genuine* notification of having been added to spammy yahoo group along the lines of:

From: kgsqdj Moderator 
Subject: Welcome to the kgsqdj group


Hello,

I've added you to my kgsqdj group at Yahoo! Groups, a free,
easy-to-use service. Yahoo! Groups makes it easy to send and receive
group messages, coordinate events, share photos and files, and more.

...etc

I've been reporting them to spam-abuse as I go... but there is actually a solution to this (and don't hit the button at the bottom of the spam email).

You need to go to your yahoo groups prefs page: http://groups.yahoo.com/myprefs.Then for each email address you have listed, clieck "edit" and untick the box marked "Allow group moderators to directly add me to their groups".

If you really want to be in control, also untick the box marked "Allow group moderators to invite me to their groups."

This way you'll only ever join groups that you actually apply to join.

Tuesday 25 October 2011

( sad world (dead (John McCarthy)))

It's been a sad month for the computing world as we lose another great icon.

John McCarthy invented LISP and in doing was a pioneer of AI - contributing heavily to the field.

He will be greatly missed.

The register have written a better article on all his many contributions here: Father of Lisp and AI John McCarthy has died

If you're wondering how this relates to ruby - remember that ruby has been described as "an acceptable version of LISP"

Thursday 20 October 2011

Does Linux Tech Support exist?

I recently had some trouble with my internet broadband connection. I changed to another provider while overseas, and when I got back, discovered that something I'd installed had broken my at-home internet setup... so I was bereft of teh intarwebs[1] for day while I figured it out.

As is usual in this kind of situation, I first tried getting it working by myself. I googled, read forums and generally faffed about installing and uninstalling various internet and USB-related packages in an effort to get things working...

but I'm not really a sysadmin, so you could probably describe my attempts as "well intentioned flailing"

I tried all the things that people said to try - but more in a voodoo/cargo-cult kinda way... because really I don't grok these packages intuitively and don't really want to spend the time learning. I just wanted to get it running again so I could get back to work.

So I eventually gave up, and rang tech support.

Or I should say I tried.

I googled about to find about 5 or 6 "linux tech support" companies in England. I checked out their websites and dropped a few off the list (for saying they only supported setting up LAMP stacks), and called the others. Two of these also said they only supported servers fairly quickly, and the third did so also - but only after they tried to tell me to go speak to vodafone or Mac (like either of them would support linux!).

and I was left with the strange sensation of being totally and utterly alone.

Back in Sydney I have ties with the linux community, and no doubt I could find half a dozen people willing to offer help for real cash money. I'm sure that figuring out a dodgy device-connection is not their usual bread-and-butter... but it's still linux support.

So, why, in this country of so many millions of people is there not a single company that does not provide this service?

Or if it does... it needs better SEO. :P

Does anybody know of a not-just-servers linux tech support company in England?


PS: in the end, a totally non-linux-sysadmin friend from Sydney suggested (via a facebook chat) that I reinstall network-manager, and as I did so I noticed there was a "recommended package" for it that was not installed... no idea which fixed it, but I owe that friend a big hug!

[1] I wouldn't normally do this, but:
Thank you Starbucks for being there when I needed you!
I think your coffee is way too milky, but when I needed some free wifi and a warm place to endlessly reboot after reinstalling package-after-package... you were there for me!

Friday 14 October 2011

rubygems upgrade killed rails

Ack! I just tried to upgrade rubygems... and it destroyed my working version of rails 2.3.5 (yes, we use it for a client that has not yet upgraded due to the quite reasonable "it ain't broke" assumption).

Now I can't run script/server without one of the following errors: /usr/lib/ruby/gems/1.8/gems/rails-2.3.5/lib/rails/gem_dependency.rb:268:in `==': undefined method `name' for "Ascii85":String (NoMethodError) or /usr/lib/ruby/gems/1.8/gems/rails-2.3.5/lib/rails/gem_dependency.rb:119:in `requirement': undefined local variable or method `version_requirements' for # (NameError)

Chris Oliver provides a quick fix for getting back to a previously-working version in his description of the undefined local variable or method `version_requirements` and there's an active bug-report for the undefined method `name' for "Ascii85":String

For now, though, it looks like the only solution is to downgrade and hope for a fix... which seems to be coming only for edge rails. I really don't like it that I have to maintain and old version of rubygems just so that I can run my client's perfectly functional rails stack. :(

Friday 7 October 2011

Jobs lost to the world

A moment of silence for the passing of Steve Jobs.

:(

They always say of businessmen that "oh he was a visionary and great leader"... but Steve Jobs really was.

If you need a reminder of all the amazing things he did, there's a nice post outlining Mr Jobs' legacy on gizmag

The world is a little less bright without him.

Thursday 6 October 2011

Rendering an rjs partial from a controller action

I've recently been working on sharing some AJAXy controller actions between an admin and non-admin controller set up in completely different parts of a site, and this required the ability to use shared rjs templates. Tis is what I found out.

Lets say you originally have an erb and rjs template thus:

   # original update_widget.rjs
   page.replace_html "widget_wrapper", :partial => "widget"

   # original widget.erb
   <div id="widget_wrapper">
      lots of cool stuff here to show off your widget
   </div>

You need to pull that rjs out into a partial template called _update_widget.rjs as below.

Note the full path-name for the partial - this is so we can share this template across controllers

   # new update_widget.rjs
   page << render(:partial => 'widgets/update_widget')

   # new partial: _update_widget.rjs
   page.replace_html "widget_wrapper", :partial => "widgets/widget"

Now to call an rjs template from a controller action you use the syntax as below:

Note: this is what you put in the new controller, the original controller (in this case it'd be widgets_controller) will still default to using the action-name to find the rjs template

   return render( :partial => 'widgets/update_widget.rjs') # the '.rjs' is essential

Thursday 22 September 2011

Links: The Truth (and Myth) about passive income

I've also read The 4-hour work week and dreamed about relaxing on a tropical island while the money pours in... but the truth is that it's actually a lot of hard work to get to that stage.

The biggest myth surrounding passive income is that it's a "set and forget" strategy. The truth is that it does actually take a lot of work, up-front to get that ball rolling.

Nacie's article weighs up whether passive income is all it's cracked up to be.

Too many people read "four hours" and think that passive income is the *easy* path to success... far from it. You'll most likely get far more up-front cash coming in via a traditional entrepreneurial route. Sure, some superstars will hit it lucky up-front and be an immediate smash, but for most of us working-joes, "passive" is all about building over the long-term; and keep in mind that it will take a long-term effort to get a full-on passive cashflow. In the meantime, you'll probably have to start with a more traditional business or job until your passive streams grow enough to be sustaining.

Have a look at what Steve says if you want to know the real consequences of trying to take the easy route when launching your own business.

Now, don't take all this to mean that "4 hours" is all a lie. As far as I'm aware, it never states that you can make money with no effort at all - or that you'll even make more money that way than the traditional routes... It's quite clear that it's handbook about really useful ways of simplifying and delegating as many parts of your business as possible. The main point being that you are building a "maintenance free" business, rather than a "totally effortless" business.

It's definitely true that people *can* make passive income work this way. Just keep in mind that it won't happen overnight and it's won't happen with absolutely no effort at all.


Anybody here have experiences with putting into practice what they found in "four hours" or any other version of a passive income stream? How did it work out for you?

Friday 16 September 2011

my travel countries

I've been doing a lot of travel recently in Europe. My visa runs out here in about six months, so I'm well aware that I have only a few months left to see as much as I can before heading home to the antipodes.

I found this neato travel map that lets you show the countries you've visited... but it makes all my recent travels look very tiny. Most of the red here was clocked up on other trips years ago. I guess that shows you just how amazingly huge the world really is!


visited 18 states (8%)
Create your own visited map of The World or another interesting project

Friday 9 September 2011

No implicit consent! Dos and don'ts for email addresses you find on the web

Like many people with an online presence, I have my email address plastered up on the web for all to see. I do it because I do want people to get in touch for business or friendly purposes.

However, there are a few myths out there about what that "means" for the purposes of taking a copy and using it for you own ends.

After a long email conversation with a man who got a few aspects of this very wrong... I thought I'd put up a quick list of dos and don'ts for using email addresses found on the web.

The myth of "Public domain"

A lot of people have the wrong idea about the web. They assume that because you can freely access a website... that means it's covered by the magic blanket called "public domain' that lets you take anything you find and use it yourself... including email addresses.

This is not true.

Let me give the example of a "public building" such as a free museum. A public building is open to any members of the public. but just because they don't charge entry, does not mean you can come in and take the artworks off the shelves and take them home. They still belong to the museum.

In this same way - just because you can easily come to a website, does not mean that anything you find there is yours for the taking. Your stuff is actually copyright. All of it!

What copyright means is that another person cannot just grab your stuff (whether the pictures words or even personal details such as email) and use it without your permission. Specifically, they cannot copy it, and especially cannot use it and put their name on it. It is *not* free for public use.

Anything you write or create is *automatically* covered by copyright law. If you create it, you own it. Automatically. You don't even need to say "copyright". It already is the moment you first wrote it down. This goes for a poem you write on the back of a napkin, a drawing you scribble in your diary or a website you build and keep on your own server.

Now, some people aren't as aware of copyright law as others... so there's this convention of putting a copyright notice on your website... just to make sure people really know that this stuff belongs to you. Just like the little roped off areas in a museum - they don't really stop anybody, but make it clear that entry is unwanted.

It actually isn't necessary - your stuff is still copyright without that notice - but I see the sense in it, and do it on my own website, just as a reminder to newbies that "you can look, but don't touch".

So, what actually is public domain and how do we put things in it?

If you've ever used wikipedia, and actually had a go at editing a page... you'll know that you actually have to agree by their terms and conditions... including agreeing that anything you contribute no longer belongs to you - and has been put in the public domain. A notice on the site declaring it as public domain isn't enough (because people frequently don't read notices). You actually have to check a box and hit "submit" before they'll accept that you have agreed to their terms.

This is how things get into the public domain... by you clearly agreeing it as such.

On flickr you can put things into the public domain... or share them using the creative commons license (which does roughly the same thing at the most forgiving levels)... but again, you must physically do something to put something in the public domain... and everything else is considered copyright.

... but you should now understand that you actually have to *actively* do something to make your stuff go into the public domain. The default case is that your stuff is not available for anybody to just grab for themselves.

What does this mean for email addresses?

Well, email is tricky in some cases. You have put your address out there as a method for people to get in touch with you. So you can't then complain if they do.

However, there are some obvious social implications of exactly how that works... and there are definitely some legal implications surrounding the concept of spam.

Firstly: it is illegal to send any unsolicited email to a person.

Your consent must be given to get in touch with you, and even if you put your email address up on the web, there is *NO* implied consent for that. You have not given up any rights by making it publicly viewable.

If I put my email up on my website and literally write next to it "use this to contact me about business opportunities"... and then get spam about pills... I can legally say that this was unsolicited. It is quite clearly *not* what I asked for.

If I get spam about "work from home using your computer"... then it's more of a grey-area. It is in fact email about business opportunities, and I can't complain about that. So - make it clear what your email is there for.

but if somebody tries to send you any other kind of "helpful free information"... you now know that they are misbehaving.

Secondly: you cannot be automatically signed up for a newsletter that you did not subscribe to.

The exact legality of this varies depending on your country. But in the UK - you cannot be automatically signed up for a mailing list that you have not requested.

...unless you actually left your email address with the company that is signing you up.

ie a company that you have voluntarily handed your email address over to (say, during purchasing online) can sign you up for *their* personal email newsletter, without asking. But they *cannot* hand your email address to a third party[*] for spam or mailing lists. You have to have given a company consent for them to get in touch with you... and consent is not transferable.

Also - a company cannot come to *your* website and *take* your email address and use it for their mailing list. You have to have handed the email over to them.

Now there's a grey area here that companies often know about, but individuals don't... you don't have to have handed your email address over for the express purpose of signing up to their newsletter. You could have handed it over just as yet-another-mandatory-field in their uber-long registration form. It doesn't matter. They are legally allowed to use it... as long as they provide an opt-out mechanism.

But companies shouldn't do this anyway!

Companies should not abuse their mailing lists by opting people into newsletters.

People are busy enough as it is, with a metric crapton of mailing lists from work, social groups, friends and family. They don't need one more. It is considered rude to opt people in to your mailing list without asking their permission first.

It is damaging to your brand!

I totally understand wanting to get your message out to people... and I am *not* against getting in touch with your hard-earned customer base. So what I suggest you do is adopt an *opt-in* (rather than opt-out) policy.

Write the email-equivalent of a warm-call: "this is new widget that we're offering, we have this neato newsletter about it, and we think you'll be really interested because you were interested in widgets from our company before... are you interested in signing up?"

Then let them choose to ignore it if they wish!

Will you get fewer "subscribers"? YES! but will it make a difference in actual turnover? UNLIKELY! the people who were going to ignore your message were going to ignore it anyway. You've just bugged them for a few more months before they finally caved and hit "unsubscribe". and probably get annoyed at the horrible unsubscribe interface (like everyone does), further damaging your brand in their eyes.

What you're left with instead is a set of people that are *ACTUALLY INTERESTED* in your product.

Take a moment to think about how valuable THAT would that be to you!

Think of it as an effective way to find your tribe of true believers... and maybe get yourself a copy of Seth Godin's book Tribes, while you're at it.

To sum up:

An email address on the web does not mean that you can spam it, or sign it up to even a really useful, helpful newsletter. There is *no* implied consent. Feel free to get in touch, but make certain that it's:

  1. appropriate to the person and
  2. opt-in only

* Third Party opt-ins Note that a lot of company online purchasing processes have one of those nearly-hidden checkboxes talking about "third parties" for exactly this purpose... they are a sneaky way of pretending that you "opted in".

Tuesday 30 August 2011

Link: training self-discipline

As a telecommuter, I well know the struggle with self-discipline. It's very hard to keep away from all the regular home-distractions and actually get down to work. But it's a necessary part of every day life.

This article on training self-discipline has some good tips on how the author has been working towards better self-discipline, and also some good general discussion on the benefits.

I especially agree with his point that you need much more discipline if you have large amounts of freedom. I remember it being much easier to get down to work when I had to actually get up and go into the office at a set time each day.

Anybody else here telecommute? Do you do anything to wok on your own self-discipline?

Thursday 25 August 2011

Emerald isle and censorship link

Hi all - sorry I've been quiet... I've been away on holidays in Ireland, learning how to pour the perfect pint of Guinness :)

There's several comments I need to reply-to, but my schedule's all haywire due to the holiday and my birthday plans... I'll get to you eventually I promise!

In the meantime, gizmag have posted an article abut an plan to let people in heavily censored cultures (eg China) get past the censorship with an interesting protocol called Telex that hides requests in the HTTP headers of normal, uncensored web requests. Kind of an interesting idea. Enjoy

Monday 15 August 2011

Life at 36

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 in my diary and day-dream about movies; making up adventure stories or inserting myself as a character in my favourites.

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 drifting 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 moved interstate by myself, to see the Big City. 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.

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 achieve 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, 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 loved planning what to do with my life, and choosing to gather interesting experiences around me - New Zealand, the Northern Territory, Thailand. I learned photography, spanish and investing. I watched a *lot* of DVDs.

When I was 34 I moved internationally by myself. I loved exploring in a new country: visiting ancient ruins and watching Shakespeare at the Globe. I enjoyed getting better at photography, meeting new people and seeing new places. I built 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 loved pottering around in my allotment late into the long, english summer nights.

When I was 36 I loved getting about europe in my first car; learning French, and then eating my way around the French countryside. I enjoyed picking fresh fruit/veg from my allotment and making blackberry pie. I loved the lazy schedule allowed by working from home, and lazy Sunday afternoons drinking velvety latte with a Cranberry-and-orange muffin at my local cafe in Windsor, in view of the castle.


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. I also like to do it to remind me of the good things in life - which can be so easy to forget sometimes.

Friday 5 August 2011

Crocker's rules

Declaring yourself to be operating by "Crocker's Rules" means that other people are allowed to optimize their messages for information, not for being nice to you.

I love it.

I now declare that I operate under Crocker's rules. Call me out on my bullshit - I want to know the real truth. Especially call me out (and remind me of this post) if you see me having a problem operating under Crocker's rules themselves.

I think I have been subconsciously operating under these rules for quite some time now. Admittedly - I also use them (a lot) on other people... even if they haven't asked for it. It is debatable whether this is a Good Idea.

I still find it a much easier atmosphere to work in - if you don't have to go through backflips of pleasantries just to say something without accidentally insulting the other person: not because what you're saying is insulting - but because you failed to put in the correct, socially-acceptable amount of padding...

Compare:

"hi there, how are you, hope your holiday went well. By the way, you know a few weeks back you borrowed my stapler. I was wondering - if you have finished with using it, that you might possibly find some time to bring it back? If that's ok. thanks a whole bunch.. love to the kids - T"

vs

"hi, could I please have my stapler back? T"

The full set of Crocker's rules here

How about you? Do you dare take the challenge? Disagree with the whole concept?

Friday 29 July 2011

Link: Computer Stupidities

I've just come across: Computer Stupidities. Its a lot of fun. I think my favourite so far is:

When I was studying programming, one of my classmates was having serious troubles with his program. When he asked me for help, I leaned over his screen and saw all of his code in comments. The reason: "Well, it compiles much faster that way."

Much like Daily WTF... though most of the CS stories are very early era

Warning! Time sink!

Sunday 24 July 2011

Who Cares About Forecast Accuracy?

Corporations and governments spend staggering amounts of money on forecasting, and one might think they would be keenly interested in determining the worth of their purchases and ensuring they are the very best available. But most aren’t. They spend little or nothing analyzing the accuracy of forecasts and not much more on research to develop and compare forecasting methods. Some even persist in using forecasts that are manifestly unreliable. … This widespread lack of curiosity … is a phenomenon worthy of investigation.

An eye-opening article by Robin Hanson, called Who Cares About Forecast Accuracy?, describes how and why corporations spend heaps of money on making predictions... but almost none on testing whether those predictions actually worked out.

The article discusses the fact that actually recording the accuracy of pie-in-the-sky forecasts means that it's much harder to hide a poor track-record for leadership. That a lot of forecasting is more about signaling affiliation to the company ("yeah, we're doing great, I predict we'll be done by tomorrow!") than actual accuracy. Quite possibly just another effect of bosses preferring overconfidence to accuracy.

From my own experience - I find that many "leaders" don't want you to say that the project might be in trouble... and the article discusses how this can happen because the middle-managers don't want somebody to go on record as having questioned their vision... because it'll reflect badly on them down the line should something go wrong. It's much harder to sweep losses under the carpet if nobody officially takes notice of how often it happens.

I think there's also another reason, not mentioned in the article. That being the long-term vs short-term payoffs. The strategic echelons of an organisation need your predictions so that they can make their own overall predictions of how long a plan will take to implement. But they don't want to bother with the long-term cost of implementing a full system with all the process-change and downtime that it will take. I've personally found it extremely difficult to "sell" both management and fellow-programmers on changing to to a methodology which will allow for recording and feedback of prediction accuracy. These are methodologies that aren't particularly heavy or difficult to implement (compared, say, with six-sigma), but which provide a quick and easy way to get better at providing an accurate estimate of your times.

The problem seems to be, that it takes more time and effort to implement, and people don't want to do the "work". They want to make their guesses *and* make t more accurate... but not to have it impact the "bottom ilne" in any way. This is a bit like saying "we'd like to buy faster computers, but won't give you any budget for their increased cost". You somehow have to just improve anyway.

What normally ends up happening is that you don't properly implement any system of accuracy, so you end up simply guessing and just hope for the best. Actually spending the effort to make those guesses meaningful is too much like hard work, and nobody wants to add to their workload. This is understandable... but not exactly helpful (or realistic). Instead of improving over time, we continually wallow in a world of wild guesstimates and "fudge-factors" that never seem to quite cover the extra time it always seems to take.

To get back to the article, Hanson suggests that we use a betting-system to literally "put your money where your mouth is"... the intention being that if you personally stand to win/lose by your prediction, then it would be in your best interest to start being more accurate.

I think I'd balk at my own actual money, but I'm sure some kind of system could be set up for "points" where you "win" various rewards (eg an extra day off, or even just the ability to work on "the fun project") if you do especially well.

Has anybody had any experience with estimates and measuring their accuracy? Either from the trenches or the strategic side of things?

Tuesday 19 July 2011

Freedom

To me, freedom is the ability to choose my own timetable; to choose in which direction I can travel, and what level of quality to aim for. Freedom does not mean being completely unburdened (as you cannot go very far when you choose to do nothing). It is the freedom to choose which burden to carry - rather than accepting the one forced upon you.

We are all constrained to one degree or another. I'd rather choose my own constraints than to wear shackles chosen by others.

What does freedom mean to you?

Tuesday 12 July 2011

Consulting harms your chance at founding startups?

Consulting is like selling crack. If you get hooked on the consulting lifestyle (and income), it can be hard to give that up to work on your own startups, yet many people get into consulting with the dream of working on their own projects on the side.

Yet it seems that consulting work can actually be detrimental to your startup-founding prospects. Read more from the original article

I have to admit I've fallen foul of this myself. It's very hard to prioritise spending a lot of time on a "maybe it'll go nowhere" startup, if you've got definite paid work to do right now (especially if it's well paid). In my case, my startup is MatchFounders, a site dedicated to matching potential founders for startups.

When prioritising, the "bird in the hand" mentality kicks in automatically - and there's a lot to be said about that particular proverb. But I also have to think hard about whether or not I'm selling my long-term future for short-term cash results.

It's not an easy choice to make, by any stretch.

Just how much do I want to work my own startup (and build something for the future) vs current, well-paid consulting.

Don't hold your breath for an answer - I'll probably struggle with this for a long time. But it has served as a reminder that I also have my own ideas on the boil - and should maybe give a little more love on their behalf.

What about you? Are you struggling to make the choice? Have you already made it? Do you have any advice?

Wednesday 6 July 2011

What's your opinion?

I've recently read the Jeff Atwood's post: A blog without comments is not a blog, and realised that, while I don't have comments turned off - I don't exactly go out of my way to encourage much commenting on this blog.

I'd just like to say that I really do want to hear your opinions on the stuff I say. I'm frequently quite opinionated, and more often wrong than I like.

I may not give this impression, but I like to hear what other people say about a topic to get other points-of-view or even just to figure out my own blind-spots (by having them pointed out to me by somebody else).

So I've decided I should do what I can to encourage more frequent commenting here.

I'm not entirely sure how to go about it... but I figured I should start with a small change. From now on, I'm going to try and end each post with a question - in the hopes of sparking a conversation about what I've been talking about. Maybe it's a dumb idea - but I figured I should begin somewhere.

Does that work for you? If not, what does? Do you have other examples of good ways of getting regular comments on a blog?

Friday 1 July 2011

How to find technical co-founders

Jason Freedman has clearly been asked one too-many times how to find technical co-founders and has written this excellent post so people will please please please stop asking how to find technical co-founders. :)

Fun to read if you are technical and, from my perspective it seems really useful if you're looking for one.

Monday 27 June 2011

EU cookie law: in video

A while back I pointed out that a new law about cookies was coming out. Well, that passed into law in the UK on 26th May 2011.

It is now illegal to have cookies on your website without explicitly asking for permission.

That includes your google analytics tracking tags!

Luckily, they've realised what a pain it is to update your website, and have told everybody that they will not actually prosecute anybody with this law for a year... as long as they are actually doing *something* about the issue.

It also makes sense to start thinking about now, if only to make sure we're not all madly stuck trying to rectify the problem at midnight May 25th next year.

Of course the problem is that there is still no consensus on what we actually need to *do* to meet compliance. The ICO's guidance on the topic still being woefully inadequate.

There's more from the Guardian on the cookie law shambles.

and here's a great YouTube video that briefly describes the whole issue.

Monday 20 June 2011

What the hell is happening with Rails?

A whole slew of controversy has been stirred up with the post: What the hell is happening to rails - which managed to top the hackernews charts for quite a while last week.

It basically gave vent to a lot of concern in the rails community that rails is becoming too difficult to learn, and that may be scaring off newbies.

The new rails has certainly been in a great state of flux - and pushes the whole framework in a new direction. Whether or not you like that direction is one thing - but the fact that it is such a big change makes it difficult to know where to start if you're coming into the community for the first time.

I recently had an eye-opening experience at a hack-day where I suggested rails as a platform-of-choice for us to use... then spent the entire day helping one guy just get a basic rails stack up and running on his laptop, and then I still had to explain how to actually use it.. This isn't as easy a I remember when I first began.

One of the big benefits of original plain-ole-C was that anybody could learn the entirety of the language and keep it in their head all at one time. Contrast that with any of the big enterprise languages, which require a long ramp-up time even just to learn everything that is available in the basic suites. Not that having less is better - but it does make the early-learning stages much quicker... so I can see the point being made here.

In any case - I think the gist of the post/discussion is worry over the potential dilution of the framework. If we want to be all things to all people - it means a lot of work to genericise the platform, and that means big changes.

On one hand, I can see why it's being done. There are good reasons for all of the alternatives to the core-defaults... and being able to support them therefore opens up our audience to a greater market. But I can also see the point that it makes Rails *feel* a lot more bloaty than before... even if it isn't actually degrading performance, and it gives newbies so much more to learn just to get out the starting gates.

In any case - Yehuda Katz has now done a follow-up post explaining just What’s Up With All These Changes in Rails? - and it's worth a read to see why they've made some of their recent decisions.

and I plan to watch the continuing discussion closely...

Saturday 18 June 2011

Goal-oriented vs process-oriented motivation

There are heaps of processes that I enjoy far more than the actual end-result.

Crochet is my example.

I'm quite happy to continue crocheting something pretty (it has to be pretty - I don't enjoy crocheting abominations) for a long time and never "owning a crocheted thing" at the end.

Before I hit upon the solution, I spent a long time starting projects - some of which I finished, but lots I didn't... because I didn't care about finishing - just about doing. Of course, couple this with an aversion to destroying something I've already made (which might have solved the problem by turning it into a sisyphean task). and I got a lot of "why don't you ever finish anything?" from my mother.

The question usually comes as "why don't you ever finish anything, don't you want the [crocheted thing] you set out to create?" - and the honest answer is "no".... but if you say that - they ask "well why did you start making it in the first place?"

Most people don't seem to understand enjoying the process - at least not on a gut level...

I actually solved this particular dilemma by giving away my crocheted things to my grandma - who likes owning crocheted doilies et al. Works for embroidery projects too.

Unfortunately, I still tend to get lack of understanding from other people: "but why don't you ever make something for yourself?" I find it *very* hard to explain to goal-oriented people why I don't like crochet... I like crocheting.

I would definitely consider myself to be more process-oriented than goal-oriented. I like doing stuff... I like crocheting, not the goal of having crocheted something in particular. Especially, I like learning - not the feat of "having learned something".

So for me - it's very difficult to go to those "attain your goals" seminars etc - because I don't have set goals. I can't point at something and say I want to have achieved precisely that thing, because for me, the thing itself doesn't matter.

It can be frustrating, because I certainly do want to improve over time. I crochet better and more complicated things, I study more challenging topics that build on past learning that I enjoyed. but I can't necessarily quantify that I want to "learn X".

Because there is no X... or at least no specific X.

and then people tell me I'm drifting and that I'll "never accomplish anything"... but accomplishing specific things for me isn't the point. I enjoy the act, not necessarily the achievement.

Of course, over time, I *do* accomplish things - because if you continue to, say, crochet over a long period of time, eventually you will have piled up a very large back catalogue of doilies... and the same goes for learning or whatever other process you enjoy. Which I can then, of course, show to my mother...

who then invariably says "but why don't you finish the ones that are still in your cupboard?"

*sigh*

Friday 10 June 2011

Project Euler

I've found a fun new site. Project Euler is a huge set of math+programming puzzles of increasing difficulty, starting out pretty easy (solved by tens of thousands of participants) and going up to puzzles that haven't been solved yet.

They're quite fun. Each one touches some aspect of mathematics, and requires some programming smarts to get it working. But don't worry if you're not cluey on maths. They start out fairly simple, and you can google for information about the math behind the puzzles if you need more.

Each puzzle has a specific, numerical answer. You submit the answer to prove you've solved the puzzle, and the site keeps track of how many you've done. It also gives you access to a forum for each puzzle - where others share their code or insights into how to make the program more efficient. Most puzzles also come with a short pdf to explain the maths behind it - generally showing you how to analyse the problem or prove the formulae behind the most efficient algorithm.

Each puzzle has been constructed so that the correct program/solution is expected to run in under a minute... and for many of the puzzles - that means you'll have to rethink how your program works to get in under that time.

Anyway, I think it's an interesting challenge to play with. Here's my score so far:

Sunday 5 June 2011

ruby encapsulation is for $%*t

Wow, I just learned that ruby encapsulation can be broken by simply using:

   my_object.send(:my_secret_private_method)

That's kinda useful to know if you're trying to unit test a private method, but makes the concept of encapsulation totally meaningless in ruby.

Apparently, Ruby 1.9 revokes this "special" privilege, but then there are still many ways to use the power of ruby meta-programming to get to them anyway (see above link for some examples).

Wednesday 1 June 2011

Autologin to rubyCAS after create user

From restful_authentication I first got the idea that when a user signs up they can also be automatically logged-in. This as opposed to having them register - then sending them to the login page where they have to re-enter the details they just typed into the registration-form.

Unless you have some kind of click-on-the-email-activation-code-before-logging-in requirement, you shouldn't force your user to go through this dance. It's a tiny nice-to-have that (if all goes well) ends up with a more seamless experience for the user - all win.

If one of your rails apps also deals with signing up your new users - you should be able to mirror this autologin functionality to smoothly get them started straight after registration.

At first glance, it looked like rubyCAS didn't support this - or at least not easily... but it's all tied into the same functionality as logging-in via a form. Autologin uses the same login_to_service method in your create action. You should already have the user's login credentials, so post them to the service and redirect them to whatever "getting started" page they should begin with. You can even just reuse the same cas_login action itself.

So, in the action that creates/registers a new user, add this at the end:

  def create
    # creating a new user code goes here
    if success?
       redirect(cas_login_path(:login => @user.username, :password => params[:new_password]))
    end
  end

Just don't forget to use the pre-encrypted password. :)


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

Thursday 19 May 2011

How not to invite me on LinkedIn

I'd like to add you to my professional network on LinkedIn.

- J Citizen

I hate that... I really do.

So - who the hell are you? and why should I add you to my LinkedIn? and is it really so hard to type just a few words into the text box?

If we've never met before - I don't know you from Adam. If you couldn't be bothered writing a few words about why we should link up - why should I be bothered accepting your invite?

Unsolicited invites with no effort read as SPAM to me, and will be ignored.

I find this particularly common from recruiters trying to fish for Rails developers. Yet the very people you most want to hire are the most likely to ignore a "form-letter" style invite. How many potential goldmine recruits are ignoring you because you didn't put in the effort to explain who the hell you are?

Or maybe I have met you - do you know how common some names are? Like most geeks I'm *crap* at names and I apologise, I've probably forgotten yours... it's nothing personal - but I've met thousands of people in the past year.

You and I probably hit it off at some networking event and we had a great conversation about your new startup and how we could work together... but that doesn't mean I remembered your *name*, it means I remembered who you *are*. Unfortunately, LinkedIn invites only show a name... so you'll have to remind me of who you are... it only takes a few words:

Hi, I'm John, we spoke at Launch48 last year about my new startup FuzzyKittens.com. 
I'm looking for an awesome Rails developer to help on my project. 
Add me to our network?

- J Citizen

*so* not hard.

Wednesday 11 May 2011

Travel Hacking Cartel

I've been doing a *lot* of travel the last couple of years: taking advantage of my stay in the UK to see as much of Europe as I can before I have to head home to Aus.

Mostly I've been traveling on cheap airlines or even driving. However, I've just joined a website that helps you collect airmiles at a much increased rate. They guarantee that you'll gather a minimum of 100,000 airmiles a year (even if you aren't based in the USA) which adds up to at least one significant trip each year.

They find the deals for you and list them on the member homepage, and you then go and collect your points and mark them "done". The claim being that you only need to spend half an hour each month gathering your points. Seems fairly good so far, but I'll let you know as I go along if I think it's worth it.

If you're interested, click on the linked image below.

Official travel hacker

Friday 6 May 2011

admin_login_required filter for rubyCAS

Setting up an admin-only login for rubyCAS is fairly straightforward.

First, you have to add an "is_admin" boolean flag to your *local* user class. Remember that you will probably want to restrict admin-rights differently on different applications - so it's better to put it in the local db for this.

If you are really sure that you want universal admins - then you can look into using the "extra attributes" aspects of rubyCAS - but I won't cover this here today.

Now it's just a matter of adding this helper-method to application_controller.rb (note, this depends on logged_in? and current_user)

    # overload the restful_auth version
    def admin_login_required
      # send them to 404 so we don't leak the page's existence
      # Note: implementation of this method left as exercise for the reader...
      render_four_oh_four and return(false) unless logged_in? && @current_user.is_admin?
      true
    end

Now you can add this as a before_filter to whatever actions you need... but make sure it comes *after* the actual login filters eg:

  class MyController < ApplicationController
    # this is the before_filter provided by rubyCAS client
    before_filter CASClient::Frameworks::Rails::Filter
    # this is a call to our own new before_filter which populates the cas user
    before_filter :setup_cas_user

    before_filter :admin_login_required, :only => :admin_homepage

  
    # actions here
    def admin_homepage
      # load cool admin-only stuff here...
    end
  end

To actually update that flag - you'll need to have local versions of user CRUD pages as per any other CRUD pages - affecting the local user values.

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

Thursday 28 April 2011

Gateway filtering in RubyCAS

Gateway login pages are ones where a user doesn't need to be logged-in... but if they already *are* logged in, then we want to know. Example: the help or contact-us pages are available to non-logged-in users.

Often we want to write these pages using the existing templates so that if they aren't logged in, the templates are fairly simple, but if they *are* logged in, then you display the usual logged-in navigation links.

So you need a filter that will auto-authenticate a user *if* they are already logged in, but doesn't *require* it. The standard CAS-login filters will actually redirect non-logged in users to the login page - and we don't want that happening. So we need to write a little filter-magick using the CAS GatewayFilter.

class WelcomeController < ApplicationController
  # don't *require* login for the public pages (inc actual login page)
  skip_before_filter CASClient::Frameworks::Rails::Filter, :only => [:home, :contact_us, :terms, :cas_login]
  # instead use gateway-login filter
  before_filter :cas_gateway_login, :only => [:home, :contact_us, :terms, :cas_login]

  # ... lots of actions and stuff here

  #####################################################################################
  private
    
    # This before_filter method is used to both call the GatewayFilter and
    # also to then call the setup_cas_user method.  Note that the latter
    # will already have been called on an action, but as we declare the
    # GatewayFilter *after* this, it must be declared again.  So we use this
    # method to make sure that we do both of these in the requisite
    # before_filter.
    def cas_gateway_login
      return false unless CASClient::Frameworks::Rails::GatewayFilter
      setup_cas_user # setup @cas_current_user etc for use by other methods
    end
end # controller

After this, you can use the logged_in? method to determine whether or not to display extra navigation features.

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

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.