Do Not Reply

Says Ryan Hoover:

How many emails did you immediately delete without opening this morning? How many of those were from [email protected]? We’re drowning in unwanted, rote email yet companies miss the opportunity to escape the trash and create a connection with their users by communicate more personally.

Absolutely – don’t be an idiot by sending mails out with noreply@.

As Ryan, and also Paul, says, you’re missing out on a huge opportunity for engagement and you’re forcing your call centre to do the work.

Even worse, you’re pissing off customers no end. I’ve had this problem recently with a UK retailer (MyProtein). Being used to Amazon’s top-notch service, it’s already a bummer when they send me the wrong order, changing an option I filled out without ever informing me, but when I have no way to reply by email, and I’m forced onto their BS “ticket” system, that sets up an antagonistic “man-versus machine” relationship. Fill out a ticket? Seriously? What does a ticket mean to anyone outside the IT industry? It’s what gets you into a football stadium, not the antidote to using email, the standard communication channel for anyone but companies who’ve messed up a customer’s order.

Please. Don’t make me jump through hoops after you screwed up.

Any random e-commerce site at this point is already two steps behind Amazon to begin with. Send your mails out with no-reply and watch your customer service plummet.

Software is Exorcism

Software is Like a Box of Chocolates

Software has had to endure a proliferation of metaphors over the years. Architecture, Engineering, Art, Craft, Design, Magic, Gardening. We’ve seen them all. Or maybe not all of them, because here is another “software is” I’d like to throw into the ring: Exorcism.

Breaking the Marble Spell

What I mean by this is summarised by Bill Joy in an essay anyone in technology should read:

“In The Agony and the Ecstasy, Irving Stone’s biographical novel of Michelangelo, Stone described vividly how Michelangelo released the statues from the stone, “breaking the marble spell,” carving from the images in his mind. In my most ecstatic moments, the software in the computer emerged in the same way. Once I had imagined it in my mind I felt that it was already there in the machine, waiting to be released. Staying up all night seemed a small price to pay to free it – to give the ideas concrete form.

Ah yes, I know that feeling.

If you’re an architect or a town planner, you might be blessed and cursed with visions of glorious structures.

Unfortunately, the only way to make them happen is to close your eyes and dream.

The other way you can get close is with software.

And that’s the point. If software is your craft (there, I used another metaphor), you actually can turn dreams into reality. It’s really all about the pixels, or as a Facebook has it, “pixels talk”.

One of Bill Joy’s greatest works is Vi, the grand-daddy of Vim, the program thousands – perhaps millions – of other developers and writers spend most of our days in. And how was this gift to humanity created from his initial vision? “I just stayed up all night for a few months and wrote vi”

Having an idea that grows in your head like a bad weed, and yearns to be unleashed as pixels on the screen. That’s exorcism.

Follow Your Passion to the Dole Queue?

I would be remiss if I didn’t mention this important and under-appreciated point.

Should you embrace every whim that comes to you, devoting the next few months or years to make it happen?

No. “Follow your passion” is popular advice, but it usually comes with a dangerously large dollop of survivorship bias. Of course Richard Branson will tell you to follow your passion. He’s the 0.00001% survivor, try listening to the other million who went down this path. It’s true that you’re likely to be better and more persistent at following your passion than maintaining a legacy invoice program in COBOL; but don’t confuse that with being a surefire way to put food on the table.

Commercial viability aside, a hacked-up prototype is not the same as a production system. There are many things to consider in building an application for real-world use: reliability, security, design, support, etc. The good news is you can still mock things up in a weekend and maybe even make them useful for yourself and friends who will tolerate a little breakage. You can also build extensions to tweak existing websites (you can try my Chrome boilerplate to get a Chrome extension up and running quickly). But committing to anything more major … go in with eyes wide open about the risks involved, and make sure it’s an idea that really, really, wants to come out. It’s what I’ve done recently and I’m loving it!

Social Delegation

Social may have been a buzzword for several years, but it’s actually very primitive from a developer’s perspective. As an app developer, all I can really do is let users log in and inspect their properties. Here’s what I actually want to do …

