26
Aug

DHL failure in usability

A couple of weeks ago I ordered the latest third-generation of the DAS Keyboard – my second generation packed away back in Guernsey and the Alps-switched one from DSI incapable of reliably registering more than 2 keys on USB.

Being that I’m fixed on the European keyboard layout (our enter key is double height with the backslash moved down next to Z) I had to order from Germany, specifically the guys over at getDigital.de

When the keyboard hadn’t arrived a couple of weeks later I headed off to the tracking link at DHL Germany.

As a customer all I’m interested in is:

  • Where is the package now?
  • When will I have it?

A good developer would understand and deliver this. Instead DHL present:

Piece-number 9507xxxxxxx7
Addressee: Item destined for abroad
Status: Arrival at inward Office of Exchange in the Country of Destination
Status from: 19.08.08 17:07
Process: Arrival at inward Office of Exchange in the Country of Destination

Everything here screams bad systems, poor understanding and disregard for the customer. They aren’t giving the customer what they want, they’re giving the customer a little of what they have and are not even reinterpreting the data from the customers perspective.

This isn’t untypical but neither of my questions have been answered and the item is over the delivery times so I need to go further. Hitting the contact button next to the “piece-number” takes us to:

For further information, please call us on 

0 18 05-345 22 55 *

(14 cent per minute within german fixed network)

Business hours:
Monday - Saturday between 7 a.m. and 10 p.m.
Sundays and public holidays between 9 a.m. and 6 p.m.
* only within Germany

or per contact form (except for investigation inquiries)

If your shipment has not arrived at the recipient within 6 days, you have the opportunity to fill out an  investigation inquiry dircectly via your PC.

Wow, so the primary point of contact for an international delivery is a number that can only be called from Germany. Useless.

So we can now choose a per-contact form or an investigation form. Okay, let’s go to the investigation form. Let’s try that.

The web page you would like to access cannot be viewed at this time.

We apologize for any inconvenience. Perhaps it is due to a connection problem, perhaps the link is no longer valid or you have directly selected a page that no longer exists in the specified directory

Wow, DHL Germany really don’t have things under control here. Let’s flip over to DHL’s main site and take it from there.

First of all we need to chose our country, currently Canada… Now let’s enter the reference number we’ve been using on DHL Germany’s web site and “Shipment/Waybill not found”.

Okay, I’m a persistent fellow, let’s give DHL Canada a call and find out what’s going on… I give the reference number to the woman at the other end and “that’s too long”. Hmm, tell her it works on DHL Germany web site, she goes to the web site and tries it out and confirms it does but that it doesn’t work on their system. She tries a few searches on my name, from Germany to Vancouver, nothing, nada, zip and suggests I try contacting DHL Germany or the sender to get a “proper” reference number.

The real icing on the cake of course is the “About DHL” page states:

DHL Express offers seamless service worldwide.

I can see a very big seam here between Germany and Canada.

Expertise around the globe.

Not much use when the people with that expertise are sat behind a number you can’t call from outside their country.

One world. One express and logistics company.

But not one system or tracking mechanism.

[)amien

25
Aug

The Xerox Alto mono-spaced font rises again

Preview of the AltoMono fontComputer history tells us of a mythical place where many of the innovations we take for granted today were either invented or refined to a working level at a single place known as the Xerox’s Palo-Alto Research Center (PARC).

These discoveries form the basis of much of the technology we use today and include the desktop metaphor, the graphical user interface, laser printers, object orientation and Ethernet among others.

Xerox manufactured a number of very-high end machines including the 1973 Xerox Alto which, being GUI based, shipped with a number of proportional bitmapped fonts.

What is interesting to me however is the mono-spaced font used by the SWAT debugger (but not by the command prompts, they were proportional – so ahead of their time!) and so, based on a screen-shot of SWAT, I thought it needed to be made available again!

I’ve had to make up a few of the symbols and letters that weren’t shown and filled out the symbols for the Windows-1252 Latin-1/ISO-8990-1 code-page and with the absence of any solid information online give it a name so here is Alto Mono!

