What do comments mean?

I mean really. What do they mean.

Specifically, what does this comment mean:

// Load the person

Which of the following gives the most correct interpretation of that comment?

  • The following code loads the person
  • The *intent* of the following code is that person object is loaded.
  • The following code *may* load the person
  • The following code used to load the person
  • The programmer thinks the following code loads the person
  • The programmer used to think the following code would load the person
  • The following code almost certainly doesn't load the person
  • The programmer once typed "// Load the person" at this point in the code
  • The programmer once copied and pasted "// Load the person" into this point in the code
  • Maybe, at this point in the code, a code generator once created a comment that says "// Load the person" or maybe an automatic merge went bezerk and put that comment there; maybe a programmer copied and pasted the text in, but in any case there's a slight chance that the following code may once have had some intent vaguely related to loading, or unloading, or otherwise tampering with an object, possibly of type person or people or, more likely, something else altogether.
  • There is a comment at this point in the code that reads "// Load the person"

Spaced Repetition Software... for Kids!

There's no getting away from the fact that kids have to do a hell of a lot of rote learning.

As much as we want our kids to be taught to think for themselves, and to develop imagination and creativity and all of the stuff that makes life good, they still need to commit a lot of facts to memory from a very young age.

It's no good calculating "4 * 4 = 16" from first principles every time you hear it. You need to memorize it, and memorize it for life.

Thus it's important that kids are given efficient tools for memorizing all the things that must be rote learned. The most effective tools for memorizing facts rely on the 'Spacing Effect' with techniques such as "Spaced Repetition". Adults use "Spaced Repetition Software" for winning at Jeopardy or, more commonly, learning a language.

graph of memory strength decaying slower with each spaced stimulus

In a nutshell the spacing effect says that you if you are forced to recall a fact right when you were on the verge of forgetting it, you will remember it for longer.

So it occurred to me that there must be some great Spaced Repetition Software for Kids, that I could use to help my kids learn all the boring stuff.

Google Says No.

I searched and found none. Zip.

Google Keyword Tool Says No.

Then I thought, maybe I should write some! I wonder how many people are searching for this stuff every day? So I checked with the Google Keyword tool, to see if there were thousands of parents out there desperately searching for "Spaced Repetition Software." Google Keyword Tool Says No.

Twitter says No.

Then I thought, maybe it's a latent idea, an idea that is growing in people's minds but they haven't yet reached the point where they search it out. So I proposed the idea on twitter, to see if other people were looking for something like this. Result: almost no response.

So at the end of that research, I dragged it from my "urgent this must be done yesterday" trello board into my "long term someday maybe" trello board.

Note that I didn't validate the idea, or my ability to execute it. I just probed to see if there was an existing market, and it got three strikes. I don't need to validate the idea. Here's the thing: I already know it's a brilliant idea. Seriously, it is. Can I execute it? Probably not very well, since I've never made apps for kids before. But the idea is ahead of its time and the market does not yet exist. So I can't afford to indulge the idea right now.

But plan B is much simpler.

Some day a mega-celebrity will talk about spaced repetition and how it helped their child learn Esperanto at age 3. And suddenly the whole world will be searching for "Spaced Repetition Software For Kids". And they'll arrive, in unison, at this very web-page. Whereupon I'll derive a decent royalty from directing every last visitor to the best "Spaced Repetition Software for Kids" available in that future age. ;-).

(Incidentally my 7-year-old had fair success at using 'Anki' to memorize some times tables. She was relieved when it quickly reached a point that it said "And that's all the memorizing you need to do today." If only teachers would be so wise.)


Solving An Air-gapped Traffic Mystery

Over the last few days there was a sudden uptick in NimbleText sales. Normally this kind of thing happens either when I've put out a new version or when I've been sent traffic from some popular source (as happened last christmas when Scott Hanselman listed NimbleText as one his top 10 most useful utilities in his much-loved Tools list).

On this occasion, looking in Google Analytics, it was a bit of a mystery. There were no new referrers. More bizarre: the traffic spike was caused by an increase in organic search traffic. In particular, it was an increase in people using the search term "NimbleText". (My most popular search term is usually Text Manipulation)

So this meant that something had happened, out there in the world, that made people spontaneously search out NimbleText. There was a stimulus, then an air-gap, then people searching for the product. It could be that someone put up a billboard in Times Square... except that would be revealed by geolocation. It could be a mention on a podcast, it could be any other "offline" channel.