Delegate The Karma

Points (StackOverflow, Reddit) aka Karma (Slashdot, Hacker News) is a neat social pattern. There’s a gamification aspect to it obviously, but what I’m especially interested in is the permissioning aspect. As you progress up the ladder, you get more and more permissions to the point where you’re pretty well part of the team. This is a more elegant permissioning model than specific roles such as “guest” “contributor” “admin”.

The problem for users, though, is they’re always back to square one. They can’t bring their reputation with them other than a token link to Somewhere Else On The Web You Probably Won’t Visit, which rather well defeats one of the original points of federated identity. And from the app developer’s perspective, there’s two further problems. Firstly, it damn well takes time to build all this! It’s not 1999 and I don’t have an army of code monkeys to bang out anything on a whim and another army to monitor funny business. And secondly, the chicken-egg problem. For a site in its tender youth, there’s not always enough activity for users to build karma and certainly not enough to build the outer loop of meta-moderation.

Well, one lean approach would be to just do that which doesn’t scale. Namely, give your mates karma, and anyone else you’re talking to who seems half-savvy. That’s perhaps the best thing you can do right now. But a better approach would be to delegate karma to a third party. What would such a third party look like? It would need some quantifiable measure of karma, an API, and really some notion of exactly what this user is good at. No point letting users run wild on your pistachio content if they’re specialists at chocolate.

The service already exists: Klout. And PeerIndex, Kred, and very likely Google Plus and Facebook under their respective covers. Klout is just PageRank for people after all, with all of the gaming and spam detection that comes with it. (These services are mostly vilified by people who are confusing flaws in their current implementations with the principle behind them and people who haven’t dealt with the considerable classes of problems they solve for enterprises. Let’s just assume they are generally reasonable services for now.)

So a solution is to keep your users’ Klout up to date. Sync all users’ Klout weekly and permission them accordingly. As your system grows, you may also build your own karma system up. Or even better, contribute your users’ karma – with their consent – back into the Klout pool.

Delegate The Groups

Social? Hello? Social should surely be about individuals banding together to form groups. Google Plus gets this right by baking in the notion of circles, though as I’ve often griped, Google’s notion of circles is more geeky than the average individual cares for, in much the same way wave’s hierarchy was more complex than most people want to think about. It should be first and foremost about fixed groups, maintained by an admin.

I don’t want groups in my own system. I don’t want a manager to have to go around to every new system and enter the emails of their 15 direct reports. I don’t want the football captain to have to enter his 30 team mates into my system for the umpteenth time. Let the group live somewhere else and I’ll deal with it.

So a solution is to identify a platform for groups, make sure your user is the same guy or gal managing said group, and let them give permissions to that group on your own system. Sync the group regularly.

Delegate The Relationships

Seriously man, every time I upload a slide to slideshare, I get a week of “Xyz has started following you on SlideShare”. WAT? I have a social network for slides! This is unacceptable. I don’t know if their real people or spammers (if the former, don’t get me wrong, thanks for the interest in my slides and now we can be slide buddies. No, wait …) But either way, I’m not going to click on their profile and Visit Their Site Somewhere Else On The Web to work out if I should invite them into my inner sanctum of people I share slides with.

Here is where Lanyrd got it right by just making your conference network your Twitter network. In the same way, it might be useful to see what your Facebook buddies are doing too. And so on. Facebook and I think G+ help a bit here by incorporating friends’ info into their Like/+1 buttons. ie “Joe, Sue, and 7 others liked this”. You may need more than that though if you’re baking this right in.

So a solution is to sync social networks.

Delegate The Profiles

“Hi I’m Michael and this is a new profile I wrote especially for this here basketball site because my football profile was wholly inadequate”. Okay again you see where this is going…pull that profile content in from other sites, at least as a default. The ever-parsimonious Josh Schachter plays this gambit nicely with his latest project, Skills.to. And pull in those Sites From Somewhere Else On The Internet too, so our intrepid user doesn’t have to enter their flickr URL yet for the tenth year running.

