All posts by Antony Kennedy

CSS3 Snippets in TextMate – border-radius

I don’t have the best memory in the world. I am incapable of remembering the exact syntax for most CSS properties, let alone the vendor specific versions of them. To that end I have started creating TextMate snippets to help me out.

text-shadow comes by default, but border-radius does not.

Create these 5 snippets within CSS:

Name:
border-radius
Tab trigger:
border-radius
Snippet:
border-radius: ${1:radius};
-moz-border-radius: ${1:radius};
-webkit-border-radius: ${1:radius};
$0

Name:
border-top-left-radius
Tab trigger:
border-radius
Snippet:
border-top-left-radius: ${1:radius};
-moz-border-radius-topleft: ${1:radius};
-webkit-border-top-left-radius: ${1:radius};
$0

Name:
border-top-right-radius
Tab trigger:
border-radius
Snippet:
border-top-right-radius: ${1:radius};
-moz-border-radius-topright: ${1:radius};
-webkit-border-top-right-radius: ${1:radius};
$0

Name:
border-bottom-left-radius
Tab trigger:
border-radius
Snippet:
${1:radius};
-moz-border-radius-bottomleft: ${1:radius};
-webkit-border-bottom-left-radius: ${1:radius};
$0

Name:
border-bottom-right-radius
Tab trigger:
border-radius
Snippet:
${1:radius};
-moz-border-radius-bottomright: ${1:radius};
-webkit-border-bottom-right-radius: ${1:radius};
$0

Now, anywhere that is a CSS context (inside a CSS file or inside style tags in an HTML file) type border-radius and press tab. TextMate asks which of our five snippets you want. Choose the appropriate one by typing the number alongside it, and the code appears. Now type the radius you want (don’t forget, you can enter two values if you want the equivalent of an elliptical radius) and it will automatically appear for all vendor-specific code. Finally, press tab again and your cursor jumps outside of the code we just typed.

I’ll provide more of these as I make them.

How social networks should take advantage of sheep mentality in targeted advertising

Facebook now has more than 400 million active users. 50% of these log on to the site at least once a day. 3 billion photos are uploaded a month. These figures are staggering. Facebook now drives more traffic to news sites than Google, according to GigaOm. Farmville – a small Facebook-based game which depends upon social interaction – actually has three times as many active users as Twitter.

In fact, some people may be starting to think that Facebook is the Internet. A few weeks ago, a post on www.readwriteweb.com ranked very highly for the search term “facebook”. As the comments on that page demonstrate, users did not understand that this was not Facebook. They complained about the new format and the missing login box, whereas most of my readers (I imagine) would certainly have realised the difference, and would have typed facebook.com into the location bar of their browser initially in any case. Some of us may take a cheap laugh at this, but the sheer volume of comments there (not taking into account those that didn’t comment) demonstrates that this is not unusual. Many people search for what they want, and dangerously assume the first result is what they are looking for. A friend of mine’s wife never browses to youtube.com – she searches for youtube and clicks the first link.

Facebook likely knows more about you than Google does. There is widespread concern that Google could be relating our searches and browsing history together, and that there are privacy implications for this. But, for the huge amount of people that use Facebook as their portal to the Internet – not only do they know what we are sharing, clicking on, and interacting with – they also know our personal details that we give to them willingly, and even who our friends are and how often we interact with them. At a recent event I attended, an employee of Facebook told me they have enough data now to be able to fairly accurately predict when a couple who are interacting will change their relationship status to show that they have got together, or broken up.

Surely this amount of data gives Facebook the ability to start the really targeted marketing and affiliate network advertising that I have been hoping for? I do not think it is hard to conceive that at some point in the near future, advertising will no longer be an irritation. If the advertiser knows enough about me to present me with advertising that I genuinely am interested in, it becomes a service. For advertisers too, presenting an ad to a group that are more likely to be interested in their product enhances their brand rather than tarnishing it, saves costs on unnecessary blanket marketing, and ultimately increases ROI.