Fortunately, I'd set up google alerts to notify me whenever google found an article that mentioned NimbleText. And I remembered a notification had come through recently. The source of the traffic was this piece at Visual Studio Magazine. It mentions NimbleText, in glowing terms, but doesn't link out at all. So a bunch of readers must've been inspired to perform their own search.

The lesson is that google analytics won't show you the source when there's an air-gap. In this case, Google alerts was the necessary tool. So if you have a little product, set up alerts for those too.


Using the commandline to write a book

As I've mentioned many times already, I'm currently writing an ebook, "Your First Product", to help people like you to build and promote your first software product.

I have a daily target to write 200 words toward the book (which I smash! ;)). And I track my progress using a short powershell script that also commits what I've written (to mercurial).

Here's the progress currently, as output by ".\count.ps1", my count and commit script.

2014-10-01,words:22515, tasks: 85/130
2014-09-30,words:21896, tasks: 85/130
2014-09-29,words:21467, tasks: 85/130
2014-09-28,words:21246, tasks: 85/130
2014-09-26,words:20925, tasks: 85/130
2014-09-25,words:20707, tasks: 85/130
2014-09-24,words:19496, tasks: 80/126
2014-09-22,words:19109, tasks: 80/126
2014-09-21,words:17898, tasks: 82/128
2014-09-19,words:17323, tasks: 82/128
2014-09-18,words:16211, tasks: 82/128
2014-09-17,words:15194, tasks: 82/128
2014-09-16,words:14824, tasks: 82/128
2014-09-15,words:13479, tasks: 82/128
2014-09-14,words:12463, tasks: 82/128
2014-09-12,words:10854, tasks: 82/128
2014-09-11,words:9571, tasks: 82/127
2014-09-10,words:6900, tasks: 79/124
2014-09-09,words:5274, tasks: 79/124
2014-09-08,words:4585, tasks: 79/124
2014-09-07,words:3237, tasks: 78/121
2014-09-04,words:1548, tasks: 62/95
2014-09-03,words:1217, tasks: 52/74
2014-09-02,words:697, tasks: 22/41
2014-09-01,317 words
619 words today (309.5%), 0 tasks today

I've made 290 commits, but count only shows details from the final commit on each day. And it compares yesterday to today to come up with my today's progress.

Here's the .\count.ps1 script itself (and the .\progress.ps1 script which it calls).

I have another script, ".\stats.ps1" that I call to see the number of words in each chapter (from biggest to smallest), another called ".\chapters.ps1" which gives me a basic table of contents, and one more script, ".\bake.ps1" that converts the markdown into an epub (using pandoc).

These are all very very rudimentary. Any effort I put into them is effort that I'm not putting into the writing itself. But I would love to make them a whole lot better.

I'd love to have graphs. Right there in the console. Or alternatively, pop-up graphs.

I'd love to have git versions, as well, instead of just mercurial. And bash versions, and node.js versions instead of just powershell. And versions for people who write TeX, not just markdown, and so on.

I'd love to be able to plug-in other metrics! Instead of just measuring words in markdown files and [_]'s in "todo.txt" files, I'd like to measure lines of code, TODO: tokens in code, number of unit tests, and so on. Extensibly.

Thoughts? Forks? All welcome.

But for now.... back to the my lonely writer's garret, and the pounding out of imperfect prose...


  • count.ps1, determine number of words added to .md files, and number of tasks done in todo.txt; craft a commit message with this data, and commit all work.
  • progress.ps1, give details about daily word and task counts, and show today's progress as a percent of goal.
  • stats.ps1, summarize the numbers of words in each markdown file, and display them by size descending.
  • chapters.ps1, gives me a basic table of contents for the book I'm working on.
  • bake.ps1, generates an epub for me, using pandoc, with my chosen cover image, stylesheet, yaml metadata and my chapters

NimbleSET 2.0: Death to the VLOOKUP!

Today I've released NimbleSET version 2.0. It finally does all the things customers have been asking for. Things you might need too.

You remember NimbleSET? It's the one that looks like this:

thumbnail of NimbleSET

Originally NimbleSET was all about basic Venn Diagram operations, where you compare two lists and see what is the same or different in each list. Useful, but quite limited.

Comparisons! All sorts of comparisons!

But often our lists are tricky and our comparisons need to be even trickier. Customers gave me countless examples where they would instead be forced to use Excel, and a VLOOKUP. That's right. I feel unwell, thinking of all the VLOOKUPs I could've avoided before now.