A special case that bears mentioning is avatars. This particular piece of developer experience suckage requires the developer to repeatedly poll the social API for the latest URL of the avatar, and then replicate the avatar, perhaps on S3, in order to avoid the sin of hot-linking. (It’s not actually clear if sites like Twitter allow hot-linking of avatars, by the way. Please make that clear, Twitter and friends.) A service I used on Twelebs was Joe Stump’s Tweet Imag.es, but it’s always been a kind of beta project and I’ve found it’s sometimes delivering blank images. And fair enough, it’s free and experimental. I’m pleased to see there’s a new service out today that may actually solve this problem: Cloudinary is an image-URL-manipulation tool, something I’ve thought about building myself for years, after once creating a gradient generation tool and, later, Faviconist.

Bottom line is, sync your users’ profiles.

Now Don’t Make Think, Consarn It! This Stuff Should Be Easy

If I wasn’t focused fully on Player FM right now, I’d be building a system to make all this easy for developers. Right now, it’s a ton of work, and really, it’s all generic stuff. As you probably noticed, it’s mostly just “here’s some data, now let’s just keep it up to date”. So, you know, let me drop in a Rails gem and said gem just automatically keeps all this stuff in the database up to date “for free”. Man would I pay you real dollar bills for that. I’m hopeful services like Parse might actually do this. I’d also suggest that any platform that provides these services – Klout, Twitter, etc. – should be mobilising their developer relations to make these kinds of libraries happen. Platforms are a huge battleground right now, and the winners will have to do more than offer raw RESTful services. They’ll need to encourage frameworks and libraries that make the sync “just work”.

Operation Zero-Shelf

“My shelves are empty. The half-dozen Billy Bookcases I bought from Ikea are now little more than scrap. I have burned my books. A bonfire of ideas and ideals.” Terence Eden

I’ve entertained the zero-shelf fantasy since I first read e-books and sync’d news on the trusty Handera 330. I stil have it:


At the time, the content wasn’t around and the screen was a bit small to be practical anyway. When the iRex came around, I thought this might be the time. But of course, content remained an issue. But now the time is here. iPad is fantastic for reading and Kindle has all the content. And just last night, Amazon popped up with an announcement that Kindle Touch is here in the UK. I’ve resisted Kindles up till now. For all their benefits, they look like a bad 1960s sci-fi imagining what life will be like in the year 1979. The keyboard in particular seems completely out-of-place for a device that is primarily about reading. And it’s impossible at this point to hold a screen which you can’t touch. So the Kindle Touch changes a lot of that and with its battery benefits and (especially after a week of glorious March weather here) working in the sun is a killer app tablets won’t beat for some years.

So it’s time to make it happen. This week, I’ll scan all my books with Delicious Monster or Bookshelved to keep a perpetual record of what I once owned. I’ll allow myself to keep 10 books of sentimental or long-lasting value and another 10 which I haven’t (fully) read. These lucky 20 will be marked with post-it notes. The rest can stay on the shelf for three months and if I feel the need to keep one of them, I will swap those post-it notes around. And on July 1, 2012, those without post-it notes will be shown no mercy! Well, some mercy … they can go to a suitable charity.

Someone Different: Encouraging Twitter Serendipity

I made a very raw cut of an idea that’s been percolating for a while. The idea is to randomly follow a few people for a month or so, then rotate to a few different people, and so on. This would let you immerse yourself in a community for a little while, with the aim of busting out of the filter bubble, learning something new, and maybe making a new friend or two.

Demo: You can try a proof-of-concept here (don’t be put off by the permissions Twitter asks for; it won’t tweet on your behalf, the permission is unfortunately necessary to manipulate lists). It’s raw, but will create a real list for you and set its membership. It works now by simply switching to one of several manually-curated lists, which I just rotate when you visit the app (/pages/welcome). If there’s interest, the plan is (a) to make the rotation happen automatically (b) generate the lists from something like Klout or PeerIndex, to ensure you’re following people in the same community.

Right now, the “someone different” people live only in your “someone-different” list, but I’m inclined to follow them in the main stream. As long as they stay in the “someone-different” list, it’s still easy to unfollow them from the main stream. And if you find you want to keep following someone, you just remove them from the “someone-different” list. (It’s all very ghetto here; I’m basically using the twitter list in lieu of maintaining a database.)