Download Alto Mono (TrueType, Windows FON, BDF) (30 KB)

When using the TrueType version choose 6 point on Windows and 8 point on Mac OS X.

The Xerox manuals are fun to browse though with such section headings as “Things the user doesn’t really need to know…” and “How to get out of trouble” and the comments about SWAT’s odd syntax and interface.

Also, don't forget to check out my reproduction of the PalmOS system font. Not monospaced but very clear at small sizes - great for the Visual Studio output window ;-)

[)amien

08
Aug

Fun entertainment online

I’m missing my DVD collection terribly and might just give in and get it shipped over now I have a Pioneer DVD player that can play region 2 titles here albeit with a poor interlace PAL > NTSC conversion.

In the mean time I’ve been entertaining myself with the following comedy gems until I can at least find a proxy server in the UK to let me back into iPlayer (BBC) and Catch-Up (Channel 4) so I can watch QI, Top Gear and Grand Designs.

Podcasts

Adam & Joe – highlights from their BBC Radio 6 show has me laughing out loud in the office sometimes to the bemusement of colleagues.

Jonathan Ross – more highlights this time from Jonathan’s Saturday morning show that is always worth a giggle.

Comics

Weebl & Bob – two egg-shaped friends make sense of a purple world that never has enough pie but an abundance of silly voices, ninja pirates and tiny bovines.

Joy of Tech – geek cartoons from some Apple loving talent.

Pictures

ICanHasCheezBurger – because there’s no such thing as too many pictures of cute cats with crazy captions aka Lolcats. (My own attempt shown at the top of this post)

Videos

Fonejacker – George just needs your bank account details and sort code for your gas refund (3 million Ugandan dollars) and the sales pitch of Internet service providings who offer a better level of Internet service providing.

MineSweeper The Movie – the only computer game left to convert into a movie. (Well, except for Half-Life which is just dying for a good movie). Some of the other strips on this site include Street Fighter: The Later Years.

Zero Punctuation - video game reviews full of more great English humor, quip and amusing animations to take your favorite games down a peg.

[)amien

05
Aug

How did I get started in software development?

Ken Egozi tagged me with the latest meme and this time it’s at least relevant :)

How old were you when you first started in programming?

Some time between 10 and 12 when my father bought home a ZX Spectrum and I ended up delving into the excellent programming manual when I finally ran out of games to play. At the same time my school opened up the computer room at lunchtimes…

What was your first programming language?

BASIC on the Sinclair Spectrum (evenings) and BBC Micro (lunch-times and after school). Multi-platform from the outset ;-)

What was the first real program you wrote?

Probably the MultiFile +3 disk & file management tool for the Spectrum in a mix of assembler and BASIC but I was also creating menu and copy protection for the BBC Micro around the same time.

I also trashed an expensive 3” disk drive at the time with a small bug in my end-of-disk detection code that resulted in the drive trying to step itself beyond the end several times and knocked it out of alignment.

What languages have you used since you started programming?

Well I’ve *used* the following although ones in italics for only brief periods involving one or two small applications.

  • BASICs: Sinclair, BBC, Microsoft, QBASIC, Mallard, QuickBasic, ASIC
  • Assemblers: Z80, 6502, 8051
  • Visual Basic, VBA, VBScript, VB.NET
  • C, C++, Objective-C, C#, Java, JavaScript, ActionScript
  • Turbo Pascal, Delphi, SQL, PHP
  • COBOL, RPG, SmallTalk, Algol, Prolog

I’m not sure if XSLT/XPath or RegEx’s count.

What was your first professional programming gig?

Writing IBM AS/400 (iSeries) banking applications in COBOL age 17 joining a team where the leader was already known as the Kindergarten Cop as everyone in his team was “only 23-25”. I got to delve into the kernel, general ledger and securities systems eventually single-handedly developing intricate multi-base-currency support leaving days before my 19th birthday. (Okay, a little pride there ;-)

If you knew then what you know now, would you have started programming?

Without a shadow of a doubt.

