Wiki lacks?

August 27th, 2013

Quote:

The only example of a wiki that worked is Wikipedia, and that’s not really a wiki in the true sense, because it is heavily edited by such a small number of people.

That’s Russell Keith-Magee, speaking on a podcast (so I may not have quoted him exactly). He was talking particularly in the context of software documentation, but I think, on consideration, that he’s right.

Don’t get me wrong, I love wikis, use them quite a bit, and shook Ward Cunningham‘s hand very enthusiastically when I met him a few years ago. But on the other hand, if one has been spoiled by the quality of documentation in projects such as Django, it makes one’s heart sink when exploring a new piece of software to discover that the documentation is ‘only a wiki’.

Wikis are great for their free-form, collaborative nature – remember, they came into existence long before Google docs and SubEthaEdit – but they also suffer from a few key problems:

  • They can make you feel as if you’ve done something about documentation, so you don’t do the real work. “The crowd will fix it later”.
  • The fact that you don’t need to think about the structure early on means they often need to be reorganised – making it hard for others to find things even if they’ve visited before, and harder to link to things reliably.
  • It’s notoriously difficult to move content from a wiki into anything else, including another wiki package.
  • It can be hard, with a software package, to know to which version the documentation applies.
  • As with mind-maps, the free-form nature closely represents the mental model of the author. It’s good for personal notes and reference (Voodoopad is lovely, for example), but the difference between structured documentation and a wiki is the difference between a talk/lecture and a rambling conversation. The letter may be more fun, but does it achieve as much in the same amount of time?

None of this means, of course, that you can’t write good documentation with a wiki. It’s just very rarely done, and when it is done, it probably takes a lot of effort. Wikis are the whiteboard doodle, the back-of-the-envelope scribble: they can be useful within a small internal group of collaborators, but they’re not the thing you want to present to the world.

Actually, I think one of the best ways of doing documentation was the approach adopted by the PHP developers many, many years ago – you write proper docs but allow comments at the bottom of each page. Here’s an example. They did this long before the concept of comments-at-the-bottom-of-the-page was well established.

What do you think?

Time’s Wingèd Chariot

May 5th, 2013

The best chat-up line ever invented has to be the poem To His Coy Mistress, by Andrew Marvell, where, in 46 lines of glorious verse, he explains to his girl that they really do need to get down to some hanky-panky, because they won’t always be able to do so, and time is running out. Extended courtship and foreplay is all very well, he argues,

But at my back I always hear
Time’s winged chariot hurrying near…

I was thinking of this as I created my first app for my Pebble watch today, inspired by a combination of a 17th-century poet and my friend Richard, a 21st-century technologist. He held a party a little while ago to celebrate being one gigasecond old, and has a nice web page where you can check your age, too.

So, since part of the idea of the Pebble is that you can personalise it to a great degree, I thought that a watch face that showed my age in seconds would be a good project. I named it ‘Tempus Fugit’.

But then it occurred to me that one could also do the opposite – a countdown. How long I’ve been around is an interesting topic, at least for me. But how long I’ve got – well, that’s even more compelling!

Of course, life expectancy is a highly personal thing (and one wishes to avoid the estimation errors made by the Rich Fool in the parable) but it’s interesting to speculate. Life expectancy, in statistical tables, tends to be quoted as ‘expectancy at birth’, based on an assumption that mortality rates will continue through your life at the same kind of level as they were at your birth. When I was born, in 1967, it was about 69 years in the UK. It’s now 78, according to Wikipedia, and will no doubt continue to rise. So on the one hand, one might expect that the inferior healthcare, nutrition advice etc in my youth would mean that I probably come somewhere between the two. On the other hand, today’s figure doesn’t take into account the improvements in healthcare that are inevitable in the future, which may mean that my allotted span may be more that the expectancy of those born today (as will theirs).

So, as a rough estimate, averaging these two factors, I decided to use the present life expectancy for the UK, currently around 78 for men and 82 for women. (It’s slightly more in Canada and Australia, and a couple of years less in the U.S.).

And so, with a minor variation in the software, I now have two new watchfaces for my Pebble. The first, Tempus Fugit shows how many seconds I’ve been alive. The other shows my best estimate of how many I’ve got left, a number which is already distressingly lower than the first, and, of course, counting down…