I recently noticed @jobsworth was also looking for something like this. His ideas are certainly not achieved in this v0.0.1, but hopefully it will get people thinking about what’s possible. Please let me know where you’d like to see this go.

The app’s built in Rails using the very nice twitter-login gem and hosted on heroku.

Login Best Practices for Mobile Web Apps

Walking home, I thought I’d venture to make a meal order via my phone…and without making a phone call. It shouldn’t be an ordeal to do so in 2011, but frankly a sense of learned helplessness means I haven’t even tried before. I know, #FirstWorldProblems, but let’s learn something from it.

Anyway, I pull up my favourite meal delivery service, Hungry House (highly recommended! At least in London.) I simultaneously launch a Market search for a Hungry House app – right or wrong, we know mobile app experience is almost always smoother. Well, no app, but the web page loads…and a bunch of antipatterns emerge.

Instead of documenting login antipatterns, I’ll make this post more useful by turning them around and proposing best practices for mobile web login. Beware it’s all speculative and subjective.

Zen Login Form

Make a simple, mobile-optimised, login form. Make sure it’s easy to click on each field to focus them (there’s only two of them!). Make sure any links (“forgot password”, “sign up”) are far enough away they won’t accidentally be licked.

This is true of all mobile web forms, not just login one. But if your app only works behind a login form, this would be the first one to optimise.

“Keep Me Logged In” should default to On

It’s a mobile phone, not an internet cafe, so yeah. Admittedly, this is trickier in the case of a tablet, but still it’s only a default, I’m not saying “hide the option altogether”. Also, form factor detection ftw.

Don’t Expire the Login Cookie

Okay, this will be controversial. But if mobile web apps are to be a viable alternative to mobile-native apps, they should provide the same login experience. Right now, a majorly overlooked distinction is login expiry. I find myself having to login to Twitter all the time, when trying to tweet from some other web app. But with the Twitter mobile app, I’m always logged in. Basically, mobile-native apps never expire the session. Most of them probably don’t even bother with a session/token, they probably just store the user’s credentials in plain text on the device (just some speculation on my part, based on the “see no evil” principle, given that this data is fairly invisible, being stuck in the app’s data storage.) At least a cookie, if found by someone else, doesn’t compromise the entire account, and can easily be expired.

Keep it Light

Needless to say, don’t load so much that the browser crashes. Repeated browser launches makes users hungry.

Phil Hawksworth: Excessive Enhancement [Full Frontal 2011]

My fellow Osmolumnus Phil Hawksworth talking on Excessive Enhancement …

Phil talks about the power of standards, with a nod to Paul Downey’s The Web Is Agreement and The URL is the Thing.

“The seductive power of the possible”. Phil compares the original, raw, Macdonalds site to the recent beetle.de site. Yes, it’s HTML5, not Flash, BUT:

  • 11mb of images
  • 251 http requests
  • no caching

“As you scroll, it lazily loads some images, the next 4MB of uncached images”

The beetle site arguably doesn’t really provide any more information than the original Macdonalds site. The URLs can’t be bookmarked and it takes an age to load!

Twitter is the next subject of Phil’s scorn! No Javascript? No love.

Now we get to Phil’s main point: Interface shizzle doesn’t have to break the web. His example is GitHub’s use of HTML5 history, with the animated slide effect. He notes you can use Levi Routes as a simple way to manage history (it’s the framework Paul Kinlan developed for our Google IO Talk).

Lots of great slides here, too many to post here, but he’ll be putting up the slideshow later on.

Ten Years On

It’s now ten years since I completed my PhD, “Design Reuse in Human-Computer Interaction and Software Engineering”. I completed the bulk of the report (compiled from earlier papers, but with a lot of tidying up and tying together) in early 2001, submitted it for review (by two external judges) in May, received the feedback in August, revised it and submitted it on September 7. I received a balloon at some point and went to the pub with some PhD buddies and one of our supervisors.

For the first time, here is my PhD online: http://mahemoff.com/paper/thesis.pdf