This has been discussed many times, and Facebook and Google (and others) are already trying to achieve it. Google’s effort is based on keywords within the page and is not yet as intelligent as we would like it to be. At best this can have funny results, and at worse it can be very offensive. Some examples are here.

Facebook makes a better effort. Since it knows the bands I enjoy, it tells me about tickets and upcoming concerts, with affiliate links. It also gives me the ability to effectively vote ads down that do not interest me, for whatever reason. But, Facebook have the potential to take advantage of sheep mentality (also known as group think, or group solidarity) – the mindless following of peers that the vast majority of us subscribe to. There have been many studies on this, with the outcome being always that we are more likely to subscribe to the same opinions, use the same services, and buy the same products that our peers and (to a lesser degree) the general populous do.

Facebook knows my interests. It knows who my friends are, and it knows of them who I hold in greater esteem based on the status updates and other shared items that I “like” or respond to. If they were to surface ads based on how many times they have been interacted with by my friends, or products that they know my friends and peers have purchased or are interested in, there would be a clearly stronger chance that I would also be interested in these things. If my friends that I hold in highest regard are treated as more important in these algorithms, the effect would be stronger still. The events application within Facebook is the best example of what I am getting at, but seems to miss out on the affiliate and advertising potential.

It is one thing to present me with artists that they know I am likely to like based on artists that I have listed as my favourites and other people’s listening preferences who also like the same artists; the value of my circle of friends strikes me as being more valuable than this. Some examples.

  • “10 of your friends including John, Joe and Mary all bought this item.”
  • “6 of your friends that listen to Nirvana also like Pearl Jam.”
  • “12 of your friends will be attending Reading Festival 2010, click here to buy tickets.”

Each of these examples would of course be accompanied by a link to buy the product or service in question, or useful services that relate (for example hotels and restaurants in Reading). This kind of advertising is not only useful, since it gives me information on people I am likely to care about, but it also offers a clear and strong revenue stream based on affiliate links and purchasing opportunities. I believe that using a user’s social network as data to base targeted advertising on is a logical next step.

What do you think?

Update: Andy Beeching pointed me to this article, which describes your circle of peers and the value of individuals within in as the “Social Graph”. It makes for interesting reading.

Standardised Bug Reporting with SEERS

SEERS

When raising bugs and defects, it can be easy to miss out vital pieces of information without a strict policy to adhere to. Often the developers have to refer back to the tester that raised the bug and ask exactly what went wrong, what they expected to happen or in which environments the problem occurred. SEERS is a term I have coined to use as a standardised series of criteria for bugs and defects. SEERS stands for:

Screenshot

There should always be a screenshot of the problem (unless it is a non-visual bug). If possible some kind of obvious visual outline around the problem should be shown. As noted by Alun Coppack in the comments, if the error is behavioural we should annotate the screenshot to describe the problem – and if this is not practicable a screencast of the problem leaves no margin for miscommunication.

Environment

There should always be details of the environment(s) (browser, operating system, screen resolution, etc) that the problem occurs in.

Expected/Actual Behaviour

There should always be details on the expected behaviour and the actual behaviour.

Reproduction

There should always be accurate details on how to consistently reproduce the bug. As noted by Alun (again!), some errors can be temporal and the testers should be aware of this and take note of the time/date before they try to recreate the error.

Severity

There should always be details on the severity of the bug.

Severity

It is a common complaint that the recording of the severity of a bug or defect is inaccurate. An element being two pixels to the left in IE6 is not a huge problem, but is often rated as Critical. To that end, I list the severities we use below.

Blocker

A blocker means that our entire story or functionality is not working or unusable, even if following The Happy Path. The Happy Path is that where the user does exactly what we expect them to and does not stray from the norm at all – e.g. entering the correct login details and clicking “login”. If we do not fix this bug we cannot release. An example is a login box where clicking the login button does nothing.