So the comparison engine has been given an overhaul. No more VLOOKUPs. Just grab NimbleSET 2.0 instead.

Now you can join on specific columns, or all matching columns (a natural join). You can also match rows where the item on the right is 'contained in' the item on the left, e.g. "Jim Jones" contains "Jones". (In SQL terminology, 'contains' is the same as like '%x%')

comparison dropdown list

I love these tools. I possibly love them a little too much ;-). I don't see how anyone can work in the modern world and *not* have both NimbleText and NimbleSET open and running all the time.

Let me go through the new features in NimbleSET 2.0 in quite a bit more detail. ← explain the benefits, not the features, dummy!

There's an argument raging in your office!

There's an argument raging in your office!

Jim says we shipped 53 mugglewumps last quarter! Joany reports 64 mugglewumps!

Not again! Jim and Joany are always making each other look like fools!

Where did Joany get the other 11 mugglewumps from? That's what I want to know!

And now YOU step up, our fearless data scientist, with a copy of NimbleSET in your hand.

Pipe down Jim. Everyone cool it.

Give me your spreadsheets! Give me your powerpoints! Give me your crappy unstructured data! Let's stop arguing in a vacuum and start comparing mugglewumps to mugglewumps.

(cracks knuckles)

It's NimbleSET time!

1. You copy paste from Joany's spreadsheet.

2. You copy paste from Jim's Powerpoint.

joanys spreadsheet on the left and jims powerpoint on the right

With your keen Data-Eyes you notice that Joany's data is tab-delimited, while Jim's is comma delimited. It's the work of a moment to configure NimbleSET accordingly:

set the old delimiters inside the options forms

We choose a 'Natural' comparison. "What is a natural comparison?" I hear you ask. A natural comparison is where we naturally compare all the columns that exist in both lists, and ignore the other columns. Both lists have an "ID" column and a "Customer" column -- so a natural comparison will focus on those columns only.

choose a natural comparison

We could've also chosen to compare any specific pair of columns... all the possibilities exist in that drop down list.

Now we press '[Intersection]' and see all the rows they have in common. This shows us the 53 rows of data, plus a header row. Let's see what extra rows Joany has... we press '[Left Only]', since Joany is on the left.

Left Only

Ah-ha! I see it! Do you see it? We see the 11 Mugglewumps Joany has and Jim doesn't have. And you don't have to be John Nash from 'A Beautiful Mind' to spot the pattern! Old mate Jim has forgotten to include the sales from Scotland!

John Nash Investigates

What's the lesson here?

That's right! Jim is an idiot!

And if you want to demonstrate Jim's idiocy, just grab NimbleSET 2.0, keep it handy, and jump out and surprise Jim any chance you get.

Download NimbleSET.exe

Don't forget to "Pin" NimbleSET to the taskbar.

Pin to taskbar

  1. Run NimbleSET.exe
  2. Right click on the NimbleSET icon
  3. Click "Pin this program To taskbar"
  4. Hey Presto! Done!

(You've already got NimbleText pinned to the taskbar haven't you?)

As always, any feedback, let me know. Any bugs? Let me know double-quick!


Clients From Hell


Everybody has them. Clients with unreasonable demands. I thought I'd share a few of mine.

Names have been omitted to protect the guilty. Ha ha ha.

Client: You charge on time and materials, is that correct?

Me: yeh, like wossup?

Client: Your rate is $100 per hour, chargeable in 6 minute increments, correct?

Me: whatevs derr.

Client: You charged us $300 to review our code. I'm informed you only spent 5 minutes on site.

Me: dude, it's not just my time, you said it yourself time and materials too. 5 minutes looking at your code took 3 bottles of whiskey to wipe out the memories. You guys are straight in my clients from hell folder. Page 1? You guys!

And another.

Client: So we're trying to determine the correct name, and there's been some internal debate.

Me: derr, whatevs. "Naming is hard", suck it up, yo.

Client: Yes. Well, we've come up with a possible...

Me: Don't be wasting time on names. Just pick a name and move on. Here, I'll pick it for you. The Goobertronic Six Million. Done. Move on. Finished.

Client: ...and we thought that 'Everyday Billing Account' would indicate...

Me: Goobertronic Six Million. It's decided. Move on.

Client: ...that it stores the Everyday Billing Information.