Some may think this morbid. But I prefer to think of it as an inspiration… a call to action.

Oh, and in case I should be short of ideas about what to do with the time that remains, I named this second one Time’s Wingèd Chariot. I think Marvell would approve.

Time's Winged Chariot

I may be celebrating a rather different kind of gigasecond soon!

Alfred 2 support for iTerm 2

May 5th, 2013

iTerm 2 is a terminal program for the Mac with lots of great features beyond the standard OS X Terminal. Alfred is an excellent app launcher, which in its newly-released second version is taking the Mac world by storm.

If you don’t use either of these, I strongly recommend them.

If, on the other hand, you already use both of them, you might like my (very basic) plugin that lets you list your iTerm profiles using an Alfred keyword and fire up a new iTerm window using the selected one.

Alfred iTerm

Goldilocks for grey-haired geeks

April 20th, 2013

When I was an undergraduate studying Computer Science, in the late 80s, the course was accredited by the British Computer Society on the condition that, as part of the syllabus, we were taught some COBOL. For those who have not encountered it, COBOL – the Common Business Oriented Language – is a very early programming language designed with the idea, amongst other things, that managers and other non-technical business types should be able to read and understand it.

In retrospect this wasn’t really a great idea (any more than it was when Apple tried something similar with AppleScript in 1993). Computer languages tend to get a kind of uncanny valley problem when you try to pretend that machines speak the same way as humans; the results are neither good English nor good programming languages. It’s a bit like Franglais, except that Franglais is enjoyable to use.

But COBOL can be forgiven; this was after all still 1959, and the world’s experience in programming languages was somewhat limited. It was designed by people as eminent as Grace Hopper (who was brilliant at handling David Letterman, as well as computers!). And COBOL was incredibly successful – for some decades it was the most-used computer language, and it’s still in use today, though it’s bizarre to discover there are people doing .NET programming with it.

Anyway, it was Dr Frank King who taught us most of our languages, and since he had to include a bit of COBOL, he did it mostly as a joke, starting with a properly-constructed “Hello World” program, which I seem to recall was 77 lines long.

At the end of the final lecture, he handed out photocopies of “The Common Business Oriented Goldilocks”, which had been published in Datamation magazine back in 1968, and which is written in something approaching valid COBOL. Maybe it is valid COBOL… I never wrote another line of COBOL after that lecture, so don’t remember. But I may have readers who do!

        THE COMMON BUSINESS ORIENTED GOLDILOCKS
            --- ------ -------- -------- ----------

IDENTIFICATION DIVISON.
PROGRAM ID.           A COBOL FABLE.
SECURITY.             INSECURE.
PROGRAMMER-ID.        ARTHUR SHAPIRO.
REMARKS.              SLIGHTLY MORE MANGLED VERSION OF ONE IN JAN., 1968
               DATAMATION.
DATE WRITTEN.         ONCE UPON A TIME.

ENVIRONMENT DIVISON.
CONFIGURATION SECTION.
OBJECT COMPUTER.      ANY MUSIC BOX, MEMORY SIZE 8X64 BYTES,
                      19 TAPE DRIVES, 11 DISK DRIVES, 1 GOLDILOCKS, 3 BEARS.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
    SELECT TAPE DRIVES, ASSIGN THEM TO CREDITOR.
    SELECT DISK DRIVES.
    SELECT GOLDILOCKS, SELECT BEARS, ASSIGN TO ONE COTTAGE.
I-O CONTROL.
    APPLY RED TAPE TO TAPE DRIVES, APPLY BRAHMS RECORD TO DISK DRIVE,
    APPLY GOLDI, BEARS TO COTTAGE.
    DATA DIVISON.
FD GOLDI.
    LABEL RECORDS ARE STANDARD
    VALUE OF IDENTIFACTION IS "GOLDILOCKS"
    DATA RECORD IS GOLDILOCKS.
01  GOLDILOCKS.
    02    HGT   SIZE IS 62 INS.
    02    WGT   SIZE IS 110 LBS.
    02    VITAL-STATS.
          03    B     38.
          03    W     24.
          03    H     36.
    02    RATING      100%.