Critical

A critical bug indicates that functionality is severely impaired. If we do not fix this bug we cannot release. An example is a login box where entering invalid credentials takes the user to an empty page. The Happy Path (entering correct credentials) works fine, but a very likely situation exists which could cause functionality to break.

Major

A major bug indicates that some functionality does not work as expected. Copy may be obscured, or specific situations may cause errors to occur. We should certainly fix this bug, but it would not be impossible to release without. An example is a login box where entering over 100 characters in the password field causes an error.

Minor

A minor bug indicates some kind of cosmetic issue or unlikely situation that causes an error. We should fix this bug if it is cost effective to do so and other more important tasks do not exist. An example is the login button being aligned incorrectly, or clicking the button 30 times causing an error.

Trivial

A trivial bug indicates a very minor cosmetic issue or very unlikely situation that causes an error. We may decide not to fix this bug. An example is IE6 and Firefox not looking exactly the same, although IE6 looks acceptable and functionality is not impaired.

Terminology

Let’s discuss what actually constitutes a bug or defect, although this is terminology that I use and your mileage may vary.

Bug

When a task is in the current iteration or sprint and we raise an issue against it, this is called a bug.

Defect

When an issue is found that does not relate to any current tasks, this is called a defect.

Graded Browsers

Finally, here is a list of the browsers we support and their grades. We expect grade A browsers to have complete functionality, and look close to perfect (as much is reasonable or practicable). Grade B browsers should look acceptable and work as expected (although potentially with less of the flashy but essentially unnecessary functionality). Grade C browsers should allow the user to read the content, and accomplish their tasks. It is important to mention that we do expect content to be accessible in absolutely any environment; it is the aesthetics and nice-to-have functionality that we are less concerned with.

Grade A

These browsers should work perfectly, look good and perform well.

  • Windows XP/Vista
    • IE8
    • IE7
    • Firefox 3.5
    • Opera (latest version)
    • Safari (latest version)
    • Chrome (latest version)
  • Mac OSX 10.5/10.6
    • Safari (latest version)
    • Firefox 3.5
    • Opera (latest version)

Grade B

These browsers should work acceptably (any unsupported functionality should be dealt with gracefully e.g. JS animations or Flash), look good (any unsupported rendering functionality should be dealt with gracefully e.g. rounded corners, alpha transparency or drop shadows) and perform reasonably well.

  • • Windows XP/Vista
    • IE6
    • Firefox 3
  • Mac OSX 10.5/10.6
    • Safari (previous version)
    • Firefox 3

Grade C

All other browsers should work acceptably (degrading gracefully where appropriate), have no obscured or illegible content and perform acceptably.

Notes

It is important to note that in my list IE6 has been relegated to Grade B (which is at odds with Yahoo!’s graded browser support, which I otherwise use as a base for my list). This is simply due to the development effort to class it as Grade A. Where it is easy to do, I still recommend striving for good aesthetics for IE6 – but (for any version of IE) rounded corners and drop-shadows are often simply not cost-effective. I would implement these with CSS3, and argue that the time saved (and performance increase) by doing this The Right Way gives us enough time to develop new features. I obviously do not expect testers to test every single Grade C browser in existence, but simply to be aware of what does and what does not class as a bug or defect.

Remember, your users do not compare browsers side by side like we do. They have no idea there are inconsistencies, and more often than not simply wouldn’t care even if they did. It is unfortunately impossible for a website to look the same in every browser or environment (without just using a huge image map, and even then a text-only browser like Lynx would not be able to render it) and there is nothing to gain in trying needlessly to overcome this.

Defensive AJAX and AJAX retries in jQuery

A lot of code that I have seen over the years always assumes success, particularly with AJAX calls. This creates code that is fragile, and entirely dependant on the result of external (to the client) code.