Me: Forget it. Goobertronic Six Million! I'm committing it. There. Done. Pushed. There. It's live. Just like that. Woo hoo! You guys are getting a whole chapter in my "clients from hell" folder. Two chapters. Don't keep looking at me like that. Three chapters. Four. Wanna keep doing it? Uh-huh. Five. That's six chapters already. I can do this all day. Seven. I'm outta here. This blows.

One more. Though I could go on all day. Clients today. SMH. (shaking my head, that is).

Client: Our lead developer tells me you broke the build.

Me: heh broke his brains more like it

Client: He tells me you pushed without compiling first.

Me: i'm a artist, i push when i wanna!

Client: Very well, but in future, can you ensure that code compiles before pushing it?

Me: move fast and break things! look it up yo! straight into my clients from hell folder. Bam!

What about you? Do you have impossible clients?


Hacking Hyperink (aka. changing the font-size of an Epub on Kobo)

This is a little bit niche. ;-)

I bought a book from a supplier called Hyperink. Hyperink specialise in taking popular blogs and turning them into ebooks. For example they've put out a few books based on Jeff Atwood's writing. The book I bought was from Patrick McKenzie, "Sell More Software: Website Conversion Optimization for Software Developers". It's a bunch of his posts about increasing sales, plus a few new articles, and some follow up on how certain experiments panned out. (I recommend it.)

After buying from Hyperink the book was made available in 3 formats, .epub, .mobi and .pdf

Problem! When I "side-loaded" the .epub version onto my kobo eReader (using calibre), the fontsize was teensy tinsy little and impossible to read. Okay I thought, no problem, I'll just adjust the size of the font... so I tried that, but woah, the text would *not* change size. It just refused to budge. This was extremely frustrating. I spent real money on this thing so I could read it, not so I could go blind.

Did I sit on the ground and cry? No I didn't! Well, not for long. I cracked out my awesome power tools and fixed the problem!

So here's what I did.

In Calibre, add the book.

click Add books from a single directory in calibres main toolbar

Look for the "Edit Book" icon. Edit the book!

click edit book icon in toolbar