FD  THREE-BEARS.
    LABEL RECORDS ARE STANDARD
    VALUE OF IDENTIFICATION IS "BEARS"
    DATA RECORDS ARE DADDY-BEAR, MUMMY-BEAR, BABY-BEAR.
01  DADDY-BEAR.
    02    HGT   70 INS.
    02    WGT   750 LBS.
    02    COLOR-OF-EYES   BLOODSHOT.
    02    DISPOSITION     UNBEARABLE.
01  MUMMY-BEAR.
    02    HGT   65 INS.
    02    WGT   700 LBS.
    02    COLOR-OF-EYES   BLUE.
    02    DISPOSITION     BEARABLE.
01  BABY-BEAR.
    02    HGT   40 INS.
    02    DISPOSITION     INFANTILE.
WORKING-STORAGE SECTION.
01 COTTAGE      PICTURE IS COZY.
    02    KITCHEN.
          03    TABLE     SIZE IS LARGE, VALUE IS 1.
          03    CHAIRS    SIZE IS MEDIUM, VALUE IS 3.
    02    PORRIDGE.
          03    KING-SIZE    OCCURS 1 TIME.
          03    QUEEN-SIZE   OCCURS 1 TIME.
          03    PRINCE-SIZE  OCCURS 1 TIME.
    02    DOOR  SIZE IS USUAL, VALUE IS OPEN.
    02    BEDROOM.
          03    BED.
                04 LARGE     OCCURS 1 TIME.
                04 MEDIUM    OCCURS 1 TIME.
                04 SMALL     OCCURS 1 TIME.
          03    WINDOW    SIZE IS SMALL, VALUE IS OPEN.
01  CORRECT-COTTAGE REDEFINES COTTAGE, VALUE IS SAME.
77 KING-SIZE-BED-SLEPT-IN    SIZE IS BIG, VALUE IS ROCK-BOTTOM.
77 QUEEN-SIZE-BED-SLEPT-IN   SIZE IS MEDIUM, VALUE IS DEPRESSED.
77 NO-PORRIDGE               SIZE IS SMALL, VALUE IS ZERO.
77 SIP                       SIZE IS LITTLE, VALUE IS "SSSLURP".
77 SLUMBERLAND               SIZE IS UNLIMITED, VALUE IS ZZZZZZZZZ.
CONSTANT SECTION.
01 COMMENT1     SIZE IS 36, VALUE IS "SOMEBODY HAS BEEN EATING MY PORRIDGE".
01 COMMENT2     SIZE IS 36, VALUE IS "SOMEBODY HAS BEEN SLEEPING IN MY BED".
PROCEDURE DIVISION.
FOREST SECTION.
START-OF-TALE.
    OPEN STORY. READ FOLLOWING.
FIRST-MOVE.
    MOVE GOLDILOCKS TO COTTAGE.
    IF DOOR IS CLOSED OR BEARS ARE GREATER THAN ZERO ALTER ENTER-GO3
          PROCEED TO HASTY-RETREAT.
ENTER-GOLDILOCKS.
    GO TO KITCHEN-SCENE.
KITCHEN-SCENE.
    IF PORRIDGE IS KING-SIZE, PERFORM TASTE-ROUTINE VARYING PORRIDGE-
          KING-SIZE BY 1 UNTIL PORRIDGE EQUALS PRINCE-SIZE
          OTHERWISE COMPUTE IF COTTAGE = CORRECT-COTTAGE GO TO BEDROOM-SCENE.
TASTE-ROUTINE.
    SUBTRACT SIP FROM PORRIDGE(KING-SIZE).
    SUBTRACT SIP FROM PORRIDGE(QUEEN-SIZE).
    SUBTRACT SIP FROM PORRIDGE(PRINCE-SIZE) GIVING NO-PORRIDGE.
BEDROOM-SCENE.
    MOVE GOLDILOCKS TO BEDROOM.
    ADD GOLDILOCKS TO BED(LARGE). DISPLAY "IT IS TOO HARD".
    SUBTRACT GOLDILOCKS FROM BED(LARGE) GIVING KING-SIZE-BED-SLEPT-IN.
    MOVE GOLDILOCKS TO BED(MEDIUM). DISPLAY "IT IS TOO SOFT".
    SUBTRACT GOLDILOCKS FROM BED(MEDIUM) GIVING OUEEN-SIZE-BED-SLEPT-IN.
    MOVE GOLDILOCKS TO BED(SMALL). DISPLAY "IT IS JUST RIGHT".
    ADD GOLDILOCKS TO SLUMBERLAND.