I’ve sent it on request, but never got around to publishing it. I was told early on you’re required to make five copies of your PhD because five people will ever read it (Your supervisor, your other supervisor, your reviewer, your other reviewer, and your mum), so I never thought much of the actual thesis document. The papers are really more concise summaries of individual components. But I never did a postdoc, so some things in there never got published as individual papers. And it’s good to have it out there anyway, instead of sitting in a library.

I learned a lot about research and its presentation, but I also learned early on that an academic life was not for me. I’m glad I worked on something I was able to use as a practitioner during and after the PhD.

Relevant

Announcing Faviconist

faviconist screenshot

I have made a new Favicon generator, Faviconist. Since most favicons are just a letter with some colour theme, I found it crazy to have to open up a photo editor every time I wanted a new favicon. Or alternatively, it’s easy enough to convert an image with ImageMagick, but most images don’t scale down nicely to a tiny icon! So the aim here is not an editor as such, but a true “favicon generator”.

Using Faviconist

To create a favicon, it’s as simple as typing the first letter of your website. But you probably don’t want the default colour scheme, so it’s easy enough to tweak. Under the covers, Favicon has a concept of a “FillStyle” and both foreground and background are instances of FillStyle, so they have the same flexibility. You can have a solid fill style (just a single colour), a linear gradient, or a radial gradient.

For simplicity, Linear gradients don’t have stops (it’s just a linearly increasing spectrum from start to finish), though you can choose the direction. And in the same sprit of simplicity, radial gradients may only begin at some points, and their span is fixed. The guiding principle here is “YAGNI” – You Ain’t Gonna Need It. I’m catering for the 95% of people who don’t want to micro-design their icons; the rest will still need to resort to PhotoShop et al.

The preview images are PNGs, which can easily be downloaded directly. However, another gripe of mine is the whole thing of downloading to hard drive and uploading back to a server somewhere else. Hot-linking, aka “bandwidth theft”, is rightly a problem for the original image host…but it’s a shame the only way we can deal with it is to silo everything. (A parallel vision of the web, which might have almost succeeded and still might, saw it more as embedded content than a collection of copies and links.) In this case, it’s only favicons, so I’ll just say hot-link and be merry. When you click “Save Favicon”, it saves the icons on my server and you can just cut-and-paste into your own project.

I hope this is useful for quick hacks and hackathons, where favicons are often forgotten! These days Favicons are more useful than here. Of many reasons to use a favicon, things one might forget are: they’re used on third party sites like Google Plus, tabbed browsing is super-popular these days; if you don’t provide favicons, you’ll get 404s in your log files.

And here’s a little tip for you – don’t just use letters. Try special characters, and don’t just limit yourself to ASCII. You have the entirety of Unicode at your disposal!

How Favicon Works

Buzzword Bingo time. There are a number of technologies at work here:

  • HTML5 Canvas In the past, a site like this would have to be powered by the server – every change would require a long wait for the server to generate a new image. But now, we can do it in real-time, in the browser, using Canvas. The only server interaction is conversion to “.ico”; unfortunately, Canvas will output to PNG, but not ICO. And while a JavaScript ICO encoder is certainly a possibility, no-one has yet written one.

  • Canvas Text To draw text, Faviconist uses Canvas’s fillText method. e.g. context = canvas.getContext('2d'); context.fontStyle = '25px arial'; context.fillText('Yo!'). When Ace Editor effort got started (called Bespin), in the early days of canvas, text support was patchy. But now it’s very well supported.

  • MeasureText Library I thought Faviconist would be easy because I thought there would be simple metrics for fonts. Turns out canvas’s measureText() returns a “TextMetrics” object, and guess what TextMetrics contains:

interface TextMetrics {
  readonly attribute double width;
};

Huh? We can only find the text’s width, not its height. And as a I went down the path, I learned you can’t just say “draw this text with its top-left at (0,0)”. To center the font, as we do in Faviconist, we actually need to determine text offset as well – left and top.