If there is one thing you learned along the way that you would tell new developers, what would it be?

Enjoy the journey, new languages are going to come and go so learn them just-in-time ;-)

It’s a shame computers and languages are more complex now but with the Internet and great books available there is no real barrier to entry.

What's the most fun you've ever had programming?

Any application that brings a smile to a users face :)

Some 'interesting' moments have been revisiting school-level physics for a pool game and an on-the-fly domain class construction system for an international configurable payroll package.

Who am I calling out?

I’m not sure any of them are reading my blog any more but you never know ;-)

[)amien

01
Aug

Ten commandments for developers

In order that applications and operating system shall not drive users insane thou shall:

1. Allow immediate termination

I hit the wrong button. I changed my mind. I didn’t know it would take this long.

Either way, the operation needs a cancel button that should take immediate effect and quickly clean up what it can.

If it was copying or uploading a file delete what was done, for database operations rollback the transaction or for formatting a disk leave it half formatted and unformat the first sector but do it FAST.

If you think the consequences are too great ask what effect forceful termination or switching off the power is going to be.

2. Leave start-up alone

I’ll do that right now, just let me log in… Zzz… Sorry. It should be done in a minute. Sigh.

Your app might be the center of your world developing day and night - it’s not the center of mine.

I might use it for a 7-8 hours a day if you’re lucky. That doesn’t mean I want it starting automatically unasked.

It also doesn’t mean you can install services, background tasks or other junk that will prevent me from doing what I need when I’m in a hurry and running with a low battery.

If you need to check for updates do it silently in background when I launch the app or add something to the Windows scheduler and don’t create an entire service.

3. Not modify existing file associations

I tried that last time and it screwed up my associations. I’m not going to try the new version no matter what.

I might want all video files to go through your app. I might not.

Let me make that choice and reverse it. If I uninstall your program reverse it automatically.

Associating every media file on my system with your app isn’t going to make think wow. It isn’t going to make the sale or make me believe my system can’t live without your software.

There will be incompatibilities, features you don’t support or perhaps a clunky UI and and I’ll uninstall your app to go back to my old favorite.

When all my associations are broken you can’t bet I won’t be coming back to see what you’ve done in version 2.

4. Not ask inappropriate questions

Do you want to move or copy files from this zone? Yes or No.

Zone? What? Err, copy please. What do you mean Yes or No?

I just performed a non-destructive operation and you want me to confirm it?

Do you want to remember your password?

An insanely stupid question that appears after a login box doesn’t have a password stored, either because:

  • I don’t use the feature but can’t switch it off (never ask me again)
  • I’m not on my own computer (shut up for 30 minutes)
  • I have a new machine and haven’t typed it for months (ask me in 10 seconds when I find out if it’s right)

You rarely get useful options but at least Firefox 3 realises it should ask quietly at the top of the page after you can see if it worked.

5. Keep noise to a minimum

Windows has installed updates!
AVG Anti-Virus updated successfully.

This is business-as-normal – I DON’T CARE.

If there is a problem updating let me know – unless it’s something simple that will go away without my involvement in a day or so like a missing network connection.

People don’t call or message me day in and out to tell me nothing, neither should my computer.

This also goes for audio notification of trivial activities.

Don’t annoy people in their offices and homes with stupid noises just because somebody the other side of the world has logged in.

6. Stay focused on the goal

The instant messaging crown was taken from ICQ because they overloaded the client with games and junk. People wanted simple messaging but by the time they figured this out with ICQ Lite it was too late.

Real repeated the same blunder where a good video player expanded to consume all available files, starting messaging me and breaking every commandment there is.