BEARS-RETURN.
    MOVE DADDY-BEAR, MUMMY-BEAR, BABY-BEAR TO KITCHEN.
    MOVE CORRESPONDING BEARS TO PORRIDGE.
    DISPLAY "DADDY BEAR ", COMMENT1.
    DISPLAY "MUMMY BEAR ", COMMENT1.
    DISPLAY "BABY BEAR ", COMMENT1, " AND EATEN IT ALL UP".
    MOVE BEARS TO BEDROOM.
BEARS-IN-BEDROOM.
    EXAMINE BEDS, REPLACING ALL GOLDILOCKS WITH BEARS.
    DISPLAY "DADDY BEAR ", COMMENT2.
    DISPLAY "MUMMY BEAR ", COMMENT2.
    DISPLAY "BABY BEAR ", COMMENT2, " AND HERE SHE IS".
HASTY-RETREAT.
    IF WINDOW IS OPEN EXIT GOLDILOCKS OTHERWISE MOVE GOLDILOCKS TO DOOR.
END-OF-TALE.
    CLOSE STORY, DISPLAY "WOULD YOU BELIEVE CINDERELLA IN PL/I?".
    STOP RUN.

Django cross-site authentication

April 17th, 2013

Richard wrote a nice bit of code to allow one Django app to authenticate users using another Django app’s database. It saves the users having to get a separate set of credentials.

This assumes that both apps can securely access the original database, but if you have a situation where, say, they both run on EC2 machines in the same Amazon account, this can be very handy.

It’s still fairly basic, so I’m sure he’d welcome contributions.

Feeling old, and honoured…

March 8th, 2013

I’m chuffed to discover, while looking for something else, that a script I wrote – called newslist – is still included as a demo in the Python distribution. I sent it to Guido in 1994.

It was basically a simple interface to Usenet (NNTP) news servers, so I shouldn’t really draw attention to it because it probably hasn’t had a lot of use in the last decade or so!

The included documentation, however, may induce a little nostalgia in those who were involved in the early web. It begins:

                             NEWSLIST
                             ========
            A program to assist HTTP browsing of newsgroups
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

WWW browsers such as NCSA Mosaic allow the user to read newsgroup
articles by specifying the group name in a URL eg 'news:comp.answers'.

To browse through many groups, though, (and there are several thousand
of them) you really need a page or pages containing links to all the
groups. There are some good ones out there, for example,

http://info.cern.ch/hypertext/DataSources/News/Groups/Overview.html

is the standard one at CERN, but it only shows the groups available there,
which may be rather different from those available on your machine.

Newslist is a program which creates a hierarchy of pages for you based
on the groups available from YOUR server. It is written in python - a
splendid interpreted object-oriented language which I suggest you get
right now from the directory /pub/python at ftp.cwi.nl, if you haven't
already got it.

Note that we hadn’t yet started to call it ‘the Web’.

I was just too late to make it into the Python 1.0 distribution. But for this and a couple of other small early contributions, I find I’ve been in the Python acknowledgements since 1.0.2, nearly 19 years ago.

‘Tis an honour I dreamed not of.

:-)

Low-friction paperless workflow

March 3rd, 2013

I’ve been trying to shift much more of the paperwork in my life into the digital world, but I was very keen that filing a bit of paper electronically should be as easy as putting it in a folder in the filing cabinet. “Wouldn’t it be nice”, I thought, “if the only thing I had to do was type a name or a few keywords and everything else happened automatically?” So I built a system which did just that.

This video describes in some detail how the script is set up. You may want to use the full-screen and HD options to make things more readable. If you’re less interested in the details and would just like to see it in action, watch the first couple of minutes and then skip to about 13:30.

One thing I don’t talk about in the video is the fact that Hazel rules can also look at the contents of the file. So, once the document has been OCRed, the automatic filing can happen based on words that actually occur on the paper — it might detect your car’s registration number (licence plate), for example, in a document and know to file that under ‘car stuff’ — which I think is very cool.