So I built the MeasureText library. It works as a drop-in replacement (~shim) for the built-in HTML5 Canvas MeasureText mechanism, and also provides a new convenience function not requiring an existing canvas. It works by drawing the text and scanning the resulting bitmap to get a true representation of the metrics. Using this, and with a little geometry, it’s possible to center text.

  • Favicon Library Figured it would be cool to show a preview of the favicon by changing the site’s actual favicon! For which I used ye olde Favicon library, which I originally created via this blog and I’ve now officially moved to Faviconist.com. The library also incorporates a new “badge” feature, so you can show number of pending emails, etc. Go try the demo!

  • Font Selection You can choose fonts, with the fonts coming from the Google Font Directory. It wasn’t feasible load all fonts, so they’re loaded dynamically, but I wanted to show previews … so there’s a script to build a 38,000 pixel sprite map! It’s loaded after the page loads, with a canvas-based check to see if it loaded successfully (since it doesn’t work on Firefox). To show it in a dropdown, I used a fork of the Chosen library, a fork which retains the class of each option in the select list.

  • Chrome Frame Didn’t want to support IE6-IE8, so introduced Google Chrome Frame, based on the code in HTML Boilerplate, but increasing the version check from 6 to 8.

  • JavaScript Libraries Faviconist uses several useful libraries: jQuery, Underscore, Backbone, and jQuery Tools. And just to say, jQuery Tools is the very picture of Developer Experience heaven. Great explanations, many easy-to-follow demos, lots of options…and a CDN for the libraries.

  • NodeJS, Connect, Express The server is NodeJS running the Express-Connect stack. Considering that the app is almost all client-side, I spent a ton of time getting up to speed with this stack, partly due to performance optimisatins, and partly due to the next point …

  • Jade, Stylus, Kaffeine Being a fan of DRY, I’m very happy to be using higher-level abstractions of HTML, CSS, and JavaScript. I certainly am happy with Jade, with the exception of dropping in raw HTML script snippets. And Stylus is absolutely awesome. Kaffeine makes JavaScript much easier, though I’ve found it difficult to incorporate everywhere because the ecosystem is very much geared around CoffeeScript. e.g. Connect comes with a default CS compiler, Nodemon (a node watch-and-run-tool by Remy Sharp) supports CS, there’s a ton of doco about getting CS working with things. So that was really the biggest challenge. I mainly wanted Kaffeine because I’m not such a fan of significant whitespace, but the ecosystem’s preference for CoffeeScript did present challenges.

I hope you enjoy Faviconist. It’s a work in progress, so please leave feedback if you have suggestions.

Integrated Google Plus on the Homepage

I’m getting more convinced Plus is the new Twitter, and also the new Posterous. I’ve been posting things on there I previously would have stuck on the Twitter or the Posterous, and so it was time to integrate Plus on my homepage alongside the existing Twitter and Posterous links.

Latest Post

It was pretty easy to integrate my latest Google Plus post (we don’t really have a name for a Plus post yet; a plust?), as I already have a framework in place for showing the last post from an Atom or RSS feed.

First, I found my Plus feed URL thanks to Russell Beattie’s unofficial Plus Atom Feed service:

http://plusfeed.appspot.com/106413090159067280619

Using MagpieRSS, you can easily get the last post.

  1. define('MAGPIE_CACHE_ON', false);
  2.   require_once('magpierss/rss_fetch.inc');
  3.   $feed = "http://plusfeed.appspot.com/106413090159067280619";
  4.   try {
  5.     $rss = fetch_rss($feed);
  6.     $recent_post = $rss->items[0];
  7.     $title = $recent_post[title] . " ...";
  8.     $link = "http://mahemoff.com/+", $recent_post[link];
  9.     $timeAgo = timeAgo(strtotime($recent_post[updated]));
  10.     // show the post
  11.   } catch(Exception $ex) {
  12.     // log exception
  13.   }

Me

Inside the CSS3-rendered vcard, there’s a link to my plus alongside twitter etc.:

  1. <a rel="me" class="url" href="https://plus.google.com/106413090159067280619">plus</a>

/+ …. redirect to Plus

Following Tim Bray’s suggestion, I redirected http://mahemoff.com/+ to the plus page. It’s nice to have a memorable URL.