Adobe think Acrobat shouldn’t be a quick useful PDF viewer for pixel-perfect page reproduction but rather a piggyback mechanism for a whole document management system and that nobody minds their web browser locking up for 20 seconds while they load plug-in’s you won’t use.

    7. Make actions obvious and reversible

    I don’t want a dialog box with some sob story about why your app can’t do what I just asked or three paragraphs of text I have to scan for negatives, digest and mentally figure out what Yes and No will actually do.

    Even worse is prompting a slightly different message with the same Yes and No options sending the user to the button they normally hit for a totally different message with potentially disastrous results.

    If Yes is doing to delete the file label the button Delete. Dialogs in OS X do this and you can answer them lightning fast with accurate results.

    Better yet just do it, put some text in the status bar, update the UI and learn how to write an undo mechanism.

    8. Avoid restarts

    If your application absolutely has to install a service start it yourself.

    If common files you are installing might be in use, check them or better yet put them in your own application folder.

    9. Make configurations count

    Adding options to your application is only extra choice to a certain point, then it works in reverse as people can’t find the option they are looking for and become bewildered at the choices available before quickly heading to the close button instead.

    If you absolutely must have extra options that only a small percentage of the population care about just store it in the configuration system and forget about giving it presence on the user interface.

    10. Adhere to the platform

    Read the user interface guidelines and only deviate when you know better than the expert team behind them. If you have to explain it then you didn’t know better after all.

    If the operating system has conventions for files, configuration and help use them. Don’t claim being the same across platforms is more important – people who use more than one platform know and expect them to be different already.

    If you want to use an update, notification or other commodity service find what is already popular and a good fit and use that, don’t develop something different.

    [)amien

    30
    Jul

    LINQ to SQL log to debug window, file, memory or multiple writers

    The Log property on a LINQ to SQL data context takes a TextWriter and streams out details of the SQL statements and parameters that are being generated and sent to the server.

    Normally in examples you will see Console.Out being assigned to it which is fine for small demos and sandboxes but sooner or later you’ll want access to it in Windows or web applications. Here are some examples of how to redirect TextWriter output such as the DataContext log to other destinations.

    To the output/debug window

    The output/debug window mechanism actually uses a listener mechanism and so doesn’t actually directly expose a TextWriter interface however we can simply wrap up Debug.Write in something that does and use that instead:

    class DebugTextWriter : System.IO.TextWriter {
       public override void Write(char[] buffer, int index, int count) {
           System.Diagnostics.Debug.Write(new String(buffer, index, count));
       }
    
       public override void Write(string value) {
           System.Diagnostics.Debug.Write(value);
       }
    
       public override Encoding Encoding {
           get { return System.Text.Encoding.Default; }
       }
    }

    To use it then simply:

    myDataContext.Log = new DebugTextWriter();

    To a file

    #if DEBUG
       db.Log = new System.IO.StreamWriter("linq-to-sql.log") { AutoFlush = true };
    #endif

    If you wish to not overwrite the existing log file then change the constructor to include the parameter true after the filename. Bear in mind this log file can get very large and slow down your application with all that extra writing to disk and could well reveal information you’d rather wasn’t persisted there so the DEBUG conditional is recommended.

    To memory

    #if DEBUG
       var sw = new System.IO.StringWriter();
       db.Log = sw;
    #endif

    You will be able to examine sw or call ToString() on it to see the contents. Again this is not recommended for production as it will cause a lot of memory consumption as the StringWriter gets larger and larger.

    To multiple writers

    Here is a small useful class that lets you send the results intended for a TextWriter off into multiple writers.

    class MulticastTextWriter : TextWriter {
        private IList textWriters;
    
        public MulticastTextWriter() {
            textWriters = new List();
        }
    
        public MulticastTextWriter(IList textWriters) {
            this.textWriters = textWriters;
        }
    
        public void Add(TextWriter textWriter) {
            lock (textWriters)
                textWriters.Add(textWriter);
        }
    
        public bool Remove(TextWriter textWriter) {
            lock (textWriters)
                return textWriters.Remove(textWriter);
        }
    
        public override void Write(char[] buffer, int index, int count) {
            lock(textWriters)
                foreach(TextWriter textWriter in textWriters)
                    textWriter.Write(buffer, index, count);
        }
    
        public override Encoding Encoding {
            get { return System.Text.Encoding.Default; }
        }
    }

    So if you wanted to output to a log and also to the debug window, you would use it like this (again recommended only for debugging):

       MulticastTextWriter mw = new MulticastTextWriter();
       mw.Add(new DebugTextWriter());
       mw.Add(new System.IO.StreamWriter("linq-to-sql.log") { AutoFlush = true };
       db.Log = mw;

    Anything you want

    To wrap things up here is a small TextWriter that lets you go off and do whatever you like with the string via the Action delegate.

    class ActionTextWriter : TextWriter {
        private Action<string> action;
    
        public ActionTextWriter(Action<string> action) {
            this.action = action;
        }
    
        public override void Write(char[] buffer, int index, int count) {
            Write(new string(buffer, index, count));
        }
    
        public override void Write(string value) {
            action.Invoke(value);
        }
    
        public override Encoding Encoding {
            get { return System.Text.Encoding.Default; }
        }
    }

    So if you wanted to output all log information to say a WinForms message box a tiny lambda expression gets you there:

       db.Log = new ActionTextWriter(s => MessageBox.Show(s));

    Have fun!

    [)amien

    23
    Jul

    LINQ to SQL T4 template reloaded

    The topic of modifying the code generation phase of LINQ to SQL comes up quite often and the limited T4 template I published here last month was good at showing the potential but wasn’t a practical replacement for the code generation phase.

    I am please to make available the next version, which now…

    • Runs from the DBML therefore keeping the designer in the loop
    • Generate all the attributes for columns and tables including UpdateCheck, IsDbGenerated etc.
    • Supports associations including those with a foreign key
    • Generates appropriate attributes and code for both serialization modes

    In short it generates code that is now functionally equivalent to SQL Metal with the following caveats:

    • C# only – VB.NET can be added if there is some interest
    • Stored procedures – not yet supported
    • Table inheritance - incomplete
    • DBML changes require you open and re-save the T4 template so it regenerates the code
    • Unidirectional serialization requires you add System.Runtime.Serialization to your project references (thanks Roger!)

    Download LINQ-to-SQL-T4-0.3.zip (5 KB)

    To use the template :

    • Extract the archive and add the two files to your project
    • Right-click on the L2ST4.tt file, choose Properties and set the Custom Tool to blank
    • Rename DataClasses1.tt to the same name as your DBML file (but keeping the .tt extension) and open it
    • Click save and watch a freshly generate C# DataContext pop out
    • Switch off the LINQ to SQL designer generated C# by either setting the Custom Tool on the DBML to blank or setting the Build Action on the generated C# to None.

    L2ST4.tt contains a lightweight wrapper around the DBML which is processed using LINQ to XML making the template easier to work with and providing a central for naming rules etc.

    This code should be treated as a sample and hasn’t received much testing yet so feel free to leave comments or feedback here.

    Some places you could take this template:

    • Generate an interface for your data context to improve mocking
    • Alternative naming and defaults
    • Splitting output into multiple files
    • New languages
    [)amien
    10
    Jul

    MobileMe up and down at me.com

    MobileMeMe.com was up, briefly, just long enough for me to grab my usual handle and get the confirmation message in fact.

    I did get a brief glimpse of the UI complete with a Finder-like view of various folders once I clicked past a warning about Internet Explorer 7 not being supported. Seconds later things stopped responding and then the original placeholder was back.

    It's no secret Apple have been using the SproutCore framework in producing Me.com and that while SproutCore isn’t tied to Ruby on Rails it seems likely Apple went with Rails given the lack of interest in WebObjects and more and more Rails articles turning up on ADC.

    If they’ve gone down that route I’m hoping we’re not in for a ride like the Rails powered Twitter one takes us on. Despite being relatively simple functionality it has been unable to cope with the demand and ability to scale which means downtime, slowness and features being switched off are regularly observed.

    They are using WebObjects after all so expect some WebObjects and SproutCore integration love soon.

    As an aside I’m in the US the week after next to meet my team and attend some training and will try and grab an iPhone 3G whilst there if not already sold out. Given that I’m only in Canada for 3 more months I don’t want to be trying to escape Roger’s expensive 3-year contract so soon.

    [)amien