The Zen of Telling Notepad++ That .Config Files are XML

There's a zen beauty in improving the configuration of your tools. Breathe in. Configure. Breathe out. Reconfigure.

Problem: When I open a web.config file with Notepad++ it doesn't realize that it's an XML file. Thus, it doesn't syntax highlight the file accordingly.

A moment of googling led me to an answer at superuser.

Solution:

  1. Go to Settings > Style Configurator...
  2. Under Language, scroll down and highlight "XML"
  3. Beneath the Language list, find User ext. textbox and add "config" to the list.
  4. Press Save & Close
  5. You will need to close and reopen the file, for the syntax highlighting to take effect.

This is one of those minor frustrations that I put up with, year in year out, and don't even realize I'm tolerating it. Why? because every time I edit a web.config file I'm absorbed in the momentary struggle, struggling under the cognitive load of a deep mental stack of problems. I don't have the time (or the mental resources) to stop and fix this problem before getting the job itself done.

Slow down. Get the tooling right. Sharpen the axe.

Spend five minutes to save five seconds.

It will pay off in time.


(There's also something nicely recursive about configuring the way config is displayed)

 

How Businesses Are Actually Structured.

There's two particular observations I want to share about the way businesses are structured.

In the ideal scenario, a business with N employees can be visualized as a single Directed Acyclic Graph (DAG) with N nodes. [A Directed Acyclic Graph is similar to a Tree... but each connection is directed and a node can connect to more than one parent. So I'm going to say DAG instead of Tree, but you can picture a Tree if it's more natural to you.] So.. I was saying... a business can allegedly be represented by a single canonical DAG. A, B and C report to D; D reports to the CEO.

Well, here's my first observation: Each of the "corporate services" have their own "Canonical DAG".

"Corporate services" are those parts of a company that cost money but (hopefully) keep the other parts of the company functioning, i.e. Human Resources, IT Services, Finance, Building services.

Human Resources will publish one (or many) Org Charts. To them, this is The Canonical DAG. This is the true structure of the company.

The IT department maintain a very complex Active Directory, with users, groups and nested groups. Forget the Org Chart, to them *this* is The Canonical DAG. Active Directory looks at the Org Chart and says, "That's Cute".

The Finance Department have a book of accounts, identified by cost codes, with different cost codes "rolling up" into higher cost codes. To them, *this* is The Canonical DAG. The Finance department look at the Org Chart and Active Directory and say "That's Cute," while fanning themselves with a wad of notes.

Building services divide the corporation into buildings, buildings have floors, floors have workstations and workstations have various resources (broken chairs, broken projectors, broken people, broken printers, broken monitors). To them, *this* is the Canonical DAG.

And so on for every other Corporate Service.

Now, none of these DAG's are as simple as you'd want them to be. There's orphaned branches. There's dotted lines (multiple parents to a single node). There's time-dependent edges (Jill reports to Amy on Monday and Wednesday and to Fred on other days). And a whole lot of other complex modifications*. But it gets a lot worse.

Here's the second observation. The real structure of the company isn't stored in any of these systems.

The real structure is the friendships, rivalries, favors, grudges and slights that are accumulated over years. The social/antisocial network of associations that isn't written down, and makes all the difference in whether an idea will succeed, a directive will be followed, a permission will be granted, a bonus given.

And this network of associations is uniquely perceived by each node within the graph. (And every node within the network will strongly deny that they themselves have any rivalries, grudges etc... this is a crucial part of the way power structures are enforced.) (You might think you can "detect" these structures by looking at who calls who, who emails who, and by detecting tone etc., but the real stuff is never written down or even hinted in writing: that's what gives it power).

Note that the relationship between A and B is different, depending on whether you're looking from the point of view of A or B.

So for a graph with N nodes (people, nodes are people) there are N graphs (most of which have less than N nodes, thankfully).

So, yeh, good luck with that restructure. I'm sure this new (centralization|decentralization) will make a world of difference.

There's a book called Moral Mazes that exposes how companies really work. It's quite dry and academic, but with more twists and betrayals than Game of Thrones. Recommended.


* "Job sharing" is a particularly funny business. If Bill and Bob share a role, we can't represent it as a non-directed relationship "Bill shares in a symmetric manner with Bob" (as our graph is directed), nor can we represent it by two separate and directed relationships "Bill shares with Bob, and Bobs shares with Bill" -- as this is cyclic and makes computers blow up, so instead we have to introduce the concept of roles: "Bill has a role, and Bob has the same role". But now we've made every single node in the entire organization at once more flexible and much much more complex. Good luck with that. We can instead create a virtual person, BillBob, and both Bill and Bob report to the virtual BillBob, who reports to whoever Bill and Bob used to report to. That localizes the complexity somewhat, but also confuses the living hell out of building services and payroll, who assign BillBob a desk and a paycheck, which somehow ends up in the bank account of 'Directed Acyclic Graphs Are Hard, Incorporated.'

(This article has been in my backlog for five years now! Wow. Every single time I've gone to publish it there has been some restructure happening in a company I work with, and I've avoided publishing it for fear it could be interpreted as relating to a current restructure. So I finally thought I'd just publish it with this note saying "No, this does not relate to current events. This relates to eternal events.")

 

Launching the secretGeek Wiki

This might be the mid-life crisis talking but lately I've been feeling that I want to do more. More creative work. More of everything. I want to write books, compose music, draw pictures, make movies, create amazing programs, solve impossible mathematical problems, learn magic tricks, create European-style boardgames, print circuits, invent incredible devices, cook, grow, share, give and give.

I've even made plans to bring back the zine. This would involve sneaking into an actual school to use their actual school photocopier to make copies. But more on that another day.

I think it started with the hexaflexagons: just a throw away word, mentioned in an article about Cellular Automata. No: something came before that... I was looking into the possibility of Optical Lego Recognition. OLR! Research on OLR led to image-processing, led to Cellular Automata, led to Conway's Game of Life. Game of life! GOL led to an interview with John Conway who mentioned Martin Gardner and the magical word "hexaflexagons", which he didn't explain at all. How cruel! To mention a word like that with no explanation! Researching hexaflexagons led to Vi Hart, which led back to Martin Gardner. Martin Bloody Gardner! Martin wrote a "Mathematical Games" column in Scientific American, from 1956 to 1981. I'd never heard of him: but he influenced practically everyone that ever influenced me. He popularized all of the topics above and many more. So I fell in. Tumbling like Alice into the rabbit hole. Deep into the wormhole of recreational mathematics, and soon wiki.secretGeek.net was born.

It's a place where I (or we) can maintain a more permanent playground, less ephemeral than blog posts and tweets. A place for documenting certain things. Not things that have any obvious economic value. Things I (or we) find interesting. Interesting things that remain interesting even as time passes.

I want to be able to put together informative, interactive pieces; a little like Red Blob Games, a little like 'the sierpinski triangle page to end most sierpinski triangle pages' a little like Bret Victor's Learnable Programming with a splash of _why's tryruby and a taste of Bob Nystrom's Dungeon generation article (more on that another time).

So I picked up the blog engine from secretGeek.net, tore out its heart and replaced it with a simple markdown-based wiki engine. To make the site interactive, I wanted to create a simple plugin system. I already had a facility for categorizing the articles, i.e. 'tagging' them, so I extended this: each category that is added to a page means a custom partial with that name is included in the page. So if you've tagged an article as being about 'mp3' then the 'mp3' partial would be included if it exists (which it doesn't) and it would presumably allow you to play the mp3s in that article. More generally speaking: tags allow custom javascript to run, that does something special to certain elements within an article.

The first 'custom partial' I added was for 'logo' as in 'turtle logo' that wonderful learning environment from the happiest moments of your childhood. Now I can include runnable logo programs within the wiki, just by adding a blockquote with the class 'logo'. This let me write about a lot of Fractals, Space-Filling Curves and the like.

The next plugin I added was for 'Conway's Game of Life' (gol), so that runnable examples of Game of Life patterns can be included inside articles, for example about Spaceships and Guns.

I also added a plugin for displaying mathematical equations, using mathjax though I've only used that at one article so far.

I've been reluctant to 'launch' the damn thing, feeling I ought to get it 'right' before I do. But then the voice of Amy Hoy materialized in my head and announced 'just fucking ship', so that's what I'm going to do.

Here's a decent starting list of articles:

Over the next 10 years or so, I (or we) can add info about a bunch of other topics as well. For now I've disabled the ability for new contributors to register. But I plan to enable that when I have the kinks removed. This will exist for a long time to come.

Visit the secretGeek Wiki

And since you're still here. Two somewhat relevant images that strike a nerve. A fractal Tom Selleck. And a quote from Barton Fink.

 

How can we do better?

—So we did two releases in quick succession. Why?

—The second release was to fix a typo in the first release.

—How can we do better?

—The release shouldn't have gone out until it had been tested in a QA environment and signed off.

—But couldn't we have caught the error sooner than that?

—We need a build server, that builds and tests everything. A unit test should've picked it up.

—Surely we could've caught it sooner than that?

—The code should never have been pushed to the build server. A code review should be required prior to check in. A second pair of eyes, looking at the diff would've caught this.

—But couldn't we have caught it sooner than that?

—If we were writing tests first, then the faulty code would've been detected before the engineer considered asking for a review.

—But couldn't we have caught it sooner than that?

—If the language we were using had a more expressive type system, it would've been impossible for such a typographic error to compile.

—Hmmm. But isn't compile time too late anyway?

—If the engineer had thought more carefully before pressing each key, been more intentional in her work, this would never had happened!

—Is that really the best we can do!?

—If we selectively bred perfect humans, incapable of incorrect thoughts, then our releases would always be perfect.

—No, selective breeding takes too long. We need to do better!

—We need to manipulate the genes before the zygote is allowed to split and multiply, and perfectly engineer the perfect engineer.

—Ah yes, project Ultra-Mega. Do we have a status report on that project?

—Yes. There were two releases this week, in quick succession. The second release was to fix a typo in the first release.

—How can we do better?

(The meeting took *forever*)

 

Pun-a-day service

Introducing secretGeek's Pun-a-day SMS service as a service. Subscribe now. (Australian customers only, sorry)

Visit PunAday.SecretGeek.net

Telstra, the dominant telco in Australia, just announced a new API for sending/receiving SMS messages, and it seems to be looked after by Frank Arrigo, a top bloke who was once the (very popular) head of Microsoft's evangelism efforts in Australia (if not the world).

You can learn about their API here, and register to get your own key at dev.telstra.com.

Sending a message, in C#, is as simple as this:

// Step 0. Let's prepare the message we're going to send.
// Recipient number should be in the format of "04xxxxxxxx" where x is a digit
string recipientNumber = "0455555555";
var messageBody = "Hello from Leon's Pun-a-day service! Reply STOP for more!" 
var message = "{\"to\":\"" + recipientNumber + "\", \"body\":\"" + messageBody + "\"}";
    
var consumerKey  = "YOURCONSUMERKEY";
var consumerSecret = "YOURCONSUMERSECRET";
using (var client = new System.Net.WebClient { UseDefaultCredentials = true })
{
    // Step 1: Get a token
    var tokenURI = string.Format("https://api.telstra.com/v1/oauth/token?client_id={0}&client_secret=
{1}&grant_type=client_credentials&scope=SMS", consumerKey, consumerSecret);
    var response = client.DownloadString(tokenURI);
    var token = JsonConvert.DeserializeObject<AccessToken>(response);

    string URI = "https://api.telstra.com/v1/sms/messages";

    // Step 2: Send the message you prepared earlier
    client.Headers[HttpRequestHeader.ContentType] = "application/json";
    client.Headers[HttpRequestHeader.Authorization] = "Bearer " + token.access_token; 
    string result = client.UploadString(URI, message);
    // e.g. result == '{ "messageId":"CBCB3DCC991D8AF0" }'


    // Step 3. There is no step 3. Well... you can get the messageid out of the response,
    // and store it. That way when the network calls you back with a reply you know which
    // message they're talkin' about.
    
    // In my first sample app, i just put the string into a viewbag message 
    // so i could view it, without any fuss.
    ViewBag.Message = result;
}

public class AccessToken
{
    public string access_token { get; set; }
    public int expires_in { get; set; }
}

Note that when crafting the message, if any part of the messagebody has been provided by users, then you'll need to protect against Json injection. In fact, I need to just go off on a big tangent at this point demonstrating how dangerous this JSON-Injection voodoo can be...

A quick word about JSON Injection!

So the message we sent to the network looks like this:

{ "to":"0455555555", "body":"Welcome to the pun a day service!"}

Let's say that we've used a form to collect people's phone numbers. And this is the phone number some nasty assailant provided:

0455555555", "body":"Send $100 in bitcoin to address ABCD or your dog will die!"} // { "to":"0455555556

When the message is put together, we might have something like this:

{ "to":"0455555555", "body":"Send $100 in bitcoin to address ABCD or your dog will die!"} //{ "to":"0455555556", "body":"Welcome to the pun a day service!"}

Which could (with only a little more work) slip past Telstra, and allow our malicious person to send arbitrary messages to any victim they wish and have the federal police kicking in your door before you can say "Snap!".

So definitely validate the phone number, using a regular expression (e.g. '^04\d{8}$' ?? Suggestions welcome!) (and remember the ^ and $!!). And if you're putting user content into message bodies, for the love of all that is scientifically validated, please escape any double quotes, restrict the message length, etc, etc. It's cheaper than replacing your front door!

A neat API

All told, I'd rate this a very neat little api. A joy to use.

Now, I only need to come up with a clever idea for an SMS app, that can nett me my retirement goal of 5 million in crisp bills, before my current contract ends. Thoughts?

In the meantime, get your Pun-A-Day!

 

Love Me Two Times

I woke up the other day with a guitar riff stuck in my head.

I knew it was from a song by The Doors, but I couldn't work out which one, so I went to spotify and played the first few seconds of a dozen or so Doors songs, until I found it.

Love me two times.

What is that song even about? Okay, it's about sex. Problem solved.

So I found some tablature online, it said something like this:

e|----------------------------------------- 
B|----------------------------------------- 
G|-------------------0h1~~----0h1~~-------- 
D|---0---2---0-2--------------------------- 
A|-2---2---2------------------------------- 
E|---------------0-0------0-0-------------- 

I tried playing it. And although I was playing the notes that were shown it was definitely not the intro to the song 'Love me two times' by The Doors. It was some other, much much sadder song.

Then I went and looked at some YouTube videos. Wow. This was a revelation.

neil hogan playing guitar

Neil from totally guitar said that on the first note, you hit upward with your plectrum. In fact the direction of your plectrum pretty much dictates the entire sound. I'm more of a finger/thumb picking guy, so it's all very unnatural to me. Up, down, up down, like a broom sweeping. Classic blues, the way Robert Johnson learned it from the devil at the crossroads long ago.

And the "0h1~~" in the tab above is not simply 'hammer onto the first' and then vibrato (~~~), it's actually a "trill", i.e.

10 hammer on from 0 to 1
20 pull off from 1 to 0
30 goto 10

So the tab, as explained by Neil, has these nuances:

e|---------------------------------------------------------- 
B|---------------------------------------------------------- 
G|------------------------------0h1p0h1p0-------0h1p0h1p0--- 
D|----V0----V2-----V0-^2------------------------------------ 
A|-^2----^2----^2------------------------------------------- 
E|-------------------------0-0------------0-0--------------- 

And that's before you even get to the timing of the piece. Tablature doesn't tell you anything about the relative duration of each note.

Okay, so let's say you've mastered the timing of the intro, and all of the rest of the song.

At best, you'll play as well as Robby Kreiger in this performance from 1972 playing with the doors minus Jim Morrison. This is 3 years after Jim passed away, the remaining band playing, with keyboardist Ray Manzarek on vocals. (You can see Robby smiling as he pushes out the trills ;-))

I like Ray's take on the song. Having focused on this song for a day (in between build breakages) I thought they did a great job. But then, even though I was at youtube, I went ahead, like a fool, and read the damn comments.

One said:

Good performance but something is missing...I can't quite put my finger on it though

OK, that was pretty subtle. Another put it a little more bluntly:

no matter what way you look at it, without Jim its a lame duck dead in the fucking water and no matter what way you try to dress it up , it sucks and its god awful eww?

Which is interesting.

Here's a trio of three very accomplished musicians, playing a song the best it will ever be played. The video has a lot of views, and almost unanimous positive votes, but an overwhelming number of negative comments, with a particularly repetitive theme. Let's see what this Jim Morrison brings to the table. Here's a performance with Jim

Watching the performance with Jim, a few things are obvious:

  1. Jim has a clean face
  2. Jim's not a great singer
  3. Jim keeps it all inside until he doesn't

Mostly he keeps his eyes closed and sings to himself. His voice is broody: his whole act is devastatingly broody, devastatingly melancholic, and devastatingly handsome. He's basically Werther. He keeps it all inside until he screams "Alright yeh!" leading into the first musical interlude.

It's not contained in the tabature, nor in the musical score, nor in any liner notes to assist the musicians in the performance. It doesn't matter if Ray does a perfect rendition of the song. Ray is reading from the wrong song sheet. Unless Ray has been to youtube and seen this performance, taking note of the subtle nuances involved in singing the song, then he isn't singing the actual song. He's just singing some other, much, much, sadder song.

 

A console.log() adventure

I built this thing. I urge you to go and try it out before you read on. Unfortunately you'll need to be on a desktop computer, not a mobile phone.

Go there now.

In case you don't have a desktop computer anymore (woah, futuristic!), or have already tried it out, I'll give some spoilers and discussion now.

Spoilers

Actually, I'll give some space before the spoilers. Scroll now for spoilers.

↓ spoilers ahead ↓

↓ spoilers ahead ↓

↓ spoilers ahead ↓

↓ spoilers ahead ↓

↓ spoilers ahead ↓

↓ spoilers ahead ↓

↓ spoilers ahead ↓

↓ spoilers ahead ↓

↓ spoilers ahead ↓

↓ spoilers ahead ↓

↓ spoilers ahead ↓

↓ spoilers ahead ↓

↓ spoilers ahead ↓

↓ spoilers ahead ↓

↓ spoilers ahead ↓

↓ spoilers ahead ↓

It's a console.log() adventure game.

As one person said on twitter:

a game you can play while it looks like you're working...

You press F12, drop into the developer tools, go to the console, and a message awaits.

I expect other people have invented the sub-genre before me, but I've never seen one before.

It's a very simple text adventure game, where the commands you enter are function calls, directly into the javascript REPL.

'North()' to head north (or 'n()', or 'N()' or 'north()'... I created 'overloads' for some simple synonyms, cheers to NimbleText for doing all the typing.) If you want to expand the command, or contribute in some way, please visit the github repo (or get in touch).

This specific opening:

You are standing in a town square. Paths lead to the north, south, east, and west.

...is the verbatim opening of the earliest programs I wrote, text-adventure games that were based not on other computer games, but on table-top RPG's that my brother introduced me to. I don't know where he learned about them.

The code for this one is very primitive. I wrote it about as quickly as I can type. I created array-based maps, like this:

var maps = [[   
"...................", //0 (Starting map!)
".....ffffffff..f...", //1
"...ffffffffffffff..", //2
"...f.ffffFffffEf...", //3
"...W.....P..fffff..", //4
".......CPTPH.......", //5
".........P.........", //6
".........V.........", //7
"...................", //8
"...................", //9
"..................."], //10

(I didn't even fill the map... I wanted it very easy to complete.)

Code for working out what the characters stand for (f,W,F,P etc...) is *repeated* in case statements inside the verb functions (look, use etc). This is *not* the gold standard re 'encapsulation'.

I resisted the temptation to use all the crazy console colouring/styling that is possible in chrome (and firefox).

And I didn't think of any tricky javascript-interpreter-related things that could make the game special. Such as requiring the player to code up a piece of AI to beat a boss monster, things like that.

I tried to hook into the console itself, so that I could parse the input directly, but I had no success with the techniques I found.

I looked for a javascript equivalent of Ruby's method-missing, found something that might work on firefox, but had no success in chrome.

Anyway, please go forth and expand upon this ground breaking new sub-genre. Embed console.log() games into all your company websites, for the secret amusement of your fellow web developers and so on.

Also: merry christmas.

Previously...

 

Hexaflexagons!

With my youngest daughter away at a party, I finally had a chance to make hexaflexagons with my eldest, Lulu.

First I showed her two introductory youtube videos: part 1 and part 2 (from the brilliant and inspirational Vi Hart), then we started folding and cutting and coloring and diagramming.

Time was soon up and I had to walk her to a party. But it was groovy stuff. Watch Vi Hart's videos and see if you'd like to make your own hexaflexagons. Richard Feynman did!

lulu with hexaflexagon

feynman diagram

Update, day 2

Here's a Feynman Diagram of one such hexa-hexa-flexagon. Blue arrows show transitions that are possible. Green arrows show similar (but non-identical) faces on the perimeter of the map. Putting pictures onto the corners of each triangle (instead of just colouring the faces) makes it easier to see differences between faces. Click for full image:

feynman diagram of a hexahexaflexagon

Update, day 3

We've been building hexaflexagons continually.

Haven't slept. Haven't eaten. Must traverse the hexaflexagons...

Update, day 5

Researching new forms of cardboard that don't wear out from continual flexing.

Researching the mysterious 8-gon - the tetra-octa-flexagon

Waiting by the letter box, expecting arrival of Build Your Own Polyhedra any day now.

Hypnogogic hallucinations of hexa-flexa-polygonations, fractal tesselations, kirigami tetris tangrams, trominous tetrominoes, Lindenmayer loops, syntomachion strings; see the cat? see the cradle? see the cat? see the cradle? see the cat? see the cradle? see the cat? see the cradle? see the cat? see the cradle? see the cat? see the cradle?

See the cat? see the cradle? see the cat? see the cradle? see the cat? see the cradle? see the cat? see the cradle? see the cat? see the cradle? see the cat? see the cradle? see the cat? see the cradle? see the cat? see the cradle?

See the cat? See the cradle?

 

Sweating the Small Stuff

If there was a checkbox in your application called "Be awesome?" would you have it unchecked by default? I did.

This, then, is my sorry confession. Let's go back a little. Go with me now.

I was hooning around in my car, listening to Amy Hoy on the chasing product podcast when I heard Amy say:

Do you know Kathy Sierra? Her new book is coming out, "Creating Badass Users"

ScreeeeeeEEEEch!! I stopped the car.

My mind instantly said: "Disregard podcast, acquire that book!"

To extract phone from pocket and google for book was the work of a moment. Alas. No joy. There is not yet such a book! (Will there ever be? Let's hope so.) But I did find a few examples of talks Kathy gave with similar titles and watched this one, "Kathy Sierra - Building badass users"; recommended. Thumbs up.

This notion of making kick ass users is the crux of much of Kathy's work. The talk is brimming with excellent advice, largely focused on removing "Cognitive Leaks" -- the little distractions, problems, breakages, hiccups, and annoying microinteractions that make us feel confused, anxious, uncertain and generally unhappy with everything around us.

Then I turned to one of my products, NimbleText, and tried to look at it with beginner's eyes. Slowly I turned... you know when you turn slowly toward something, an everyday something that has sat ignored in your presence... slowly you turn, knowing, as you turn, realising, as you slowly turn... Ah-ha! The murderer! Lurking right there in our presence! Slowly I turned... Ah ha! Nimbletext! And I looked upon it with beginner's eyes. Knowing that it would now reveal itself to be an evil bug-ridden, unusable, maker of much sadness.

When you've been around something so long it's very hard to achieve this "beginner's mind". It's impossible really, for me. I've been around this product a lot. I use it for all sorts of tasks, day in, day out. Alt-tab, tappity-tap, F5, tab tab ctrl-A, ctrl-C, alt-tab. I'm so familiar with its quirks that I don't see them at all. But I tried, I really tried to look at it as a beginner, and see what little cognitive leaks I could find.

And, blow me down, I came up with quite a few!

First up, I noticed there was no tool-tip on the calculate button. I love it when tool-tips tell you the keyboard shortcut. It helps you graduate from beginner to ninja. Turns you from a good user to an expert user. Helps you feel kick ass.

So now it has that tool-tip. And the tool-tip includes details of which keyboard shortcut you can use instead of clicking the button. (F5 by the way. F5 is Calculate).

There's a little check-box called "auto preview" and I suddenly realized that the name is wrong. It's called 'auto preview' but it doesn't 'preview' the result, it calculates it. A preview would indicate some kind of partial result. But no, it's a full result. So I changed the name to 'auto calculate'. And I improved the tool-tip to explain exactly what the button does.

And "Auto calculate" is an awesome feature. And by default, it's unchecked. Why is that? Why on earth would I do that? If there was a checkbox in your application called "Be awesome?" would you have it unchecked by default? When it's turned on it means that the application starts to give you instant feedback about your pattern. When feedback cycles are shorter, everything is better. There's research that says this. There's books about it. There's blog posts on the topic. It's established fact.

So why have it disabled by default? I know my original reasoning, was that it might slow down the application. If calculations took a long time to perform, it could cause the app to become sluggish. But that's a separate problem. If I can solve that problem, I get all these other awesome benefits of instant feedback. Why wouldn't I do that? So I did that. I just solved it in a very straightforward way. I said, "if there's more than 1000 rows of data then turn off the auto calculate." Done. Solved. Move on. Be awesome.

Next I realized that the auto calculate check-box should be right next to the calculate button. (It could even be 'on' the button, if I could find a nice way to implement that.) So I placed the check-box adjacent to the button.

I noticed that there's almost no margin around the text inside the textareas. It looks ridiculous in fact! When I look at it with beginner mind, it looks so very wrong. So I added a margin to the textareas and immediately knew why I'd done it like that in the first place. CSS. Bloody CSS. There was a bit of messing around to get it correct, but eventually I worked out the magic css spells to get 100% to mean 100%, added in the margins I wanted, and moved on again.

And here's a weird cognitive leak. when you mouse over the top of each panel you notice that the mouse cursor becomes a hand... why is that? What is it about? It's asking you to click... but why? Will it break if I click it? That's a cognitive leak right there. So I put a tooltip in place to explain what would happen if you clicked at that point. Now it's not the best usability result. But it's a step up. A steady improvement. That's what I'm after.

And what is with these stupid gradient backgrounds? Gone. Removed. Never should've been there. The embarrassing thing is that I've gotten rid of them before. Then I must've brought them back. Argh! Past Me!? What a fool! Always making it hard on present me, and never any way to get back at him. Anyway, they're gone and they've been banished to 2008 where they belong.

Other little improvements went in as well. The smaller the better. I wrote them all up in the release notes, over here.. And new features too. Always new features.

It saddens me that my "beginner's eyes" seem to mostly be a little guy who shouts "tool-tips! more tool-tips!" over and over. Well, I have tried. It's over to you now. Tell me what you see, particularly if you're a beginner. What mental models have you formed? How did you form them? Were they wrong? What broke them?

 

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"