There are a few ways we can attempt to protect against this. The first, is to always depend on the result of the call to make any changes to the DOM or UI. For example, let’s say we have a quantity field in a shopping basket on an e-commerce site. When the user clicks a plus next to the field, we make an AJAX call that increments a value in a basket stored server-side and updates the UI to match. It is very common, and tempting, to increment the value in the UI immediately, and then make the AJAX call. There are a few obvious problems here. If the AJAX call fails, now we have a UI that is inaccurate. We can decrement the value in the UI to make up for it, but now we are starting to confuse the user with the numbers jumping up and down, and if they have clicked the button six times in quick succession (very common use of this kind of control) our chance of error for accurate UI representation of data increases dramatically.

A much safer way to do this is to return the current stored quantity value from the server with each AJAX call, and only update the UI when the AJAX call completes. This results in a less “snappy” feeling UI, and it will be necessary to display some kind of visual cue that something is going on the background, but the user learns quickly how the site works and this is a much more robust process.

Without having any kind of genuine statistics to call upon, I would suggest that nine out of ten AJAX calls that fail are due to an issue that is temporary and would be resolved by a retry. Anything due to network issues, a lost packet somewhere, a brief server glitch, load balancing problems and so on can cause a timeout or 404 without the target resource actually being missing or consistently failing. Often when a website fails to load, I click refresh and there it is. An AJAX call is just the same. (The same applies to database connections, or anything dependant on a network resource.)

Therefore, rather than display an error on an AJAX timeout (“we could not connect to the server” or “there was a problem, please try later”) or worse, doing nothing at all, there are some things we can try to resolve the issue ourselves without bothering the user about it until we’re certain that it is broken.

Let’s look at a typical jQuery AJAX call.

$.ajax({
	url : 'ajaxurl.json',
	type : 'get',
	data : 	{name : 'value'},
	dataType : 'json',
	timeout : 20000,
	success : function(json) {
		//do something
	}
});

The immediate problem with this is it completely assumes (and depends upon) success. There is not even a basic error handler. Something like this is better:

$.ajax({
	url : 'ajaxurl.json',
	type : 'get',
	data : 	{name : 'value'},
	dataType : 'json',
	timeout : 20000,
	success : function(json) {
		//do something
	},
	error : function() {
		alert('Oops! There was a problem, sorry.');
	}
});

The error callback function is actually passed three arguments.

  • The XMLHTTPRequest object in use
  • A textual equivalent of the status
  • The actual exception thrown

These allow us to react in a more sophisticated manner:

$.ajax({
	url : 'ajaxurl.json',
	type : 'get',
	data : 	{name : 'value'},
	dataType : 'json',
	timeout : 20000,
	success : function(json) {
		//do something
	},
	error : function(xhr, textStatus, errorThrown ) {
		if (xhr.status == 500) {
			alert('Oops! There seems to be a server problem, please try again later.');
		} else {
			alert('Oops! There was a problem, sorry.');
		}
	}
});

Since the error function lives inside the AJAX object itself, and is called in that context, the this keyword very usefully points to the jQuery AJAX instance itself. Using this, and the arguments we are being passed we can very easily set the UI to retry the AJAX call on our behalf. Let’s attach some extra properties to the AJAX object:

$.ajax({
	url : 'ajaxurl.json',
	type : 'get',
	data : 	{name : 'value'},
	dataType : 'json',
	timeout : 20000,
	tryCount : 0,
	retryLimit : 3,
	success : function(json) {
		//do something
	},
	error : function(xhr, textStatus, errorThrown ) {
		if (xhr.status == 500) {
			alert('Oops! There seems to be a server problem, please try again later.');
		} else {
			alert('Oops! There was a problem, sorry.');
		}
	}
});

We have added tryCount and retryLimit. These are going to store how many attempts we have made, and how many attempts we will make respectively. Making use of these:

$.ajax({
	url : 'ajaxurl.json',
	type : 'get',
	data : 	{name : 'value'},
	dataType : 'json',
	timeout : 20000,
	tryCount : 0,
	retryLimit : 3,
	success : function(json) {
		//do something
	},
	error : function(xhr, textStatus, errorThrown ) {
		if (textStatus == 'timeout') {
			this.tryCount++;
			if (this.tryCount <= this.retryLimit) {
				//try again
				$.ajax(this);
				return;
			}
			alert('We have tried ' + this.retryLimit + ' times and it is still not working. We give in. Sorry.');
			return;
		}
		if (xhr.status == 500) {
			alert('Oops! There seems to be a server problem, please try again later.');
		} else {
			alert('Oops! There was a problem, sorry.');
		}
	}
});

So, now we are trying three times before giving in. Where I have actually used this, some modal dialogue boxes are used instead of window.alert() and I save a copy of the AJAX object when we reach our retry limit. At that point, although I tell the user we have given in, I still provide them with a button to try again themselves.

I am convinced that implementing techniques like this will rid us of many unnecessary bad user experiences, and many support calls. Keep the user informed (in simple language!), and assume things will fail. I hope this is helpful.

Destructuring assignments in JavaScript 1.7

Destructuring assignments are great for time saving methods of assigning values to variables. They make for shorter code, and shorter code is less error prone.

A destructuring assignment essentially allows you to arrange variables in an arrayesque manner, and assign them an array. What this does is actually assign the items in the array to each variable in one go. This is much easier to explain with an example.

Say we have two variables:

var variable1 = 10, variable2 = 20;

Now, we want to assign them two new values. By putting those variables inside an array-like structure before the assignment operator, we can do this in one statement instead of two:

[variable1, variable2] = [30, 40];

Now, variable1 is 30, and variable2 is 40. We can use this to take all of the items of an array returned from a function and put them in individual variables:

var color1, color2, color3;
var fnGetColors = function() {
	var arrColors = ['red', 'green', 'blue'];
	return arrColours;
};
[color1, color2, color3] = fnGetColors();

Or to swap the values of two variables, which previously would have required a temporary variable to use for storage:

var strBlack = '#FFFFFF';
var strWhite = '#000000';
//Oops, wait - that's not right
[strBlack, strWhite] = [strWhite, strBlack];

Sadly, support for JavaScript 1.7 is patchy. Internet Explorer, even in version 8, still only supports JavaScript 1.5. This kind of code could be useful if you were writing extensions for Firefox though, or had control over your user base (perhaps in an Intranet). I include it here just for interest – one day we’ll be able to use it!

Further reading:
New in JavaScript 1.7 – MDC
JavaScript Versions on Wikipedia

Regular Expression to match UK residential telephone numbers

A regular expression to match UK residential telephone numbers. It understands the difference between 02 and 01 numbers. It will accept all common formats and internationally formatted numbers.

Examples of accepted numbers:

  • 02081234567
  • 0208 123 4567
  • 020 8123 4567
  • 0208 123-4567
  • +44 208 123 4567
  • +44 (0) 208 123 4567
  • 01234 567 890
  • +44 0 1234 567-890
  • 07712 123 456

Examples of numbers that will not be accepted:

  • 020812345678
  • 123456789
  • 07612 123 4567
  • +33 345 876 1298

This is my first submission to the excellent regexlib.com regular expression library – I’d appreciate if you could vote for it!

/^(((44))( )?|((+44))( )?|(+44)( )?|(44)( )?)?((0)|((0)))?( )?(((1[0-9]{3})|(7[1-9]{1}[0-9]{2})|(20)( )?[7-8]{1})( )?([0-9]{3}[ -]?[0-9]{3})|(2[0-9]{2}( )?[0-9]{3}[ -]?[0-9]{4}))$/

Let me know if I’ve missed anything!

Update: This has been amended as per comments below, to allow 020 as a prefix for London, 07624 (Isle of Man) and 074xx xxxxxx.