Some further links:

Inventing on Principle

February 24th, 2013

This is an interesting and unusual talk, given about a year ago at a Canadian software engineering conference. I’d seen it before, but a friend reminded me of it recently (thanks, Aideen!) so I’ve just watched it again.

Bret Victor starts by talking about new ways to design software, and finishes with some suggestions on how to live your life. This is dangerous, because you may only find him credible on one of these points, and one could perhaps argue that the one-hour talk would be better delivered as two half-hour talks. And the first couple of minutes, delivered in his slow, careful style in a badly-lit brown room, don’t jump out and grab you. However, I think he pulls it off, and it certainly has the merit of being very different from your typical software-engineering talk.

Recommended.

Change management…

November 23rd, 2012

There’s an amazing thing I’ve just discovered after installing an SSD in my laptop: Microsoft Office products now start up at a reasonable speed!

I’ve only just realised that, because I open them so rarely. (It’s one of the joys of working for myself that I can largely pick the tools I use.) In fact, I realise, I probably download updates for Office components more frequently than I actually use them.

That’s an interesting phenomenon; there ought to be a word for it. I’m probably unusual in having Microsoft Word work that way, but there are many of my lesser-used iOS apps that will be updated several times between successive actual executions of their code.

This is a real cultural shift from a world where big corporations would debate for months before rolling out an update to a program. On the web, we’ve grown used to the idea that a piece of software might not look quite the same the next time you log into it. But it’s now true of many apps in my pocket: something will have changed in an app before I run it again. I could quite easily pull my phone out one day and discover that last night’s update had broken something and I could no longer access the boarding pass I need for that plane…

I guess it’s a tribute to progress in software development, or perhaps to the Apple software-approval process (a real pain for developers but in many ways a boon to customers) that this so rarely happens.

Keep the customer notified

August 18th, 2012

Here’s a handy utility for those using Mountain Lion’s new Notifications system (something I find I rather like despite never really getting on with Growl).

It’s called ‘terminal-notifier’ by Eloy Durán, and it lets you send these from the command line. So, for example:

   $ terminal-notifier \
     -message “Shall I compare thee to a summer’s day?” \
     -title “Morning greeting” -execute “open http://bbc.co.uk/weather/2653941”

This pops up a little notification, and clicking on it will take you to the BBC weather forecast for Cambridge.

You could put the command all on one line – I’ve just split it up with backslashes for readability. It’s easy to install terminal-notifier from the command line with:

  $ sudo gem install terminal-notifier

Now, as an illustration of why it can be useful, I wanted this for a particular purpose:

I’ve been experimenting more and more with Multimarkdown, since so much of what I write ends up in HTML, and the markdown syntax is a convenient way to create it. I have an Automator service which takes the currently selected text, for example in a blog post text-entry field, parses it as Markdown, and replaces it with the HTML equivalent. I’ve assigned it a keystroke, so typically I’ll just do Cmd-A to select everything I’ve typed and Ctrl-Alt-Cmd-M to convert it to nice HTML. Very handy. It’s how I wrote this.

Just occasionally, however, I might want to go back to the Markdown version, so before conversion the selected text is also copied into the clipboard. This is the kind of quick temporary backup that becomes second nature if you have a clipboard history utility. But it’s easy to forget this has happened.

Now, I can just add a quick extra line in the automator script and I get a little pop-up to remind me, which vanishes again after a few seconds:

Thanks, Eloy!

Here’s what the Automator service looks like, in case anyone wants to do something similar:

Customise app defaults with AppleScript

August 12th, 2012

Nobody likes AppleScript. Well, almost nobody. It’s an attempt to make a programming language look like a natural language, which means that knowing what constitutes valid syntax in any given situation is almost impossible. I once suggested that what the world really needs is a Perl-to-Applescript translator, because Perl is a language that’s pretty easy to write but impossible to read, and AppleScript is easy to read but impossible to write. The syntax is a bit dependent on the apps with which you’re trying to interact, too, and the debugging options are exceedingly limited.

But the most annoying thing is that, on occasion, it’s exceedingly useful, and there aren’t really good alternatives for the kind of things it can do.

So just in case anyone out there is googling for this kind of thing, here’s how I made it change the default options on a dialog box that I use every day.