Navigate, using the "Files browser" pane on the left, double-click on any chapter, and look at the markup for a regular paragraph in the book. (It feels weird to be double-clicking... that's an action that has almost fully disappeared from our mouse-repertoire.)

navigate to a chapter and look at the xhtml

In this case we can see that a regular paragraph is wrapped in this xhtml:

<div class="bodyText"><p class="calibre1"><span>

Notice the class of "calibre1" -- that's what we'll use for specifying the styling of paragraphs. It will be different in any given epub, and there's various other css selectors that could be used to style the text. But a class, such as calibre1, has just the right level of specificity for our purposes. So in this case, commit "calibre1" to your already over-burdened short-term memory.

Now scroll down in the "Files Browser" until you find "Styles" and in there you'll find stylesheet.css. Double-click to edit that... (For other books it might be a different css file.)

find the stylesheet

Where it currently says that the style ".Calibre1" (translation, styles applied to all elements with class=Calibre1), change the font-size rule from the fixed size of "16px", to the far more flexible, relative, scalable size of "1em."

change the font-size of the calibre1 style from 16px to 1em

Save your changes. Send the ebook to your kobo (or other device), open it up and read it at ANY SIZE YOU WANT.

Ahhhh. That's beautiful.

(I find that reading very late at night, as I get more and more tired, I make the text bigger and bigger and BIGGER until finally I fall asleep with the kobo on my face.)


How Bundling Doubled The Income of 'NimbleText.com'

I couldn't bring myself to use the original headline, "This one simple trick doubled my income!". But I'm happy to finally be one of those people who made a simple adjustment to their business and turned around a month later to report that income had doubled.

The NimbleBundle was a roaring success. In case you've just joined us, the back story is that last month I introduced a 'bundle' version that was simply the grouping together of two pre-existing [& complementary] products, NimbleText and NimbleSET.

Total income for August was 185% of the income for July, while traffic stayed consistent across both months. (I track all this on my funky new dashboard). Thus, even though customers buying both products were now handing over ten dollars less than before, it was more than made up for by the increased sales volume! Support was easy-peasy, refunds remained at nil. (However a significant chunk of earnings went to Motor Neurone Disease, after a long-time friend, now enemy, named me in an ice-bucket challenge.)

What were the actual figures? I know you voyeurs would love to know, but I'm keeping the actual metrics to myself. What really matters is: were these figures statistically significant? to which the answer is a resounding yes. I plugged the traffic from each month and the sales for each month into my favorite G-Test calculator and got a result of:

"The G-test statistic is 44.7 so version 'B' wins with 100% confidence."

I'm not going to argue with 100% confidence, or the awesome power of maths.

I talked about the psychological reasons for bundling in a previous blog post. I have no way of knowing if those were the actual reasons why the sales went up. It could just be that a lot of people had text manipulation tasks and set comparison tasks in August. But whatever the reason for the increase, I'm definitely keeping the bundle around. ;-)

There was a minor disaster in the first few days. Whenever someone purchased a bundle it would sometimes send out two licenses (instead of one). Then they would write to me and ask what to do with the second license. I suspected I had a race condition in the code. And since race conditions can be very hard to track down, I pored over the code very carefully, looking for any place where a race condition might hide. Eventually the cause of problem occurred to me while I was sleeping. It was just plain old bad logic doing me in once again:

Deep inside my license generation app I have a boolean function that determines if a sale has already been recorded. It (essentially) ran a query like this: Select count(*) as count from Purchases where PayPalID = {0}. Then back in the code, it said return count == 1. This worked flawlessly for several years. But with the introduction of the NimbleBundle, there would now be up to 3 entries in the purchase table for every actual purchase. So I changed the code to return count >= 1 and duplicate license generation stopped happening.

Now on to bigger and better versions. I've got major new features implemented for both products, due out in the coming weeks. I have of course distracted myself (as I often do) with the task of writing a book. If you haven't signed up to be notified when the book is ready, go and do that now. A really solid amount of people have signed up already: if you're one of them, then thank you! I currently have an outline, a bunch of powershell scripts for tracking my progress, converting my markdown to .epub etc, and over 5000 words committed. So far: lots of fun. Have learned a heck of a lot.


Your First Product

I've been steadily cranking out products for the last few years (TimeSnapper, NimbleText, NimbleSET etc. etc.), and finally decided to write an ebook about how it's done.

There are things I consider to be "my secrets". They'll all be in the book.

I'm writing the ebook for four reasons:

  1. To get much better at making and selling products. Nothing teaches like teaching!
  2. To realise some of the capital investment I've made in building products so far
  3. To get in contact with my people: people who make products
  4. To learn about ebook production itself.

I've put up a landing page at "YourFirstProduct.com" where you can sign up to be notified when the book is ready.

Landing page for YourFirstProduct.com

In answer to the questions I've received so far:

How much will the book cost?

I do not know. It will certainly cost more than $10. It may be $30. For higher prices you'll get access to a suite of my secret tools that help when building products. And there'll be a team version, for a much much much higher pricer.

I know a bit about how these things work, and I can tell you for sure that the price will get higher over time. So the sooner you sign up the better. (Signing up to be notified is free)

When will it be ready?

It could take 3 months, it could take a year or more. I do not know. The amount of time and effort I divert into this project will be highly influenced by the number of sign ups I get at "YourFirstProduct.com". So if you want to see this ebook realised, go ahead and sign up. And tell all your like-minded friends to sign up too.

Sign up to be notified when the book is launched

Also, as a special bonus to anyone who signs up today, you get a free joke.


SimCity Drug Wars in the Real World

My name is Leon. It has been less than 1 day since my last harebrained scheme.

So the Australian Bureau of Statistics* recently put out a sim-city style game on iphone and Android, called 'Run that town' in which you compete for money and klout by approving/rejecting fictional development in familiar suburbs, using real statistics from that suburb.

The attraction of the game is that it uses settings that are intimately familiar to you, and makes you very aware of a whole host of statistics about that area. (You soon learn for example whether it's wiser to approve a local aged-care facility than a sports stadium)

And on the same day as I saw that I took a look at this interesting site, crimemap.info showing where and when real crimes have happened in my home state of Queensland. Right down to the address.

So - mashing the two ideas together - I thought, why not make a Drug Wars clone with a local flavour. You choose a starting street, anywhere in Queensland. And on each turn you can run from your current location to any of the adjoining real streets. The criminal behaviour in that street is based on historic crime in that street. (Magnified several thousand times to suit the intense pug-wars style of play). Obviously we take it global as datasets become available, but we market locally.

run that town plus crime stats

So now I present...

Okay, I've got nothing to present. I didn't implement anything. Yet.

I know some people though. This would be riiiight up their alley. You know who you are.

* The game was built by millipede possibly with input from Leo Burnett Sydney.