I’ve been inspired by David Sparks’s e-book Paperless, and my new-found fondness for the kind of things you can do with the Hazel utility, to get a better, more automated workflow for scanning in documents.

A key component, of course, is that you want them to be OCRed so that you can search for them, or search within them, later. I want something that does this automatically, or can be made to do it automatically, when a scan ends up in a folder on my disk, with minimal manual intervention. Good OCR programs are fairly costly on the Mac – Abbyy FineReader, at £79, is generally agreed to do the best OCR job, but the Mac version is not very scriptable. PDFpen, at £47, does a reasonable job and has better scriptability, and if I were starting now I’d probably use that.

But a while ago I splashed out on NeatWorks, which has good OCR, plays nicely with my wonderful ScanSnap scanner, and provides a complete filing system for my documents, with flexible metadata options. It’s a nice package. But the problem is that I no longer want a complete filing system for my documents – I want to do that myself.

So for the moment I’m using NeatWorks to capture my scans, OCR them, enter some metadata and then export them as PDFs to the folder where Hazel and other things take over. They typically stay in NeatWorks for about a minute.

OK – that was a long run-up to explain why I regularly – often several times a day, do File > Export… and get this dialog:

At this point I can almost just hit [Return], except for one problem: the default is to export all the items in the currently selected folders and I just want to export the thing I last scanned. So every time I do this, I have to switch from keyboard to mouse, click the little radio button by ‘Selected items only’ and then carry on.

AppleScript to the rescue! I used Automator to create a service that just applies to NeatWorks and runs the following AppleScript:

This runs ‘File > Export…’, clicks the appropriate radio button, and then clicks the Export… button.

Finally I used the Keyboard section of System Preferences to assign a keyboard shortcut to this service.

Now, I drop some paper into the scanner and press the button on the front. NeatWorks pops up and OCRs it. I type in a title, document date and any other keywords I fancy, then just hit my magic keystroke and check the name and folder before hitting return to save.

At that point, Hazel takes over and does something like “if this file was created by NeatWorks, and has a name containing the word ‘Telemarq’ and the word ‘receipt’, then file it away in the appropriate folder of my receipts directory with a suitably reformatted filename”.

Raspberry Pi Webcam Viewer

June 10th, 2012

I finally got a chance to play with my RaspberryPi, so I threw together a quick experiment.

 

 

Update: A few people have asked me for a little more information. I’m happy to make the source code available, but it’s not very tidy and a bit specific to my situation… however, to answer some of the questions:

The enclosure for the Raspberry Pi comes from SK Pang Electronics, and it’s perfect for my needs. You can buy just the perspex cover, but they do a nice Starter Kit which includes the breadboard, some LEDs, resistors and the pushswitch. Definitely recommended.

For the graphics, I used the PyGame library, which has the advantage of being cross-platform: you can use it with a variety of different graphics systems on a variety of different devices. On most Linux boxes, you’d normally run it under X Windows, but I discovered that it has various drivers that can use the console framebuffer device directly. This makes for a quicker startup and lighter-weight system, though I imagine it probably has less access to hardware acceleration, so it’s probably not the way to go if your graphics need high performance. You can read about how to get a PyGame display ‘surface’ (something you can draw on) from the framebuffer, in a handy post here.

To load an image from a file in PyGame is easy: you do something like this:

            im_surf = pygame.image.load(f, "cam.jpg")

where ‘f’ is an open file, and the ‘cam.jpg’ is just an invented filename to give the library a hint about the type of file it’s loading.

Now, with a webcam, we need to get the image from a URL, not from a file. It’s easy to read the contents of a URL in Python. You just need something like:

            import urllib
            img = urllib.urlopen(img_url).read()

but that will give you the bytes of the image as a string. If we want to convert it into a PyGame surface, we need to make it look more like a file. Fortunately, Python has a module called StringIO which does just that: allows you to treat strings as if they were files. So to load a JPEG from img_url and turn it into a PyGame surface which you can blit onto the screen, you can do something like:

          f = StringIO.StringIO(urllib.urlopen(img_url).read())
          im_surf = pygame.image.load(f, "cam.jpg")

I’ll leave the remaining bits as an exercise for the reader!

If you like this, you might also like my CloudSwitch